Actually, i'm programming a little spaceshooter game (2.5D, Topdown View). The player can move along the XZ Axies and rotate the spaceship via right ministick (gamepad) or look to the cursor position (keyboard + mouse).
So, the movement and rotation (Y-Axies, Yaw) are seperated.
The whole thing works fine and looks good - but now i want to do the following:
If the spaceship moves sideways, it should rotate around the X / Pitch axies / lean left and right a bit, dependent on the sideways speed.
So, i have to compute the sideways speed from the following, given input:
Velocity Vector (Movement on X and Z Axies, Y is always '0')
Direction Vector (Rotation on Y Axies, X and Z are always '0')
And with the amount of sideways speed, i could rotate my spaceship around the X axies and multiply the resulting quaternion by the rotation around the y axies.
Anyone who has a solution for this?
Solution: Just "rotate" the velocity vector by the heading of the spaceship and use the "roll/z" axis as the sideways rotation about the X axis (the axis, where your ships nose points towards):
Quaternion Rotation = Quaternion.Euler(0, mHeading.y, 0);
Vector3 RealVeloctiy = Quaternion.Euler(0, -mHeading.y, 0) * Velocity;
float Angle = RealVeloctiy.z * 2.5f;
Rotation = Rotation * Quaternion.Euler(Angle, 0, 0);
A couple of possibilities:
Compare the velocity vector with local left direction of the spaceship (make sure they're in the same coordinate space first). You could use the Vector3.Angle function, or a dot product to do the comparison. Scale the result appropriately, and apply a local rotation around the forward axis.
Take user input directly. If the user is strafing in a direction, apply a roll value. You could use a float between -1 and +1, along with a rate of change. If they're strafing left, move the value towards -1 at that rate, or if they're strafing left, to +1. If neither key is being pressed, move the value back towards 0. (You might like to play around with the Lerp, SmoothStep and SmoothDamp functions too). Scale the value to apply an appropriate rotation about the relevant axis.
Related
I have a camera, it is attached to the capsule, and rotates independently of it.
But I need the capsule to rotate along the Y axis following the camera. How to get the Y-axis rotation values of the camera? Tried through transform.rotation.y. But it gives an error.
Transform.rotation returns a Quaternion (see also Wikipedia - Quaternion) - it has not 3 but 4 components x, y, z and w!
=> Unless you know exactly what you are doing - which is almost never the case ^^ - you do never want to touch any of its components directly.
Unfortunately also the Transform.eulerAngles are not really reliable for your use case.
So what I would do is rely on Vector3 instead.
// take camera's forward vector
private forward = yourCamera.transform.forward;
// erase the Y axis => vector is now only on the XZ plane rotating around Y
forward.y = 0;
// rotate the capsule so its forward vector aligns with "forward"
yourCapsule.transform.rotation = Quaternion.LookRotation(forward);
// could also do
//yourCapsule.transform.forward = forward;
see also Quaternion.LookRotation
I'm trying to test some code to create Vector2 from its angle and its distance from the player position. I've looked up online how to do this and found the Vector2.Angle function to get the angle between two vectors, and the Vector2.Distance function to find the distance between two vectors, and I thought that I would be able to recreate the original (check_points[i]) Vector using these values, but when I run this code this is what I get (the white lines are from position to check_points[i], and the red lines are from position to other, which is the vector I'm trying to create from the values):
I would have expected the red and white lines to be the same, how can I make them this way?
float angle = Vector2.Angle(position, check_points[i]) * Mathf.Deg2Rad;
float dist = Vector2.Distance(position, check_points[i]);
Vector2 other = new Vector2(Mathf.Cos(angle) * dist, Mathf.Sin(angle) * dist);
Debug.DrawLine(position, check_points[i], Color.white);
Debug.DrawLine(position, other, Color.red);
The point of this is to track the corners of obstacles so I can generate a mesh from the triangles made between the corners and the player, to do line of sight checking. I've previously gotten it to work just casting a ray out for every degree of rotation (0-360), but I've read this tutorial and am trying to implement corner tracking to get it to look smoother: https://ncase.me/sight-and-light/
So the issue is that your position and check_point[i] are both positions .. you are not really taking directions here.
As noted in the comments e.g. a position of 0,0,0 wouldn't work at all since this vector has no direction so any angle between this and another position should be undefined.
What you want to do is take directions like Vector2.right and check_points[i] - position.
The next issue was that Vector2.Angle is always positive so you want to rather use SignedAngle here!
float angle = Vector2.SignedAngle(Vector2.right, check_points[i] - position) * Mathf.Deg2Rad;
float dist = Vector2.Distance(position, check_points[i]);
Then later note that a position vector has one more component than only an Angle and a Distance (which alone is only a direction): A StartPoint. You want to use this vector and start at your position (which now also can be 0,0,0) like
Vector2 other = position + new Vector2(Mathf.Cos(angle) * dist, Mathf.Sin(angle) * dist);
Debug.DrawLine(position, check_points[i], Color.white);
Debug.DrawLine(position, other, Color.red);
As you can see the white lines are exatly covered by the red ones so you only see the red lines recalculated from the angle and distance
I'm working on this tank game where you move a tank using the keyboard input and aiming its turret using the mouse input.
For the tank movement I use this code in the update method:
x = Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed;
z = Input.GetAxis("Vertical") * Time.deltaTime * speed;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
But I get results similar to this video (even when locking the rotation of the axes):
https://streamable.com/tm33b
Is there anyway to prevent such irritability with the movement of the tank, also is there anyway to attach both the body and the turret of the tank while making each rotate independently, also the tank to climb the terrain appropriately.
I'm a beginner to unity, I'm sorry if my questions were obvious or easy. I will be so thankful if I get any direct solution to this.
Note that both Translate and Rotate have a last optional parameter Space relativeTo = Space.Self. This means by default always Space.Self is used:
If relativeTo is left out or set to Space.Self the movement is applied relative to the transform's local axes. (the x, y and z axes shown when selecting the object inside the Scene View.) If relativeTo is Space.World the movement is applied relative to the world coordinate system.
Your tank opject starts "flying" and "tilting" because you rotate and translate in its own local coordinates instead of world coordinates. You should instead use
transform.Rotate(0, x, 0, Space.World);
transform.Translate(0, 0, z, Space.World);
to perform the translate and rotate in workd space.
I want to write a simple foosball game in unity. To rotate the players I am mapping my mouse movement to the rotation of the players:
float mod = (Input.mousePosition.x - RotationSpeed) * RotationSpeed;
rb.transform.eulerAngles = new Vector3((90 - mod) , 90, 90);
with mod being a delta to my mouse position. However by doing so I can't kick the ball as I teleport through it by setting the exakt angle. So my question is: how to map the rotation in a way that I actually am able to apply force to the ball, so that it can be shot?
Edit more information:
By moving my mouse to the left, my players rotate clockwise. E.g. my mouse is at x position 300 , then the rotation of the player will be set to 300 times a step (here called "Rotation Speed"). Counterclockwise in the other direction. As in a typical foosball game I want to kick the ball by flinging my mouse to one of the directions. However the ball gets stuck / does not move much when they collide. The reason for this is probably, that by setting the euler Angle directly, the players "teleport" through the ball and don't kick it back. So I need some kind of an instant smooth motion to where my mouse is.
I'm working on a new control scheme for the Oculus Rift that utilizes the tilt of the headset to move the player. Meaning, you tilt your head back and forth to go forwards and backwards, and from side to side to strafe. The camera is tied to a rolling sphere, as that gave it a nice sense of acceleration, and feels a bit like kind of flying around. So far, it's working quite well, but only on the global axis. So if you turn to the left and tilt your head forward, you still go forward according to the starting position (Which if you're facing to the left means you'll go right). I'm trying to fix it so that you can go forward and strafe relative to the direction the camera is facing, but with no luck. I have a strong sense that it's something ridiculously simple, but I just can't seem to find it. Any help is very much appreciated!
Here is what I have on the rolling sphere right now:
public GameObject RightCamera;
void FixedUpdate(){
float angleX = RightCamera.transform.eulerAngles.x;
angleX = (angleX > 180) ? angleX - 360 : angleX;
float angleZ = RightCamera.transform.eulerAngles.z;
angleZ = (angleZ > 180) ? angleZ - 360 : angleZ;
Vector3 movement = new Vector3 (-angleZ, 0, angleX);
GetComponent<Rigidbody>().AddForce (movement);
}
There's an easy way to do this. Given the orientation expressed as a quaternion (or 3x3 Matrix) compose it with a unit Y axis vector.
The resulting vec3's X and Z values are your forces. No need to involve Euler angles, which will almost certainly start hurting you as your approach a 90 degree angle from vertical.
Finally solved it! I used
GetComponent<Rigidbody> ().AddForce (RightCamera.transform.forward * angleX);
GetComponent<Rigidbody> ().AddForce (-RightCamera.transform.right * angleZ);
And now the sphere rolls relative to the camera.