I am working on combat mechanics in a Top Down 2D game. I want to create a circle around a player and move the object on the edge of that circle. No matter where your mouse is, the object always stays on the edge. How would I do that? I know this is related to math but I am yet inexperienced to implement it on the right way. Here is a picture of the idea and the question itself. Picture.
It would be nice to know how does the user controls the player.
Anyway, here's some piece of code that i used on a 2D project of mine. Not sure if it works on 3D, but even if it doesn't, the logic is the same
float radius = 400; //radius of circle
Vector3 playerPosition = player.transform.position; //Player's position
Vector3 centerPosition = transform.localPosition; //center of the circle
float distance = Vector3.Distance(playerPosition, centerPosition); //distance from player to the center of the circle
if (distance > radius) //If the distance is greater than the radius, it is already within the circle
{
Vector3 fromOriginToObject = playerPosition - centerPosition;
fromOriginToObject *= radius / distance; //Multiply by radius //Divide by Distance
Vector3 newPlayerPosition = centerPosition + fromOriginToObject; //all that Math
}
player.transform.localPosition = newPlayerPosition ;
I really encourage you to check the font as it have some visual explanation: https://answers.unity.com/questions/1309521/how-to-keep-an-object-within-a-circlesphere-radius.html
You will need the radius and center of the circle. Then probably some vector that defines the direction.
Related
I always want to keep an object in the center of view of a camera.
The object can not change its position.
The camera can be rotated.
The camera can move up and down.
The object should always be centered in the view of the camera.
So when I rotate the camera by -45°, I would like to know the Y position of the camera at which the rotated camera would still directly face the object.
I know the "horizontal" distance between the camera and the object (as this never changes), and I know the angle of the camera.
How could the "required camera position Y value" be calculated?
Thank you.
So this code works for me:
//Distance between object and camera. Y-axis is pointing up, so we use x and z coordinates.
float R = Vector2.Distance(new Vector2(obj.position.x, obj.position.z),
new Vector2(camera.transform.position.x, camera.transform.position.z));
// Lets find rotation from zero to target angle
float rAngle = Mathf.Deg2Rad * (camera.transform.rotation.eulerAngles.y + angle );
// Using minus cause when we rotate camera to the "right" we have to move it to the"left"
float x = -R * Mathf.Sin(rAngle);
float y = -R * Mathf.Cos(rAngle);
// Apply changes.
camera.transform.position = new Vector3(x, camera.transform.position.y, y);
Vector3 cameraRotation = new Vector3(0, angle,0);
camera.transform.Rotate(cameraRotation);
And as i said you easily can use https://docs.unity3d.com/ScriptReference/Transform.RotateAround.html
I have an image UI in a canvas with Screen Space - Camera render mode. What I like to do is move my LineRenderer to the image vertical position by looping through all the LineRenderer positions and changing its y axis. My problem is I cant get the correct position of the image that the LineRenderer can understand. I've tried using ViewportToWorldPoint and ScreenToWorldPoint but its not the same position.
Vector3 val = Camera.main.ViewportToWorldPoint(new Vector3(image.transform.position.x, image.transform.position.y, Camera.main.nearClipPlane));
for (int i = 0; i < newListOfPoints.Count; i++)
{
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
Screenshot result using Vector3 val = Camera.main.ScreenToWorldPoint(new Vector3(image.transform.localPosition.x, image.transform.localPosition.y, -10));
The green LineRenderer is the result of changing the y position. It should be at the bottom of the square image.
Wow, this was annoying and complicated.
Here's the code I ended up with. The code in your question is the bottom half of the Update() function. The only thing I changed is what was passed into the ScreenToWorldPoint() method. That value is calculated in the upper half of the Update() function.
The RectTransformToScreenSpace() function was adapted from this Unity Answer post1 about getting the screen space coordinates of a RectTransform (which is exactly what we want in order to convert from screen space coordinates back into world space!) The only difference is that I was getting inverse Y values, so I changed from Screen.height - transform.position.y to just transform.position.y which did the trick perfectly.
After that it was just a matter of grabbing that rectangle's lower left corner, making it a Vector3 instead of a Vector2, and passing it back into ScreenToWorldPoint(). The only trick there was because of the perspective camera, I needed to know how far away the line was from the camera originally in order to maintain that same distance (otherwise the line moves up and down the screen faster than the image). For an orthographic camera, this value can be anything.
void Update () {
//the new bits:
float dist = (Camera.main.transform.position - newListOfPoints[0]).magnitude;
Rect r = RectTransformToScreenSpace((RectTransform)image.transform);
Vector3 v3 = new Vector3(r.xMin, r.yMin, dist);
//more or less original code:
Vector3 val = Camera.main.ScreenToWorldPoint(v3);
for(int i = 0; i < newListOfPoints.Count; i++) {
line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
}
}
//helper function:
public static Rect RectTransformToScreenSpace(RectTransform transform) {
Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
Rect rect = new Rect(transform.position.x, transform.position.y, size.x, size.y);
rect.x -= (transform.pivot.x * size.x);
rect.y -= ((1.0f - transform.pivot.y) * size.y);
return rect;
}
1And finding that post from a generalized search on "how do I get the screen coordinates of a UI object" was not easy. A bunch of other posts came up and had some code, but none of it did what I wanted (including converting screen space coordinates back into world space coordinates of the UI object which was stupid easy and not reversibe, thanks RectTransformUtility!)
Im trying to get my GameObject to point towards the mouse. It has a child object with a sprite. The childs rotation is set to 0 on all zxis. The sprite points upwards (positive X) at start. The GameObject rotates with the mouse pointer but its always turning its right side towards the mouse pointer. Also when i add force forward it accelerates at the same direction the sprite is pointing which as stated before is not the direction the mouse is. What is my code missing?
var cam = Camera.main;
// Distance from camera to object. We need this to get the proper calculation.
float camDistance = cam.transform.position.y - transform.position.y;
// Get the mouse position in world space. Using camDis for the Z axis.
Vector3 mouse = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, camDistance));
float AngleRad = Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x);
float angle = (180 / Mathf.PI) * AngleRad;
rb2d.rotation = angle;
Your shape is rotated by 90 degrees due to the way that your calculations resolve the angle, you can account for this by using:
rb2.rotation = angle - 90;
I want to restrict player movement in the sphere, the schematic diagram show as below. If player movement is out of range, then restrict player to sphere max radius range.
How can I write C# code to implement it, like this?
These are my current steps:
Create 3D sphere
Create C# code append to sphere object
My code so far:
public Transform player;
void update(){
Vector3 pos = player.position;
}
I don't know how you calculate your player`s position but before assigning the new position to the player you should check and see if the move is eligible by
checking the new position distance form the center of the sphere
//so calculate your player`s position
//before moving it then assign it to a variable named NewPosition
//then we check and see if we can make this move then we make it
//this way you don't have to make your player suddenly stop or move it
//back to the bounds manually
if( Vector3.Distance(sphereGameObject.transform.position, NewPosition)< radius)
{
//player is in bounds and clear to move
SetThePlayerNewPosition();
}
What #Milad suggested is right but also include the fact you won't be able to "slide" on the sphere border if your movement vector even slightly goes outside the sphere :
(sorry for the crappy graphic skills...)
What you can do if you want to be able to "slide" on the sphere interior surface is get the angle formed between the player position and the X vector and then apply this angle with the :
public Transform player;
public float sphereRadius;
void LateUpdate()
{
Vector3 pos = player.position;
float angle = Mathf.Atan2(pos.y, pos.x);
float distance = Mathf.Clamp(pos.magnitude, 0.0f, sphereRadius);
pos.x = Mathf.Cos(angle) * distance;
pos.y = Mathf.Sin(angle) * distance;
player.position = pos;
}
Just make sure using this won't counter effect your player movement script (that's why I put it in LateUpdate() in my example).
I thought I understood matrix math well enough, but apparently I'm clueless
Here's the setup:
I have an object at [0,0,0] in world space. I have a camera class controlled by mouse movements to rotate and zoom around the object such that it always looks at it. Here is how I calculate my viewMatrix from the camera:
public Matrix viewMatrix {
get {
return
Matrix.CreateFromAxisAngle(Vector3.Up, rotAngle)
* Matrix.CreateFromAxisAngle(Vector3.Left, pitchAngle)
* Matrix.CreateTranslation(0, 0, distance)
;
}
}
I need to be able to get the position of the camera in world space so I can get its distance from the box--particularly its distance from each face of the box. How can I get the camera's xyz position in world space coords?
I've tried:
// all of these only return [0, 0, distance];
Vector3 pos = Vector3.Transform(Vector3.Zero, viewMatrix);
Vector3 pos = viewMatrix.Translation;
Vector3 pos = new Vector3(viewMatrix.M41, viewMatrix.M42, viewMatrix.M43);
It seems like the rotation information is being lost somehow. The strange thing is that the viewMatrix code works perfectly for positioning the camera!
or to simplify slightly:
Vector3 pos = Matrix.Invert(view).Translation;
Once again, I figure out the problem within seconds of posting the question:
I needed to invert the view matrix. The rotation info was being lost because it plays no part in the distance calculation until the view matrix is inverted. The rotation was at the wrong "end" of the transformation.
Vector3 pos = Vector3.Transform(Vector3.Zero, Matrix.Invert(viewMatrix));