Coroutine help (452440)

Hi all

I am having a nightmare trying to get my head around coroutines.

As far as I can see from docs, there are two ways of calling a coroutine:

  1. StartCoRoutine(X) - this returns control to the caller at the first yield.
  2. yield return StartCoroutine(X) - this returns control to the caller only when the coroutine is done.

But - I have a chain of functions calling each other (from object to object) - I need to add a “yield return new WaitForSeconds(x)” to the last one. I need the chain to act in a synchronous manner (ie each should wait for the one below to finish before continuing). If I use method 2 above, then the caller becomes a coroutine itself, and then needs to be called using method 2, which turns ITS caller into a coroutine, etc…

Am I missing something here? Is there another way to call these methods? What happens if I just call “X()” when X has a yield statement in it?

Thanks,
Rich

Not sure if this will help you at all but this is a way of handling One coroutine after another. The generic of this I found at unifycommunity.

This is a part of some code to make Doors Open and Close when activated.

       void Start()
	{
	    StartCoroutine("CoStart");
	}
       IEnumerator CoStart()
	{
	    while (true)
	        yield return StartCoroutine("CoUpdate");
	}
	
	IEnumerator CoUpdate()
	{
		if(!doorLocked)
	    	       yield return StartCoroutine("changeStates");
		else
			eventTriggered = false;
		//Display to the user the door is locked
	}
	
	IEnumerator changeStates()
	{
		if(eventTriggered)
		{
			if(currentState == DoorState.open)
			{
				currentState = DoorState.closed;
			}
			else
				currentState = DoorState.open;
		
			switch(currentState)
			{
				case DoorState.closed :
					animation.CrossFade("Close");
					yield return new WaitForSeconds(animation.GetClip("Close").length);
					break;
				case DoorState.open	:
					animation.CrossFade("Open");
					yield return new WaitForSeconds(animation.GetClip("Open").length);
					break;
			}
		}
		eventTriggered = false;
		yield return null;

This is exactly what I am afraid my code will end up looking like… I cannot turn every function in my chain (and hence every function that ever calls any of them) into Coroutines. For a start, some of them are in objects that do not inherit from MonoBehaviour. (so no StartCoroutine at all).

Please someone say there’s a way to avoid this?

I think you can just call the functions from one object as per normal.
Class A
when something finish calls Class B Some Function()

Class B Some Function() runs then end calls Class A Another Function

Class A Another Function() Yield wait.

Thanks for the reply! That’s pretty much what I ended up doing, Object 1 passed itself to Object 2 as a parameter, and Object 2 could then do everything needed, with yields where necessary, then called a “Finalise” method on the Object 1 when it was done.

It seems to work, just testing the timing of it all now…

Thanks again!

Hi,

It sounds like you got it but just to give another way of thinking about. I recently had two situations where I used a single co-routine as a sort of event manager. It didn’t chain anything, so there was no yield return co-routine, but I could fire off regular functions called something like…
On…Start()
On…SomeStateAUpdate()
On…SomeStateBUpdate()
On…SomeStateAFinished()
On…SomeStateBFinished()
On…Finished()

So my co-routine just distpached these “events”. This was in a base class, so I had this private and I had all the events in there as empty functions but as protected virtual so derrived classes could tap in to events as needed.

By the way, does anyone know a more elegant pattern for situations where a base class needs to have a function implemented but only children will actually use the function? Is an empty function body good enough?

A simple method is to create a extension class from a base class, and even extend the extended one. The easiest and best way I have seen is to create a simple MonoBehaviour base class then extend it as you need.

Vehicle
–SpaceShip
----PlayerSpaceShip
----AISpaceShip

This is a rather simple example.

The vehicle would have basic stats:
mass
maxSpeed
currentSpeed
turningRadius
Move()

Here you would put the basic move function that operates basic vehicles. Say it just wants a vector which is where it is going to move. This vector controls the look rotation as well as the rigidbody.velocity.

On the space ship you put a more advanced move, which takes into account no gravity and 3d movement. It still uses all the same variables that the vehicle does, it just reads them differently.

The player and AI ships now get the Update() function. Each update they take information from the scene or player controls and feed it into the space ship sub class.

How does this work for Coroutines. Exactly the same. Everything is a Monobehaviour so you can use coroutines. Since the PlayerSpaceship is derived from the Spaceship and vehicle classes, then all of the coroutines in those classes (as long as they are public) are accessible from the player. So if you made a Coroutine to “ping” for nearby enemies in the vehicle class, you could call it and use it from the AISpaceship. The only drawback is that the Vehicle class cannot see any variables that are in the AISpaceship, unless they are present in the Vehicle class.

Another incredibly useful part of this is that you can use a common GetComponent() and still get the PlayerSpaceship. :wink: just like it was a vehicle. Again a drawback here is that you cannot access any variables that are not defined in the Vehicle class.