- Home /
Coroutine not starting
So I'm new to coroutines and I'm really hoping I'm just missing something simple but I can't figure this problem out. I have an object I want to rotate but I don't want it to rotate instantaneously, I want it to rotate over a certain amount of time. In another post I found a bit of code that is supposed to accomplish what I'm looking for through a coroutine but it doesn't seem to be working. The object does not rotate at all. If I use the normal transform.rotate the object will rotate but does so instantly which is not what I want.
GameObject objectToRotate;
public float speed = 1f;
public Vector3 rotationAmount = new Vector3(0, 0, 180);
[SerializeField] private List<GameObject> platformsMoved;
private void Start()
{
objectToRotate = platformsMoved[0];
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Bullet"))
{
clickSource.PlayOneShot(switchClick);
StartCoroutine(MovePlatforms());
}
}
IEnumerator MovePlatforms()
{
float endTime = Time.time + speed;
float step = 1f/speed;
var fromAngle = objectToRotate.transform.eulerAngles;
var targetRotation = objectToRotate.transform.eulerAngles + rotationAmount;
float t = 0;
while(Time.time <= endTime)
{
t += step * Time.deltaTime;
objectToRotate.transform.eulerAngles = Vector3.Lerp(fromAngle, targetRotation, t);
yield return 0;
}
}
Answer by Bunny83 · Aug 04, 2021 at 05:22 AM
Well, first of all your coroutine is over complicated. While using eulerAngles is not recommended, this should generally work. Your coroutine could be just:
static IEnumerator RotatePlatform(Transform objectToRotate, Vector3 relativeRotation, float duration)
{
var fromAngle = objectToRotate.eulerAngles;
var toAngle = objectToRotate.eulerAngles + relativeRotation;
Debug.Log("Rotate platform from " + fromAngle + " to " + toAngle, objectToRotate);
for(float t = 0f; t < 1f; t += Time.deltaTime / duration)
{
objectToRotate.eulerAngles = Vector3.Lerp(fromAngle, toAngle, t);
yield return null;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Bullet"))
{
clickSource.PlayOneShot(switchClick);
StartCoroutine(RotatePlatform(objectToRotate.transform, rotationAmount, speed));
}
}
There are many things we don't know about your setup. Though keep in mind that StartCoroutine starts a coroutine on the monobehaviour here you run StartCoroutine on. So the coroutine is bound to that object. If that object is destroyed of deactivated your coroutine will be stopped / terminated.
Note that I added a Debug.Log statement for debugging to the coroutine. See if you can see this log in the console. If not, your trigger does not Fire at all.
Note I've refactored a few things. Your "speed" actually represents a "duration" which is pretty much the opposite of what a speed represents. A higher value means it takes longer. You should never yield the value "0". This will produce garbage as an integer value returned as object need to be boxed. When you want to wait for one frame, just yield null. I also renamed the coroutine since it doesn't move platforms but it rotates a single one ^^. Using class member fields to pass information to methods is bad design. By passing the object to rotate, the rotation amount and the duration as parameters the method is self-contained (so I made it static). This makes it way easier to reason about the code.
Finally keep in mind when this code is supposed to rotate a platform, this platform needs to have a kinematic rigidbody if it should interact with other rigidbodies.
ps: The debug log call has a second parameter which represents a context object. I passed the objectToRotate as context. When you click on the debug message in the console, Unity will ping / highlight that object in your project / hierarchy. Maybe you're trying to rotate the wrong object?
Thank you for the in depth explanation, it helped me understand it a little better. The debug.log is what helped me solve my issue. My previous code worked the same as yours, although yours is cleaner, but it turns out me declaring the Vector3 and initializing it outside of the start function was the issue. With the debug statement it was saying it was rotating to (0, 0, 0) which wasn't what the Vector3 was set too, as soon as I initialized it in the start function it worked properly.
Thank you again for your help, sometimes I forget that a simple debug statement is all I need to help solve my issue.
Note that your "rotationAmount" is declared as a public variable and therefore is serialized in the inspector. So it doesn't matter what you set the variable to in the field initializer. Of coruse overwriting the serialized value in Start would work, however if you set it from code it should not be serialized as this would be confusing. By overwriting it in Start the serialized value will become pointless instead.