Hi, I’m working on 2d ship game and I’m trying to get my ship to rotate and then move after having finished rotating.
In order to make the rotation happen over time I’m using a while loop inside a coroutine and I’m also using another coroutine to make the ship move but I don’t want the ship to start moving before its finished rotating.
Here is my code:
void Update () {
//stuff
StartCoroutine(RotateToTarget());
//isRotatingToTarget = false; pointless since the coroutine wouldn't have finished rotating
//StartCoroutine (MoveToTarget()); If I add this here it doesn't wait for the rotation to finish
}
IEnumerator RotateToTarget(){
while(transform.rotation != rotationToTarget)
{
transform.rotation = Quaternion.Lerp(transform.rotation, rotationToTarget , Time.deltaTime);
this.isRotatingToTarget = (transform.rotation != rotationToTarget);
yield return null;
}
isRotatingToTarget = false;
print ("Can move to target");
StartCoroutine (MoveToTarget()); //this never gets excecuted
}
IEnumerator MoveToTarget(){
if (!isMovingToTarget && !isRotatingToTarget){
while(transform.position.x != target.x && transform.position.y != target.y)
{
isMovingToTarget = true;
transform.position = Vector2.MoveTowards(transform.position, target, Time.deltaTime*movementSpeed);
yield return null;
}
this.isMovingToTarget = false;
}
Also, due to floating point imprecision, it is not recommended to compare floats using the equal operator. So, to check whether 2 positions are same, it would be better to compare the distance between them.
The code in your question starts the RotateToTarget coroutine on every Update(). This stacks up Coroutine calls. So if your movement script would take 5 seconds to complete and your app is running at 60 fps, you have 300 coroutine running that may be accelerating the process or fighting with each other, or simply taking resources. Coroutines work well when you want independent piece of work to run without interference. If the target will be moving so this code as to reacquire it, then consider using Update() as @Pyrian suggests.
As for not completing the rotation, the issue is this line:
The way this form of Lerp works is to walk the approximately the same fraction of the remaining distance to the goal each frame. Since the distance is shrinking, the same fraction represents smaller and smaller rotations. The result is an eased movement. But the problem is that it takes a very long time to complete…and only completes due to floating point imprecision and perhaps some slop built into rotation comparison. It like the old adage, “how many days will it take to reach my goal if I walk half the distance each day.” The answer is infinite…you never reach your goal. A solution is the one @YWord suggests…to use an angle threshold.
Chaining coroutines or using flags will work for what you want here, but there is an alternate. You can use ‘yield’ with coroutines. Here a demonstration rewrite of your code. It may not be a perfect fit since I don’t have all your code, nor the context where it will be used.
Although starting the second coroutine in the first coroutine should work (I think), you can use a ‘flag’. Note this will only work if “Can move to target” prints successfully. If it doesn’t, see the paragraph at the end of this solution.
Then, set the boolean to true on the last line of RotateToTarget() and set it false on the first line of MoveToTarget().
That all said, you may want to check your vector maths. Due to the nature of Lerp, unless it receives a ‘1’ as the final parameter, you’re always going to be moving closer to the target, never equal to it. I recommend you set transform.Rotation equal to rotationToTarget once the difference between the two is small enough.