- Home /
Endless while loop in coroutine which uses condition changing in Update() function.
I have been trying to make a series of Lerp move functions work one after the other for an intro to my simple racing game. (Camera starts in some place moves a bit then teleports to some other place moves a bit and so on). The way I have been tackling this problem is with the following code:
using UnityEngine;
using System.Collections;
public class PreviewCamera : MonoBehaviour {
public Transform[] cameraPos;
public bool finished = false;
public float fraction = 0;
public float speed = 0.2f;
//Fill the array with the caamera positions for the race preview
void Start () {
//Fill the array (indexes 0 and 1 will be useless)
cameraPos = transform.parent.GetComponentsInChildren<Transform>();
//Set first camera at position 2
transform.position = cameraPos[2].position;
transform.rotation = cameraPos[2].rotation;
StartCoroutine(RunPreviewCamera());
}
// Update is called once per frame
void Update () {
if (fraction <= 1)
{
fraction += Time.deltaTime * speed;
}
}
IEnumerator RunPreviewCamera()
{
StartCoroutine(MoveCamera(transform, cameraPos[3]));
yield return null;
}
//Function to teleport camera from one position to another
void TeleportCamera( Transform teleportPos)
{
transform.position = teleportPos.position;
transform.rotation = teleportPos.rotation;
}
//Function to move camera from current position to another
IEnumerator MoveCamera(Transform fromPos, Transform movePos)
{
fraction = 0;
while(fraction < 1)
{
transform.position = Vector3.Slerp(fromPos.position, movePos.position, fraction);
transform.rotation = Quaternion.Slerp(fromPos.rotation, movePos.rotation, fraction);
}
yield return null;
}
}
What I supposed would happen is that since the fraction variable changes in the Update() eventually it would escape from the loop in the coroutine MoveCamera but it doesn't and it crashes unity every time I run the game. I suppose update() is not being called if MoveCamera doesn't finish? Is my way of thinking wrong? Any way to do it via scripting and not just making 4 different cameras in my scene and calll them to make the moves I want one by one?
Answer by ScaniX · Aug 25, 2016 at 08:36 PM
You need to yield inside of the loop.
//Function to move camera from current position to another
IEnumerator MoveCamera(Transform fromPos, Transform movePos)
{
fraction = 0;
while(fraction < 1)
{
transform.position = Vector3.Slerp(fromPos.position, movePos.position, fraction);
transform.rotation = Quaternion.Slerp(fromPos.rotation, movePos.rotation, fraction);
yield return null;
}
}
Answer by DiegoSLTS · Aug 25, 2016 at 08:38 PM
Move the yield return null inside the while loop. The code inside a coroutine between the start and a yield or between 2 yields will run completelly before returning control to the rest of Unity methods. Your loop won't finish because the coroutine isn't letting the Update run, since fraction is less than one.
Anyway, that code is too complex for something really simple. I don't have much time right now, but later I'll tell you how to clean that A LOT.
I never wrote the simplified version I said I'd write. Here it is:
using UnityEngine;
using System.Collections;
public class PreviewCamera : $$anonymous$$onoBehaviour {
public Transform[] cameraPos;
public bool finished = false;
public float speed = 0.2f;
//Fill the array with the caamera positions for the race preview
void Start () {
//Fill the array (indexes 0 and 1 will be useless)
cameraPos = transform.parent.GetComponentsInChildren<Transform>();
//Set first camera at position 2
transform.position = cameraPos[2].position;
transform.rotation = cameraPos[2].rotation;
StartCoroutine($$anonymous$$oveCamera(transform, cameraPos[3]));
}
//Function to teleport camera from one position to another
void TeleportCamera( Transform teleportPos)
{
transform.position = teleportPos.position;
transform.rotation = teleportPos.rotation;
}
//Function to move camera from current position to another
IEnumerator $$anonymous$$oveCamera(Transform fromPos, Transform movePos)
{
float fraction = 0;
while(fraction < 1)
{
transform.position = Vector3.Slerp(fromPos.position, movePos.position, fraction);
transform.rotation = Quaternion.Slerp(fromPos.rotation, movePos.rotation, fraction);
fraction += Time.deltaTime * speed;
yield return null;
}
}
}
Starting a coroutine that starts a coroutine is useless unles you're waiting for it to end to do something else (with a yield return StartCoroutine). You can keep track of the time inside the coroutine itself ins$$anonymous$$d of Update. This also removes the need of having fraction as a class member. I said it would be "A LOT" cleaner but I was wrong, just simplified it a bit. Hope it helps somehow, anyway.
Your answer
Follow this Question
Related Questions
Assigning current color to a variable for fade out (C#) 0 Answers
How to make a var "global" 0 Answers
Custom Inspector - How to add functionality? 1 Answer
Accessing Variables Through Scripts 1 Answer
Adding and Removing to a Inbuild Array 2 Answers