Tuesday, July 14, 2015

unity - How can I rotate a Transform over a specified time in a single line of code?



How can I rotate a Transform over a specified time in a single line of code?


I have had a lot of trouble with this in the past. I wrote a script which rotates a Transform by a specified rotation over n seconds, or rotates a Transform towards a Vector3 over n seconds, in a one liner. I hope it helps others in the future. See below.



Answer



Create a script called TransformExtentions. Paste the code into that script.


You can call Transform.RotateTowardsOverTime(Vector3, float) on your Transform where the Vector3 is the target you want to rotate towards and the float is the number of seconds you want it to take.



You can call Transform.RotateOverTime(Vector3, float) on your Transform where the Vector3 is the rotation you want to apply and the float is the number of seconds you want it to take. You can apply rotations greater than 360 degrees or less than -360 degrees.


Calling Transform.RotateTowardsOverTime(Vector3, float) or Transform.RotateOverTime(Vector3, float) will cancel out any active rotation calls on the Transform.


If you pass in 0 seconds, the Transform will rotate infinitely. If you pass in negative seconds, the Transform will rotate in reverse.


using UnityEngine;
using System.Collections;
using System;

public static class TransformExtensions
{
///

/// Rotates the transform to a specified rotation over a set number of seconds.
/// For an infinite rotation, multiply the degrees by a float to adjust the speed, and set the duration to 0 seconds.
/// Calling RotateOverTime() or RotateTowardsOverTime() will cancel any pending rotations on this transform.
///

public static void RotateTowardsOverTime(this Transform transform, Vector3 degrees, float seconds)
{
Vector3 rotationToBeMade = degrees - transform.rotation.eulerAngles;
if (degrees.z > 270.0F && transform.rotation.eulerAngles.z < 90.0F)
{
rotationToBeMade.z = -(360.0F - degrees.z + transform.rotation.eulerAngles.z);

}
if (transform.rotation.eulerAngles.z > 270.0F && degrees.z < 90.0F)
{
rotationToBeMade.z = 360.0F - transform.rotation.eulerAngles.z + degrees.z;
}
RotateOverTime(transform, rotationToBeMade, seconds);
}

///
/// Rotates the transform by a specified number of degrees over a set number of seconds.

/// For an infinite rotation, multiply the degrees by a float to adjust the speed, and set the duration to 0 seconds.
/// Calling RotateOverTime() or RotateTowardsOverTime() will cancel any pending rotations on this transform.
///

public static void RotateOverTime(this Transform transform, Vector3 degrees, float seconds)
{
RotateOverTime[] oldRotateOverTimeComponents = transform.gameObject.GetComponents();
foreach (RotateOverTime oldRotateOverTimeComponent in oldRotateOverTimeComponents)
{
GameObject.Destroy(oldRotateOverTimeComponent);
}


RotateOverTime rotateOverTimeComponent = transform.gameObject.AddComponent();
rotateOverTimeComponent.hideFlags = HideFlags.HideInInspector;
rotateOverTimeComponent.Degrees = degrees;
rotateOverTimeComponent.Seconds = seconds;
}

class RotateOverTime : MonoBehaviour
{
public Vector3 Degrees { get; set; }

public float Seconds { get; set; }

private Vector3 rotationCompleted = Vector3.zero;
private Vector3 speed;
private Vector3 startRotation;

void Start()
{
speed = GetBalancedRotationSpeeds(Degrees, Seconds);
startRotation = transform.eulerAngles;

}

void FixedUpdate()
{
UpdateRotation();
if (IsRotationComplete())
{
Destroy(this);
}
}


private Vector3 GetBalancedRotationSpeeds(Vector3 degrees, float seconds)
{
if (seconds == 0)
{
seconds = 1;
}
float degreesWeight = (Degrees.x + Degrees.y + Degrees.z) / 3;
float speedModifier = degreesWeight / seconds;
float totalChangeInDegrees = Math.Abs(degrees.x) + Math.Abs(degrees.y) + Math.Abs(degrees.z);

float xWeight = Math.Abs(degrees.x) / totalChangeInDegrees;
float yWeight = Math.Abs(degrees.y) / totalChangeInDegrees;
float zWeight = Math.Abs(degrees.z) / totalChangeInDegrees;
float xSpeed = xWeight * speedModifier * 3;
float ySpeed = yWeight * speedModifier * 3;
float zSpeed = zWeight * speedModifier * 3;
return new Vector3(xSpeed, ySpeed, zSpeed);
}

private void UpdateRotation()

{
rotationCompleted += Time.deltaTime * speed;
Vector3 rotation = Quaternion.Euler(rotationCompleted + startRotation).eulerAngles;
bool rotationIsValid = !(float.IsNaN(rotationCompleted.x) || float.IsNaN(rotationCompleted.y) || float.IsNaN(rotationCompleted.z) && float.IsNaN(startRotation.x) || float.IsNaN(startRotation.y) || float.IsNaN(startRotation.z) || float.IsNaN(rotation.x) || float.IsNaN(rotation.y) || float.IsNaN(rotation.z));
if (!rotationIsValid)
{
Destroy(this);
}
transform.eulerAngles = rotation;
}


private bool IsRotationComplete()
{
bool xRotationIsComplete = Math.Abs(rotationCompleted.x) >= Math.Abs(Degrees.x);
bool yRotationIsComplete = Math.Abs(rotationCompleted.y) >= Math.Abs(Degrees.y);
bool zRotationIsComplete = Math.Abs(rotationCompleted.z) >= Math.Abs(Degrees.z);
return xRotationIsComplete && yRotationIsComplete && zRotationIsComplete && Seconds != 0;
}
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...