2
\$\begingroup\$

I'm trying to make a plane rotate down a certain amount and 180 degrees horizontally over 2 seconds.

Basically I want it to take the plane 1 second to rotate to a horizontal-facing angle, then take the other second to rotate 180 degrees around to face the other direction.

The formula I'm currently using is:

    //If you're rotating, lower the speed and rotate the plane.
    if (rotate == 1 && rotationPhase > 0) {
        //If in phase 0, figure out which phase you need too go to.
        if (angle > 90 && rotationPhase == 1) {
            //Rotation phase 2 = rotating down
            rotationPhase = 2;
            rotationAngleTime = angle - 90;
        }
        else if (rotationPhase == 1) {
            //Rotation phase 3 = rotating up
            rotationPhase = 3;
            rotationAngleTime = 90 - angle;
        }

        //After phase 0, if in phase 1 begin rotating down, if in phase 2 begin rotating up.
        if (angle > 90 && rotationPhase == 2) {
            transform.Rotate(0, 0, -rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)));
            angle -= rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (angle > 89 && angle < 91) {
                angle = 90;
                rotationPhase = 4;
                rotationAngleTime = 180;
            }
        }
        else if (rotationPhase == 3) {
            transform.Rotate(0, 0, rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)));
            angle += rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (angle > 89 && angle < 91) {
                angle = 90;
                rotationPhase = 4;
                rotationAngleTime = 180;
            }
        }

        //After you have rotated to horizontal in phase 1/2, rotate around to face the other direction.
        if (rotationPhase == 4) {
            transform.Rotate(rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)), 0, 0);
            rotationAngle += rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (rotationAngle > 179) {
                rotationAngle = 0;
                rotationPhase = 0;
                rotationAngleTime = 0;
            }
        }
    }

I've tried many different things, but I can't figure out what to do.

EDIT: This seems to be a problem with Time.deltaTime. I can get the plane to rotate correctly, but for some reason it's not rotating over the right amount of time. I have a timer being subtracted by Time.deltaTime, and this animation happening, and the animation always finishes about half a second before the timer runs out.

\$\endgroup\$

4 Answers 4

2
\$\begingroup\$

Use the line:

transform.Rotate(Vector3.up, horizontalAngle*Time.deltaTime);

to carry out the horizontal rotation over 1 second. Then use the line:

transform.Rotate(Vector3.right, verticalAngle*Time.deltaTime);

to carry out the second phase of your rotation. You can keep track of which rotation you're supposed to be applying using a method similar to the one you posted (the rotationPhase variable), but I would recommend using an enum for readability:

enum RotationPhase { Horizontal, Vertical };
public RotationPhase currentPhase = RotationPhase.Horizontal;

Finally, if you want to create a smoother rotation, you can look into the Vector3.SmoothDamp function; the documentation is here. In order to use this method you will first need to calculate the forward vectors of the plane as a result of each rotation. That vector becomes you're "target" vector. Then you can check if you've completed the rotation by checking the angle between the current vector and the target vector:

transform.forward = Vector3.SmoothDamp(transform.forward, target, ref vel, 1.0f, /*maxSpeed*/);
if(Vector3.Angle(transform.forward, target) < 1.0f) {
    // move on to next phase of rotation
}

Note that you would need to set up a variable to store the current velocity of the operation (vel in my example).

\$\endgroup\$
1
  • \$\begingroup\$ This doesn't seem to rotate the plane correctly, the plane rotates diagonally and gets stuck like that. \$\endgroup\$ Commented Mar 6, 2012 at 16:39
1
\$\begingroup\$

To get how much we need to rotate per ms assuming the timedelta is in ms also.

total_ticks = 1000 * seconds
rotation_per_tick = angle / total_ticks

In update we rotate until elapsed time is up

if (total_ticks != 0) {
    if (total_ticks > Time.deltaTime) {
        transform.Rotate(rotation_per_tick * Time.deltaTime)
        total_ticks -= Time.deltaTime
    } else {
        transform.Rotate(rotation_per_tick * total_ticks)
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ That code will not actually run, transform.Rotate is given insufficient arguments. Also, your calculation of the time of rotation is incorrect. Time.deltaTime returns the elapsed time in seconds, not milliseconds. \$\endgroup\$ Commented Mar 6, 2012 at 1:48
  • 2
    \$\begingroup\$ So? I've never used unity. I leave it up to the asker to deal with API specific issues. \$\endgroup\$ Commented Mar 6, 2012 at 2:00
  • \$\begingroup\$ Something similar to that may work, however Disco is correct, Time.deltaTime returns in seconds not milliseconds. \$\endgroup\$ Commented Mar 6, 2012 at 16:39
1
\$\begingroup\$

I strongly suggest looking at Itween, which is free, and has the ability to in a single line, do a "rotate x by 180 degrees taking 2 seconds, before calling procedure y". Performance is good even for mobile.

An example might be:

Vector3 customRotation = new Vector3(0f,0.5f,0f);
iTween.RotateBy(myGameObject, customRotation, 2f)

Noting that the rotation is normalized, so 1.0f == 360 degrees.

iTween also has an alternative syntax that opens up a span of additional options for this kind of rotation, for example adding easing curves or the possibility of a callback when the routine completes.

Vector3 customRotation = new Vector3(0f,0.5f,0f);
iTween.RotateBy(myGameObject, iTween.Hash("Amount",customRotation,"EaseType",iTween.EaseType.EaseOutCubic,"OnComplete","RunThisMethodNext");
\$\endgroup\$
1
  • \$\begingroup\$ This answer would be better with a link and an example. \$\endgroup\$
    – House
    Commented Apr 19, 2012 at 18:56
0
\$\begingroup\$

EDIT: This makes the animation run properly, but it's still not running at the correct amount of time.

I figured out how to fix the problem myself, the solution was:

//If you're rotating, lower the speed and rotate the plane.
    if (rotate == 1 && rotationPhase > 0) {
        //If in phase 0, figure out which phase you need too go to.
        if (angle > 90 && rotationPhase == 1) {
            //Rotation phase 2 = rotating down
            rotationPhase = 2;
            rotationAngleTime = angle - 90;
        }
        else if (rotationPhase == 1) {
            //Rotation phase 3 = rotating up
            rotationPhase = 3;
            rotationAngleTime = 90 - angle;
        }

        //After phase 0, if in phase 1 begin rotating down, if in phase 2 begin rotating up.
        if (angle > 90 && rotationPhase == 2) {
            transform.Rotate(0, 0, -rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)));
            angle -= rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (angle > 89 && angle < 91) {
                angle = 90;
                rotationPhase = 4;
                rotationAngleTime = 180;
            }
        }
        else if (rotationPhase == 3) {
            transform.Rotate(0, 0, rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)));
            angle += rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (angle > 89 && angle < 91) {
                angle = 90;
                rotationPhase = 4;
                rotationAngleTime = 180;
            }
        }

        //After you have rotated to horizontal in phase 1/2, rotate around to face the other direction.
        if (rotationPhase == 4) {
            transform.Rotate(rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2)), 0, 0);
            rotationAngle += rotationAngleTime * (Time.deltaTime * (rotationSpeed / 2));
            if (rotationAngle > 179) {
                rotationAngle = 0;
                rotationPhase = 0;
                rotationAngleTime = 0;
            }
        }
    }
\$\endgroup\$
2
  • 1
    \$\begingroup\$ If I were you I would look into Quaternions and rotational interpolation, they are very common mathematical topics that have many resources and will give your rotation a more natural and smooth feel. (You will see horrible jumps with 3D Euler rotation) \$\endgroup\$ Commented Mar 6, 2012 at 22:23
  • \$\begingroup\$ The animation in this fix is perfectly fine, no jumps. The only problem is I can't seem to accurately get it to draw over 2 seconds. I have a timer that runs for 2 seconds for the rotation animation, and the code I linked above should technically run over two seconds, but it runs slightly under two seconds (about 1.5 or 1.6) I don't see how you're supposed to do something over an accurate amount of time. \$\endgroup\$ Commented Mar 7, 2012 at 16:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .