- Home /
Quaternion.slerp messing with wrong axies
So I'm trying to write a script to rotate my sled between -10 and 10 degrees on the X axis when pressing the left and right arrow keys respectively. What currently happens is that the sled will flip entirely the wrong direction on the Y axis and begin to spiral out.
I have been trying to figure this out for days, can anyone help?
private void Start()
{
rb.transform.rotation = Quaternion.Euler(0, 180, 20);
AngleL = Quaternion.Euler(-10, rb.rotation.y, rb.rotation.z);
AngleR = Quaternion.Euler(10, rb.rotation.y, rb.rotation.z);
Physics.gravity = new Vector3(0, -400f, 0);
}
void FixedUpdate()
{
transform.Translate(new Vector3(-moveSpeed,0,0) * Time.deltaTime);
if(Input.GetAxis("Horizontal") > 0)
{
transform.Translate(new Vector3(0,0,turnSpeed) * Time.deltaTime);
//anim.SetTrigger("Right");
currentAngle = AngleR;
transform.rotation = Quaternion.Slerp(transform.rotation, currentAngle, 0.1f);
}
if (Input.GetAxis("Horizontal") < 0)
{
transform.Translate(new Vector3(0,0,-turnSpeed) * Time.deltaTime);
currentAngle = AngleL;
transform.rotation = Quaternion.Slerp(transform.rotation, currentAngle, 0.1f);
}
}
I think you might be a bit confused about how Unity does rotations. Someone better suited for the explanation will probably come along and help, but this bit here is definitely not doing what you probably think it is:
rb.transform.rotation = Quaternion.Euler(0, 180, 20);
AngleL = Quaternion.Euler(-10, rb.rotation.y, rb.rotation.z);
AngleR = Quaternion.Euler(10, rb.rotation.y, rb.rotation.z);
Physics.gravity = new Vector3(0, -400f, 0);
Those y
and z
components are not in degrees, btw.
Answer by TreyH · Nov 26, 2019 at 08:40 PM
You're getting weird behavior because the Start() function body seems to have some unit confusion and there's explicit Quaternion usage.
So for rotations, you will want to keep track of when you're dealing with the tradition Euler angles and when you're dealing with Quaternions. Unity keeps track of transform orientation with Quaternions, so this can seem a bit daunting but actually becomes pretty convenient once you learn how to use their operators / built-in functions.
For your case, I'm not sure why you're starting off with that weird rotation so I'll skip it in my example. Your goal is to gradually tilt something +/- 10 degrees on the Y-axis based on player input, so we'll just do that directly.
using UnityEngine;
public class RotateSlightly : MonoBehaviour
{
Rigidbody rb;
Quaternion initialRotation;
Quaternion desiredLeftRotation;
Quaternion desiredRightRotation;
float horizontal;
Quaternion targetRotation;
// Start is called before the first frame update
void Start()
{
this.rb = this.GetComponent<Rigidbody>();
// Just take whatever rotation we started with
this.initialRotation = this.rb.rotation;
// Note that the * operator lets us compound rotations.
this.desiredLeftRotation = Quaternion.Euler(0, -10, 0) * this.initialRotation;
this.desiredRightRotation = Quaternion.Euler(0, 10, 0) * this.initialRotation;
}
// Update is called once per frame
void Update()
{
// Get our input and assume the initial rotation
this.horizontal = Input.GetAxis("Horizontal");
this.targetRotation = this.initialRotation;
// Check if we're trying to move in some direction
if (this.horizontal > 0)
this.targetRotation = this.desiredRightRotation;
else if (horizontal < 0)
this.targetRotation = this.desiredLeftRotation;
// Apply that rotation
this.rb.rotation = Quaternion.Slerp(this.rb.rotation, this.targetRotation, 0.1f);
}
void OnGUI()
{
GUI.HorizontalSlider(new Rect(0, Screen.height - 40, Screen.width, 40), horizontal, -1, 1);
GUI.TextArea(new Rect(Screen.width / 2 - 100, Screen.height - 80, 200, 40), this.rb.rotation.ToString("F4"));
}
}
You should be able to drop that onto an object and get the following behavior: