- Home /
Defining the rotation of a transform to rotate an object via Lerp
Ok, so I'm trying to get an object to rotate 180 degrees after a keystroke triggers a gravity reversal in my game (so that it's "walking on the ceiling", or back on the ground after a second reversal). I've got the gravity part worked out but I'm having trouble getting the object to rotate when the gravity shift occurs.
I've searched all over for a few hours now on how to Lerp between the two rotations and most answers provide something like this:
transform.rotation = Quaternion.Lerp (fromRotation, toRotation, Time.time * speed);
with fromRotation and toRotation being Transforms. But nothing explains how I define those Transforms other than to have an empty variable to drag in objects (but the unity scripting reference says they should be different objects than the one my script is attached to- which doesn't help me at all since all three of these things (the current rotation, the destination rotation and the object this script is attached to) are all applying to the same object).
So how do I define the toRotation to simply be 180 degrees from the fromRotation/current rotation in the first place? i know Quaternions aren't simply x/y/z but I'm not seeing how to define a rotation without making extra objects for them to look at (which I could do, I suppose, but that's seems extraordinarily unnecessary).
Answer by robertbu · May 08, 2013 at 05:28 AM
First, you rotation code as you have listed it will not work. The typical use is:
transform.rotation = Quaternion.Lerp (transform.rotation, toRotation, Time.deltaTime * speed);
This will produce an eased rotation (slower at the end). It is by far the most commonly posted Quaternion.Lerp() code on Unity Answers, but is an "misuse" of Lerp(). The last value of Lerp() is designed to increment from 0 to 1. This is often done by using a timer, and the result is a linear movement without the easing at the end.
As for creating quaternions, there are several functions in the Quaternion class that will create them for you. For example Quaternion.Euler() will produce a rotation with a specified angle:
var qTo = Quaternion.Euler(180, 0, 0);
Note quaternions are not the only way to solve your problem. You could use Transform.Rotate() for example or you could assign angles directly to Transform.eulerAngles. As with most things concerning rotations, are some gotchas with these two solutions as well.
Thanks!
The only two things now are that the rotation speed doesn't seem to change no matter what I change it to and when I try to reverse the gravity back to normal, the object rotates back the way it came (counter clockwise from the POV), when I would like it to continue rotating in the same direction (clockwise from the POV) so it sorta corkscrews as you progress forward if you keep changing gravities.
This is the entire code with both the gravity switching and the rotation as we've discussed:
#pragma strict
public var gravity : boolean = true;
public var grounded : boolean = true;
public var speed : float = 100;
public var antigravityForce : float = 2;
var qBack = Quaternion.Euler(0, 0, 0);
var qTo = Quaternion.Euler(0, 0, 180);
function OnCollisionEnter(collision: Collision)
{
//Check to see if object is on floor or ceiling
Debug.Log ("Collided With" + collision.gameObject.name);
if(collision.gameObject.name.Contains ("1st Floor Block") || collision.gameObject.name.Contains("2nd Floor Block"))
{
grounded = true;
Debug.Log ("Grounded!");
}
}
function Update ()
{
var value = Input.GetButton ("P1-SwitchGrav");
//Check to see if player has shifted their gravity
if (Input.GetButton ("P1-SwitchGrav"))
{
Debug.Log("Hit Z!");
//If gravity is active & object is on floor, disable gravity,
//indicate object is not on floor & start to reverse gravity
if (this.gravity == true && this.grounded == true)
{
Debug.Log("Rising!");
this.gravity = false;
this.grounded = false;
this.rigidbody.useGravity = false;
ReversedGravity();
}
//If gravity is disabled & object is on ceiling, reactivate gravity
//& indicate object is not on ceiling
if (this.gravity == false && this.grounded == true)
{
Debug.Log("Falling!");
this.gravity = true;
this.grounded = false;
this.rigidbody.useGravity = true;
RestoredGravity();
}
}
}
function ReversedGravity ()
{
Debug.Log("Reversing!");
//When gravity is disabled, apply constant force towards ceiling and rotate character upside down
while (this.gravity == false)
{
rigidbody.AddForce(0, antigravityForce, 0);
transform.rotation = Quaternion.Lerp (transform.rotation, qTo, Time.deltaTime * speed);
yield;
}
}
function RestoredGravity ()
{
Debug.Log("Restored!");
//When gravity is enabled, rotate character rightside up
while (this.gravity == true)
{
Debug.Log("Restoring Rotation!");
transform.rotation = Quaternion.Lerp (transform.rotation, qBack, Time.deltaTime * speed);
yield;
}
}
I converted your answer to a comment. Replies to answer should be posted as comments not as seperate answer.
I'm guessing that you tried to change 'speed' in the code above. Since it is a public variable, it needs to be changed in the inspector. The value assigned in code will only be used the at the time the script is attached to the object. As an alternate, you could make speed private:
private var speed = 100;
As for the rotation, rotations calculations are "lazy." They take the shortest distance between two vectors. With exactly 180 rotation, the path is arbitrary. The way to get your code to work is to make is shorter to go the way you want than to rotate back the way it came. So at the time gravity is flipped, just do a Transform.Rotate() an every so slight amount and the rotation should do what you want.
Ah, that did the trick for the speed- figured it would be something obvious. I will give that rotation trick a try. So, basically, I'm going to set the rotation to, say, qTemp = Quaternion.Euler(0, 0, 181), then Lerp from there back to 0?
Thanks again!
I would leave your rotation at (0,0,0) and (0,0,180), but I would bump the rotation just before you flip. That is call Transform.Rotate() to rotate it a fraction of a degree in the direction you want it to go.