The intent of this script is to move the object it is attached to to a specific location using Lerp. Then once it reaches that location, to then switch directions and move to another location using Lerp. It will repeat this movement until the object is destroyed (in another script).
using UnityEngine;
using System.Collections;
public class BossMovement : MonoBehaviour
{
private Vector3 startMarker, endMarker, leftMarker, rightMarker;
private float startTime, journeyLength, distCovered, fracJourney;
private bool endIntro, movingLeft, movingRight;
public float speed = 1.0F;
private void Awake()
{
this.transform.position = new Vector3(0.0f, 12.0f, 0.0f);
startMarker = this.transform.position;
endMarker = new Vector3(0.0f, 8.0f, 0.0f);
leftMarker = new Vector3(-4.5f, 8.0f, 0.0f);
rightMarker = new Vector3(4.5f, 8.0f, 0.0f);
endIntro = true;
}
void Start()
{
//Intro Movement
startTime = Time.time;
journeyLength = Vector3.Distance(startMarker, endMarker);
}
void FixedUpdate()
{
if (this.transform.position != endMarker && endIntro) { StartCoroutine(Moving(endMarker)); }
//Moving Left after Intro
if (this.transform.position == endMarker && endIntro)
{
endIntro = false;
movingLeft = true;
this.transform.position = new Vector3(0.0f, 8.0f, 0.0f);
startMarker = this.transform.position;
startTime = Time.time;
journeyLength = Vector3.Distance(startMarker, leftMarker);
StartCoroutine(Moving(leftMarker));
Debug.Log("made it");
}
//Moving right after reaching left
if (this.transform.position == leftMarker && movingLeft)
{
movingLeft = false;
movingRight = true;
this.transform.position = leftMarker;
startMarker = this.transform.position;
startTime = Time.time;
journeyLength = Vector3.Distance(startMarker, rightMarker);
StartCoroutine(Moving(rightMarker));
}
//Moving left after reaching right
if (this.transform.position == rightMarker && movingRight)
{
movingLeft = true;
movingRight = false;
this.transform.position = rightMarker;
startMarker = this.transform.position;
startTime = Time.time;
journeyLength = Vector3.Distance(startMarker, leftMarker);
StartCoroutine(Moving(leftMarker));
}
}
IEnumerator Moving(Vector3 goalMarker)
{
distCovered = (Time.time - startTime) * speed;
fracJourney = distCovered / journeyLength;
this.transform.position = Vector3.Lerp(startMarker, goalMarker, fracJourney);
yield return null;
}
}
The problem I am running into is that the StartCoroutine() calls in the if statements are being ignored. I know that the if statements are being entered by using various Debug.log() statements around the script.
Why are the StartCoroutine() statements ignored? What is the nature of Coroutines in Unity?
Thanks,
Brodi
They’re not ignored. Your coroutine is just one frame long. You need to loop.
1 Like
I am so confused about Coroutines.
I know that the Update() functions are called once per frame. Which means that any other function that is called during Update needs to be able to complete it’s task in one from or less. Coroutines would be necessary to complete task over a period of time (like moving an object). Yet, I though coroutines were seperate entities that run parallel to the Update functions.
Am I way off base here? I though Coroutines were a natural loop that would continue until it’s done.
You’re correct, in principle. Coroutines maintain their internal state and execute outside of Update, but they’re still just functions that run from top to bottom.
IEnumerator OneShotCoroutine()
{
int value = 5;
value += 1;
Debug.Log(value); // will output once
yield return null;
}
IEnumerator LoopCoroutine()
{
int value = 5;
do
{
value += 1;
Debug.Log(value); // will output multiple times
yield return null;
} while(value <= 10)
}
1 Like
Oh ok I see what you’re saying.
So in my code, using Lerp, the coroutine would keep track of all the values it needed to complete the movement. But it would only complete what it can in 1 frame, yield, then restart from where it left off on the last frame. However, if I don’t call it again, it will maintain that yield until it is called again.
Ok that makes sense.
Thanks dude!
Maybe your wording is a bit wonky there but if you call it again, all that will do is a start a new coroutine with a new set of values and both will execute until they conclude. You only want to call StartCoroutine when you intend to start a new coroutine, not to update an old one or something.
…Ok now I’m confused again. I guess my wording was wonky.
Let’s say I put my coroutine in the Update function. On frame 1, the coroutine will be called. On frame 2, will that be a continuation of the coroutine called in frame 1 or a separate coroutine?
How then do I complete the first coroutine from frame 1?
What do you mean by “put my coroutine in the Update function”? Every time you call StartCoroutine() you begin a new coroutine. Once it’s started, it runs until it concludes or you call StopCoroutine() or StopAllCoroutines(). You cannot force an already active coroutine to update (without a bunch of non-sense).
public class CoroutineTutorial : MonoBehaviour
{
private static int safeguard = 0;
private void Start()
{
StartCoroutine(One());
StartCoroutine(Two());
}
private void Update()
{
StartCoroutine(Three());
}
private IEnumerator One()
{
Debug.Log("Coroutine: One");
yield return null;
}
private IEnumerator Two()
{
while(true)
{
Debug.Log("Coroutine: Two");
yield return null;
}
}
private IEnumerator Three()
{
while(true)
{
Debug.Log("Coroutine: Three");
safeguard++;
if(safeguard >= 1000)
{
StopAllCoroutines();
}
yield return null;
}
}
}
Watch how quickly Three begins to pile up.
1 Like
Think of your yield statement as putting a bookmark in the method and coming back to it later to continue executing it. It will come back to the exact place and exact state it was in before it left. That means that if you yield inside of a loop, it will return to inside the loop and continue where it left off. If you yield in iteration 5, it will return in iteration 5 and continue onto iteration 6. Don’t think of Coroutine methods as a weird, special structure. Treat them like normal methods that can take breaks.
Also, you don’t have to update coroutines yourself. Unity takes care of that for you.
2 Likes
OOOOOOOOOOOOOOOOOOOOOK Now I think I got it!!!
GroZZler, when you mentioned that I needed a loop, you weren’t saying that I need to put the Coroutine in a loop, you meant I needed a loop in my coroutine.
Madgvox, that’s a great explanation. I never thought of it that way.
Ok, ok, ok, I think I’ve got a handle on it now.
Thank you both for explaining what should have been a simple concept to me. 
2 Likes