I decided to take a look at coroutines today because I noticed that my Update callback was getting busy already, and coroutines seemed like a better way to do things. Here’s the problem I tried to solve and how I solved it.
I have a player character which always needs to be facing an object. The object it faces may move at any time, but it may not always be moving. When the player character notices that it is not facing the correct direction, it starts an animation and begins turning toward the object. When it is facing the object again, it stops turning and goes back to waiting until the object has moved again.
This is pretty easy to solve in update. You just check whether you’re turning or not. If you are, you check if you need to stop, and if you’re not, you check if you need to start.
But there’s no need for that conditional check. I know whether I’m turning or not. So I thought it would be better to move to coroutines, where I can only check whichever one I need to check. Here’s my solution:
// Use this for initialization
protected void Start()
{
SetupCoroutines();
}
void SetupCoroutines()
{
StartCoroutine(Update_NotTurning());
}
IEnumerator Update_Turning()
{
while (turnState == TurnState.turning)
{
transform.rotation = Quaternion.Slerp(transform.rotation, targetOrientation, turnSpeed * Time.deltaTime);
float dProd = Mathf.Abs(Quaternion.Dot(transform.rotation, targetOrientation));
if (dProd >= 0.99)
{
FinishTurning();
}
yield return 0;
}
}
IEnumerator Update_NotTurning()
{
while (turnState == TurnState.notturning)
{
float dProd = Mathf.Abs(Quaternion.Dot(transform.rotation, targetOrientation));
if (dProd < 0.99)
{
BeginTurning();
}
yield return 0;
}
}
void BeginTurning()
{
turnState = TurnState.turning;
BeginTurnAnimation();
StartCoroutine(Update_Turning());
}
void FinishTurning()
{
turnState = TurnState.notturning;
BeginIdleAnimation();
StartCoroutine(Update_NotTurning());
}
So a few questions:
- Is this a good use for coroutines?
- Am I doing everything right here? No leaks, no running both coroutines at once, or not cleaning up after myself?
It seems to work fine, but I just wanted to make sure that I’ve understood it all, so that I can safely do similar things elsewhere instead of a variety of state machines.