I’m trying to make a script for rolling cubes. I use the size of the cube and a couple of hand edited animation curves to, essentially, figure out what rotation the cube should have and how much to bob it up and down based on the cube’s world-space position. The idea is that as the cube moves, it automatically handles the rolling behaviour. The works great along one axis, but I would like it to work along both X and Z. The problem is that if the cube has rotated along the first axis, the rotation on the second axis will now happen on the wrong axis. My question is, how can I rotate my cube (preferably using Rigidbody.MoveRotation) so my rotations always happen around the world X and Z axes?
Here is my script as it currently appears (sorry for the JS):
#pragma strict
private var thisTransform : Transform; // reference to this object's transform
private var thisRigidbody : Rigidbody; // reference to this object's rigidbody
private var startPosition : Vector3 = Vector3.zero; // used to store the start position of the object
public var size : float = 8.0f; // size of the tumbler cube on one side
private var cornerHeightOffset : float = 0.0f; // distance difference between height of center when flat vs 45degs
public var heightCurve : AnimationCurve; // this curve defines how the cube moves up and down during the rotation
public var rotationCurve : AnimationCurve; // this curve defines the rotation of the cube over the course of the movement
function Awake ()
{
thisTransform = gameObject.transform;
thisRigidbody = gameObject.GetComponent.<Rigidbody>();
startPosition = thisTransform.position; //initialize the start position
cornerHeightOffset = Mathf.Sqrt( ( 2 * ( Mathf.Pow( (size/2), 2) ) ) ); //calculate the distance between center and corner
cornerHeightOffset = cornerHeightOffset - (size/2.0f); //calculate difference between height from corner and height from side
}
function FixedUpdate ()
{
var offset : Vector3 = thisTransform.position - startPosition; //calculate the offset from start position
var heightOffset : float = 0.0f; // this is the offset which will be applied to the height of the cube
var tempHeightEval : Vector2 = Vector2.zero; // this is the calculated offset by X and Z movement
//evaluate height in X and Z
tempHeightEval.x = heightCurve.Evaluate(offset.x / size);
tempHeightEval.y = heightCurve.Evaluate(offset.z / size);
Debug.Log("heightEvaluation = " + tempHeightEval , gameObject);
tempHeightEval *= cornerHeightOffset; // multiply the evaluated result by the cornerHeight
heightOffset = Mathf.Max( tempHeightEval.x , tempHeightEval.y ); //set heightOffset to whichever is greatest
var rotation : Quaternion = Quaternion.identity; // this will hold the final calculated rotation to apply
var tempRotationEval : Vector2 = Vector2.zero; // this is the rotation on each axis.
//evaluate the rotation in X and Z (*4 to account for 360degs being 4 1/4 rotations)
tempRotationEval.x = rotationCurve.Evaluate(offset.z / (size*4.0f)); // rotate along one axis as the other axis moves
tempRotationEval.y = rotationCurve.Evaluate(-offset.x / (size*4.0f));
tempRotationEval *= 360.0f; // mutiply the result by 360 to get a full rotation between 0 and 1
rotation = Quaternion.Euler(tempRotationEval.x , 0.0f , tempRotationEval.y);
// apply the movement and rotation
thisRigidbody.MovePosition(Vector3 (thisTransform.position.x , startPosition.y + heightOffset , thisTransform.position.z));
thisRigidbody.MoveRotation(rotation);
}