0
\$\begingroup\$

Let's say I have a RotatableObject class, which inherits from MonoBehaviour. Here is its Start() method:

private void Start() {
    this.startingLocalRotation = this.transform.localRotation;
    this.finalLocalRotation = Quaternion.Euler(this.startingLocalRotation.eulerAngles.x, -150f, this.startingLocalRotation.eulerAngles.z);

    // Initialize other private fields
}

It has a method called Rotate(), defined as follows:

private void Rotate() {
    this.transform.localRotation = Quaternion.Lerp(this.startingLocalRotation, this.finalLocalRotation, 0.2f);
}

Given the following Update() method, the object rotates as expected:

private void Update() {
    this.Rotate();
}

However, if I make the following changes to Update(), then the object does not actually rotate, even though the Rotate() method is hit:

private void Update() {
    if (this.SomeCondition) {
        this.Rotate();
    }
}

this.SomeCondition always has the value true over multiple frames.

What is my mistake, and how can I fix it?

EDIT:

In response to this comment:

When you say "the object rotates as expected" do you mean that the object rotates from starting angles until final angles and then stops rotating (without the if) ?

Yes.

could you provide some more details about what SomeCondition is?

this.SomeCondition is determined by the state of another object, say, Puppy. E.g. if puppyInstance.Mood == Mood.Happy, then this.SomeCondition is true.

Did you try replacing the condition with the word true

No, I have not tried that. However, when stepping through the call stack in debug mode, I can see that this.SomeCondition is true and Rotate() is called -- I managed to step into the Rotate() method itself.

EDIT:

I tried the first approach described in this answer. However, it did not produce the effects that I was aiming for.

I set a breakpoint here:

transform.localRotation = Quaternion.Lerp(
   startingLocalRotation, 
   finalLocalRotation, 
   _rotationProgress
);

Every single time the breakpoint was hit in the Update() call, I could see that the value of _rotationProgress was steadily increasing. However, the value of transform.localRotation never actually changed -- it was always (-0.7, 0.7, 0.0, 0.0).

If I updated transform.localRotation outside of an if clause, however, that game object rotates as expected -- transform.localRotation gets updated as _rotationProgress gets updated.

EDIT:

Never mind, I am an idiot. The problem lies elsewhere in the code. The suggested approach works and I have accepted it as the answer.

\$\endgroup\$
6
  • \$\begingroup\$ When you say "the object rotates as expected" do you mean that the object rotates from starting angles until final angles and then stops rotating (without the if) ? Also could you provide some more details about what SomeCondition is? Did you try replacing the condition with the word true, did you put a Debug.Log before the Rotate to make sure the if is running properly? \$\endgroup\$ Commented Apr 18, 2018 at 15:48
  • \$\begingroup\$ @TomTsagk Thank you for your comment. I have updated my question with answers to your questions. \$\endgroup\$
    – user112729
    Commented Apr 18, 2018 at 15:56
  • \$\begingroup\$ I have tested your code exactly, line by line, without the if, and as I expected, your object does not rotate from start to final angles, instead it keeps the rotation based on the Lerp with t=0.2f. I assume this means you tried to simplify your code and failed, so you might want to edit that. \$\endgroup\$ Commented Apr 18, 2018 at 16:01
  • \$\begingroup\$ Thank you for your comment. Do you mind explaining what you mean by "instead it keeps the rotation based on the Lerp with t=0.2f"? Additionally, the object actually does rotate when I run the code supplied in this post... I don't know why we are seeing different results. :-( \$\endgroup\$
    – user112729
    Commented Apr 18, 2018 at 16:05
  • \$\begingroup\$ Inside function Rotate you set the localRotation to be a Lerp between the beginning and end of your angles, but for the last argument you give a constant of 0.2f which means it should return the exact same rotation everytime it runs, which becomes the rotation of your object. If your object is rotating, it means that you are running different code, or that object's parent is rotating, and as a result this one is rotating too. \$\endgroup\$ Commented Apr 18, 2018 at 16:08

2 Answers 2

0
\$\begingroup\$

You need to accumulate some progress between your start and your end. For instance...

[Tooltip("How long the rotation should take to complete, in seconds")]
public float rotationDuration = 2f;
float _rotationProgress = 0f;

private void Rotate() {
    // Accumulate rotation progress.
    _rotationProgress = Mathf.Clamp01(_rotationProgress + Time.deltaTime/rotationDuration);

    // Blend to the appropriate fraction of the way between start & final
    transform.localRotation = Quaternion.Lerp(
       startingLocalRotation, 
       finalLocalRotation, 
       _rotationProgress
    );
}

Or you can use the current localRotation itself as your progress measure, using an exponential ease-out style of Lerp:

[Range(0f, 1f)]
public float smoothness = 0.9f;

private void Rotate() {
    // Correct the exponential blend speed for the current framerate.
    float blend = 1f - Mathf.Pow(smoothness, Time.deltaTime * 30f);

    // Blend a small incremental step from where we are now to where we're going.
    transform.localRotation = Quaternion.Lerp(
       transform.localRotation, 
       finalLocalRotation, 
       blend
    );
}

Or using the RotateTowards method:

[Tooltip("Speed to rotate, in degrees per second")]
public float rotationSpeed = 180f;

private void Rotate() {
    // Rotate at a fixed speed toward the destination.
    transform.localRotation = Quaternion.RotateTowards(
       transform.localRotation, 
       finalLocalRotation, 
       rotationSpeed * Time.deltaTime
    );
}
\$\endgroup\$
4
  • \$\begingroup\$ Thank you for your reply! I will test this out tomorrow. I will accept your answer once I verify that it works. :-) \$\endgroup\$
    – user112729
    Commented Apr 18, 2018 at 17:53
  • \$\begingroup\$ Hi, I tried the first approach that you described, and while I can see that _rotationProgress steadily increases, nonetheless the game object itself isn't actually rotating. When I set a breakpoint at the re-assignment of transform.localRotation, the value of _rotationProgress gets larger every time I hit the breakpoint, but transform.localRotation itself keeps staying the same. \$\endgroup\$
    – user112729
    Commented Apr 20, 2018 at 7:14
  • \$\begingroup\$ I have updated my question to include this information. \$\endgroup\$
    – user112729
    Commented Apr 20, 2018 at 7:34
  • \$\begingroup\$ Never mind, I am an idiot. The problem lies elsewhere in the code. The suggested approach works and I have accepted your answer. \$\endgroup\$
    – user112729
    Commented Apr 20, 2018 at 7:46
-1
\$\begingroup\$

Try multiplying the last value in the Lerp function by Time.deltaTime. I’m not by my computer to check my old scripts where I used the Lerp function, but I think I remember doing something with Time.deltaTime

\$\endgroup\$
1
  • \$\begingroup\$ This will not have the desired effect on its own, but will instead cause the object to vibrate between different fractions of the way between start & end depending on how long each frame happens to be. It won't on its own introduce memory so it can make forward progress toward the goal. \$\endgroup\$
    – DMGregory
    Commented Apr 18, 2018 at 17:00

You must log in to answer this question.