Reputation: 20995
I'm writing a function that slowly turns exactly 90 degreees over the course of a period of time. So far everything is working fine, I just need to figure out how to make it rotate around a point instead of rotation around the transforms center.
protected bool _isRotating = false;
public IEnumerator RotateWithEasing(GameHelper.Axis axis, Vector3 isolatedAxisPoint, float inTime)
{
if(_isRotating)
{
yield break;
}
_isRotating = true;
var degrees = this.GetDegreesFromAxis(axis);
Quaternion fromAngle = transform.rotation;
Quaternion toAngle = Quaternion.Euler(transform.eulerAngles + degrees);
for (float t = 0f; t < 1f; t += Time.deltaTime / inTime)
{
transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
yield return null;
}
_isRotating = false;
}
Can anyone help point me in the right direction, How can I modify this so it rotates around the specified isolatedAxisPoint?
Upvotes: 1
Views: 3360
Reputation: 12631
Here's an actual example Unity tween that happened to be showing in a text editor another window!
If you want to rotate something, it is trivial just use deltaTime in a loop in an IEnumerator, and adjust the eulerAngles or just call Rotate. (Never use quaternions for any reason in Unity.) In this example I just call Rotate.
This is a very basic pattern in Unity.
Here is the basic pattern of a tween in Unity. You will do this 1000s of times in Unity!
Note that of course you
yield return null;
inside the loop, it means "wait until the next frame".
(Note that as with any tween, it's good practice to force-set the final values at the end so you know it's perfect. Notice in this example I simply set the eulerAngles, at the end when the loop is finished.)
private IEnumerator _roll( Vector3 delta )
{
rollBegins.Invoke();
Vector3 begin = transform.eulerAngles;
float rollSecs = 2f; // speed of the roll
float startTime = Time.time;
float endTime = startTime+rollSecs;
while (Time.time < endTime)
{
Vector3 d = delta * ( Time.deltaTime / rollSecs );
transform.Rotate(d, Space.World );
yield return null;
}
transform.eulerAngles = .. perfectly correct end values;
busy = false;
rollComplete.Invoke();
}
{Note, in that actual code example, "delta" is understood to be only on one axis; don't worry about this, it's just an example of a tween using a coroutine.}
Note - of course there are "two ways" to go inside the loop. You can calculate the small amount you should move it that frame. Or, you can just calculate what the new position should be at that time. It's up to you. Many programmers think the latter is more logical, if so, do that. Note too that you can do the while loop until a certain time has passed, or, you can do the while loop until you reach your destination! (Being very careful about float equalities.) The choice is yours.
Note that very very often you use Lerp or even better SmoothStep with such tweens. It is ubiquitous in Unity. Once you master the basic pattern, experiment with that.
Note that in my example the code is using UnityEvent to flag the beginning and end of the animation. This is extremely common. After all it's usually the case that once some movement finishes, you then have to go on and do something else. Another good example is, while something is animating, the user is blocked from say steering or whatever is the case in your game.
Excellent intro to UnityEvent https://stackoverflow.com/a/36249404/294884 pls vote it up :)
For the record.
The truly advanced way to tween in Unity is to tweeng:
Basic Tweeng code base appears in this question.
It takes a while to get the hang of that but it is incredibly powerful. It's mindboggling that the tweeng extension is only a few lines of code.
Upvotes: 5
Reputation: 659
Use something like, assuming rotate in 1 sec by 90 degree:
int rotatedDegrees;
int desiredRotation = 90;
float startTime = null;
float rotationDuration = 1f;
public void rotate()
{
if(startTime == null)
startTime = time.Now;
while((time.Now - starttime) / rotationDuration > (((float) rotatedDegrees) / desiredRotation))
{
transform.RotateAround (isolatedAxisPoint, Vector3.up, 1);
rotatedDegrees++;
}
}
At startTime + 0 it has rotated 0 degrees.
Now assume time.Now is something like startTime + 0.1 (+100ms). Then time.Now - startTime is 0.1, rotate until (rotatedDegrees / desiredRotation) is 0.1 which is 9, or 1/10 of the total rotation.
Upvotes: 0