Unity C# Quaternion Rotation Correcting orientation - c#

IHi I've been working on a camera rotation method.
I'm trying to rotate a camera using the mouse inputs.
I need the horizontal rotation to be parallel to a x,y plane(my board) and the vertical rotation to be limited to certain angle(something like 40 degree to -40).
I use quaternions to rotate the camera.
Here my code so far
float angle = (mouseX_Current - mouseX_ActionStart) * 0.25f;
Quaternion horizontalRotationQuat = Quaternion.AngleAxis(angle, Vector3.up);
angle = (mouseY_Current - mouseY_ActionStart) * 0.25f;
Quaternion verticalRotationQuat = Quaternion.AngleAxis(angle, Vector3.right);
Camera.main.transform.rotation *= (horizontalRotationQuat * verticalRotationQuat);
My problem is that by adding those mouse related rotations to my current camera orientation quaternion the camera is no more parallel to the plane(x,y) which it s looking at.
I' ve been trying to create a correction quaternion to add to the camera quaternion after adding those mouse related rotations but I can't seem to find the right one.
Quaternion currentOrientationQuat = Camera.main.transform.rotation;
Quaternion corretionQuat = new Quaternion(0.0f, 0.0f, - currentOrientationQuat.z, currentOrientationQuat.w);
Camera.main.transform.rotation *= corretionQuat;
If someone could help me out on this I would be very grateful.
Thanks.
Sorry for the English, not my primary language.

Solved this using another method
float angle = (mouseX_Current - mouseX_ActionStart) * 0.25f;
Camera.main.transform.Rotate(0.0f, 0.0f, angle, Space.World);
angle = (mouseY_Current - mouseY_ActionStart) * 0.25f;
Camera.main.transform.Rotate(angle, 0.0f, 0.0f, Space.Self);
Feeling dumb after seeing how easy it was to do it.
Did'nt even needed the quaternions for this one.

Related

Smooth rotating in the direction player is moving towards (in 2D)

So I tried to use a script from tutorial that Makes a 3d object rotates smoothly to the direction the object is moving towards and when I tried to use it to my 2d sprite it started to rotate really weird 3D rotating, I am really new to unity so please expect any stupid mistakes and here is the script I used:
float horizontalInput = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput).normalized;
if (movementDirection != Vector3.zero)
{
Quaternion toRotation = Quaternion.FromToRotation(movementDirection, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation,
rotationSpeed * Time.deltaTime);
}
I tried to replace it with Vector3.right but still the same issue, I also tried to replace it with Vector3.up but this weird 3D rotation still exist.

Unity 3D - rotating gameobject without rotating axis

Hope my title summarises my problem. I have a rocket on a 2d game that only moves horizontally across the screen. I want it to rotate towards the players finger (the direction of movement), but cannot find a way to rotate the object without rotating the whole axis it moves on. I simply need it to seem like it has turned, but it should keep moving along the x. How can I go about this?
void Start () {
//scoreT = GetComponent<TextMeshProUGUI> ();
gameSpeed = 1;
score = 0;
Rigidbody2D rb2d = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void Update () {
float MoveHorizontal = Input.GetAxis ("Horizontal");
Vector2 Movement = new Vector2 (MoveHorizontal, 0.0f);
rb2d.rotation = Quaternion.Euler (0.0f, 0, 0f, rb2d.velocity.x * -tilt);
transform.Translate (MoveHorizontal * speed, 0, 0);
One thing you can do is to modify rigidbody.rotation of your rocket rocket to make it tilt, when it moves, to one direction or to another. For example:
float tilt - 0.3f;
//In case you prefer the rotation in another axis you just need to modify the position of the rigidbody.velocity.x * -tilt
rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
Since you didn't add any code I am not sure how you are moving your rocket, so I will post a generic code you will need to adapt depending on your own project:
public class PlayerController : MonoBehaviour
{
public float speed;
//The tild factor
public float tilt;
//The limit within the spaceship can move
public Boundary boundary;
void FixedUpdate ()
{
//You will need to capture the screen touchs of the user for the inputs
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
//Applying the movement to the GameObject
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidbody.velocity = movement * speed;
//To ensure the GameObject doesnt move outside of the game boundary
rigidbody.position = new Vector3
(
Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
);
//Here is where you apply the rotation
rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
}
}
As an aside, you are doing a space 2D game you may be interested in checking this tutorial:
https://unity3d.com/learn/tutorials/s/space-shooter-tutorial
What you want is to move your object in global/world space. As it seems the movement of your rocket is currently happening within local space. So when you rotate the rocket it's local coordinates are rotated as well. The world space coordinates are fixed and will never rotate when you change your rocket.
Here is another explanation at that.
You can also have a look at Transform.localPosition and Transform.position and see how your rocket behaves when using one or the other.
You could make the sprite/renderer a child of the GameObject that is your rocket.
Then you can freely rotate the sprite/renderer around without changing the rotation you move the parent GameObject.
This is a hacky solution but it achieves the desired result.
You must move your object relative to the world and rotate locally.
So use Transform.position to move your object and Transform.LocalRotation to rotate it.
Or you can put the part that must rotate as a children of the object that translate, and rotate the children.

Rotating Child Object in Unity 2D with C#

I have a moving object (the ship) with several child objects (its turrets). The turrets are to rotate towards the player object regardless of the direction the ship is facing. The problem is, unless the ship is rotated straight up, the turrets just spin around wildly.
The code to rotate the turrets is as follows:
//Rotate towards player
dir = PlayerScript.GlobalVariables.playerPosition - myPosition;
angleToTarget = Vector2.Angle(dir, transform.up);
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
transform.localRotation = Quaternion.RotateTowards(transform.rotation, Quaternion.AngleAxis(angle, Vector3.forward), turnSpeed);
The ship is instantiated with this code. Changing rotation changes the intitial rotation. At rotation = 180 it is rotated vertically up:
newEnemyShip = Object.Instantiate(enemyShip2, new Vector3(mousePosition.x, mousePosition.y, 0), Quaternion.Euler(210, 0, rotation));
The ship has an initial rotation which never changes. It's movement code is:
//moves in straight line at constant speed
transform.Translate(Vector3.up * currentSpeed * Time.deltaTime, Space.Self);
It also has this to lock it onto the 2d plane:
//Lock rotation on 2d plane
Quaternion q = transform.rotation;
q.eulerAngles = new Vector3(0, 0, q.eulerAngles.z);
transform.rotation = q;
Any help would be great appreciated!
I figured it out! I'm not sure what the problem was with the original code, but the following code for the turret worked:
//Rotate towards player
dir = PlayerScript.GlobalVariables.playerPosition - myPosition;
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.AngleAxis(angle, Vector3.forward), turnSpeed);
Bijan, thanks for taking the time to look and respond
Why you just don't use transform.LookAt(playerPosition) ?

Unity - Using RayCast to orient object to terrain (C#)

I am currently making a flight simulator. Right now, I am trying to get the plane to fly on its own, but I am having some problems with trying to rotate the plane such that it is parallel to the ground.
This is my code:
heightDetect = new Ray (transform.position, Vector3.down);
if (Physics.Raycast (heightDetect, out hit, Mathf.Infinity)) {
Debug.Log (hit.distance);
transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
Debug.DrawRay (heightDetect.origin, heightDetect.direction*1000);
}
The code works and all, but the problem is it is way too bumpy. The camera on the plane keeps jerking about on my screen, and is completely unplayable. Is there a way to smoothen this process? Thank you!
Presumably you are doing this in your Update function, and therefore changing the rotation of your plane many times per second. Instead of directly setting the rotation, you could use spherical linear interpolation:
public float speed = 0.1f;
void Update() {
...
var targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * speed);
}
This effectively smoothes the rotation over time. It works by taking the current rotation and the eventual desired rotation, but only returning a rotation somewhere in between (controlled by speed).
If I understand correctly, you're looking for the Quaternion.Lerp to smooth your rotation for Quaternions, or Mathf.LerpAngle for Vector3 rotation.
Usage example:
Vector3 currentRotation = transform.rotation;
Vector3 newRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
newRotation = new Vector3(
Mathf.LerpAngle(currentRotation.x, newRotation.x, Time.deltaTime),
Mathf.LerpAngle(currentRotation.y, newRotation.y, Time.deltaTime),
Mathf.LerpAngle(currentRotation.z, newRotation.z, Time.deltaTime));
transform.rotation = newRotation;
Multiply Time.deltaTime by any value to change lerp's "speed".

Translation on a X,Z plane using variable axis relative to camera orientation

I have a board on the world X,Z axis.
I have a camera that can rotate to look downward or upward and rotate left to right using the world Y axis.
Here's the camera rotation code:
float angle = (mouseX_Current - mouseX_ActionStart) * camRotationSpeedMod;
Camera.main.transform.Rotate(0.0f, angle, 0.0f, Space.World);
angle = (mouseY_Current - mouseY_ActionStart) * camRotationSpeedMod;
Camera.main.transform.Rotate(angle, 0.0f, 0.0f, Space.Self);
Using mouse button down and a mouse position input(drag&Drop) I translate the camera in the world. It receive a 2D vector that contain the X and Y value of the mouse(drag&drop) operation. Here's the code of the method I use :
private void CameraOnPlaneTranslation(Vector2 myVector)
{
float cameraYPos = Camera.main.transform.position.y;
Camera.main.transform.Translate(new Vector3(myVector[0], 0.0f, myVector[1]));
Camera.main.transform.position = new Vector3(Camera.main.transform.position.x, cameraYPos, Camera.main.transform.position.z);
}
Problem : When my camera is not oriented directly toward the Z Axis(0.0f, Z, 0.0f) the translation vector I compute is incorrect. I need to change the Y value of the vector so the camera don't move on the world Y axis.
Thanks
I am not familiar with Unity, but supposing it is similar to other 3D systems on these points, I will attempt an answer and hopefully not embarrass myself.
It looks like you /translate/ the camera position, then immediately /set/ the camera position, thus overwriting the work done by translate. If this is the case, you should try setting camera.main.transform.position once (in the line after you create the Camera). Then only apply myVector by the Translate call (as you have it). Thus you should eliminate the third line of the method Camera.main.transform.position = new Vector3(Camera.main.transform.position.x, cameraYPos, Camera.main.transform.position.z);
After trying this, if it still does not do what you expect, see if it needs you to Update the view or Flush or ApplyTransform . . . anything that will make it understand you are done altering the transform and you are ready for it to process again with the updated transform.
I've solved this by adding another GameObject that is affected only by the camera right/left rotations(world up vector) and the camera translations.
In the Awake method
cameraOrientation = new GameObject("cameraOrientation");
cameraOrientation.transform.position = Camera.main.transform.position;
cameraOrientation.transform.localEulerAngles = new Vector3(0.0f, Camera.main.transform.localEulerAngles.y, 0.0f);
In the rotation method
float angle = (mouseX_Current - mouseX_ActionStart) * camRotationSpeedMod;
Camera.main.transform.Rotate(0.0f, angle, 0.0f, Space.World);
cameraOrientation.transform.Rotate(0.0f, angle, 0.0f, Space.World);
angle = (mouseY_Current - mouseY_ActionStart) * camRotationSpeedMod;
Camera.main.transform.Rotate(angle, 0.0f, 0.0f, Space.Self);
And finally the translation method
cameraOrientation.transform.Translate(new Vector3(myVector[0], 0.0f, myVector[1]));
Camera.main.transform.position = cameraOrientation.transform.position;

Categories