coroutines : trouble editing and accessing the same public variable

Hi,

Before I go into detail, let me pose what I THINK my question is:

Is it correct to access and edit public generic lists with multiple running instances of a single coRoutine? My script seems to update said variables, but when reading from them they act like they aren’t updated all the way, or at all.

I’m trying to use a generic list as an active dynamic list of objects that should be EXCLUDED from a functions operation.

So in rough psuedo code:

coRoutine (){

for (gameObject in bigList){

 if(gameObject is not in excludeList){

  DoStuff();

 }

}

Since I’m not using UPDATE at ALL, I start a few of these coroutines in the START function, and then they call themselves at the end to continue the simulation.

I’m wondering if they aren’t updating because these functions aren’t being run from Update?

Can anyone shed any light on this list or why its not working correctly? Or a better way to go about this?

I thought maybe assigning a simple script with a public variable to each gameObject that can move that has a boolean, that signifies if it is “excluded” or not. Maybe that would update with coRoutines?

Any help much appreciated!

This is my first question, so let me know if I can be more clear in any way :slight_smile:

}

EDIT:

Apologies for the lack of initial info!
The code is long, hopefully the below snippet is enough to give you an idea of what I’m trying to do.

Several cubes, or gameObjects are sliding around in a 2d plane (similar to those 2d sliding puzzle games). Part of what I want is to have multiple empty spaces and multiple cubes moving around to empty spots independently of each other, but when I have more than 1 empty spot, and there for more than 1 cube moving at a time they tend to conflict and move to the same spot and overlap.

The below code in conjunction with some if statements in other functions were meant to check if an empty spot was already chosen( a member of “empties_CheckedOut”) as an available empty spot and to exclude it from the list of possible empty spots to choose from.

Declaring the initial empty list of empty spots:

private var empties_CheckedOut = new List.<Vector3>();

Regular Function used for “Checking out” an empty spot:

//--------------Function used for "checking OUT" an empty spot. means it cant be used again until it is checked back in.-----------------//
function CheckOutEmpty(item : Vector3) : ArrayList	{
	var trueFalsePass : boolean;
	var genericReturnList = new ArrayList();
	trueFalsePass = false;
	if(empties_CheckedOut.IndexOf(item) == -1){
		empties_CheckedOut.Add(item);
		trueFalsePass = true;
		//print("Checked OUT empty: " + item);
	}
	genericReturnList.Add(trueFalsePass);
	genericReturnList.Add(item);
	return genericReturnList;
}

Regular Function used for “Checking in” an empty spot:

//--------------Function used for "checking IN" an empty spot. means it can be checked out and used at any time after this.-----------------//
function CheckInEmpty(item : Vector3) : ArrayList	{
	var trueFalsePass : boolean;
	var genericReturnList = new ArrayList();
	trueFalsePass = false;
	if(empties_CheckedOut.IndexOf(item) != -1){
		empties_CheckedOut.Remove(item);
		trueFalsePass = true;
		//print("Checked IN empty: " + item);
	}
	genericReturnList.Add(trueFalsePass);
	return genericReturnList;
}

Once a start and end position is computed, this coRoutine does the actual moving of the game object:

function SmoothMove (objToMove : Transform, startpos : Vector3, endpos : Vector3, seconds : float) { // smooth move, pass obj, new pos, and seconds for move.
	var t = 0.0; // set time counter to 0
	var randToAdd : float;
	randToAdd = Random.Range(cubeSpeedRandomAmt*-1,cubeSpeedRandomAmt);
	seconds += randToAdd;
	var tmpTransform : Transform = objToMove;  // grab the transform argument to variable.
	while (t <= 1.0) { // loop for Lerping from old, to new location. yields to update viewport.
		t += Time.deltaTime/seconds; // use deltatime to regulate speed across devices.
		tmpTransform.localPosition = Vector3.Lerp(startpos, endpos, Mathf.SmoothStep(0.0, 1.0, t)); // uses smoothStep to easeIn/Out
		yield;
	}
	var checkinMoverResult = CheckInMover(objToMove);
	var checkinEmptyResult = CheckInEmpty(endpos);
	var checkoutEmptyResult = CheckOutEmpty(startpos);
	yield WaitForSeconds(cubePause);
	DoIt();
}

This is kind of a wrapper function, this gets called from smoothMove at the end to keep the sliding process going once started in “Start”:

function DoIt(){
	CodeProfiler.Begin("doit:Update");
	
	var pickEmptyResult = PickEmptySpot(cubeChildrenInitPositionsFull);
	//print(pickEmptyResult.Count);
	//print("Chosen empty spot: " + pickEmptyResult[0]);
	
	var pickMoverResult = PickMoverCube(pickEmptyResult[0]);
	//print("Chosen mover cube: " + pickMoverResult);
	
	if(pickMoverResult == GameObject.Find("breakObject").transform){
		//print("doing nothin");
	}
	else{
		SmoothMove(pickMoverResult, pickMoverResult.localPosition, pickEmptyResult[0], cubeSpeed);
	}
	
	CodeProfiler.End("doit:Update");
}

I use the start function here to kick off however many empty spot / cube movers as desired. The idea is that once started, the coroutines feed themselves the necessary info to keep going.

function Start () {

	while(droppedCubesSpawnCounter > 0){
		DoIt();
		droppedCubesSpawnCounter -= 1;
		yield WaitForSeconds(cubePause);
	}

}

For simulation, you probably want to look into putting your logic into Update() or FixedUpdate() functions and using Time.deltaTime or Time.fixedDeltaTime for computing incremental updates to your objects.

Co-routines could probably work, but what’s the reason why you’re trying to use coroutines?

Some code would also help identify the problem you’re having with coroutines, pseudo code would not help if you’re having a specific issue and not seeing your coroutine fire.

Lists are .Net/Mono stuff, and have nothing to do with Update. A possible cause is the coroutine being started before its previous instance has finished: this lets two or more coroutines running in parallel, and changes made by a coroutine instance may be undone by another instance. Replacing Update with a coroutine usually is done this way:

function Start(): IEnumerator {
  while (true){
    // do stuff here
    yield; // wait for next frame
  }
}

Notice that only one coroutine instance is created (the Start function itself), and runs forever in an endless loop. This eliminates any possibility of multiple coroutines running at the same time, and also allocates memory only once. If you start a coroutine every frame, however, you’ll get lots of coroutines running in parallel (and lots of blocks allocated in the heap). Anyway, post your Start function to show what exactly you’re doing.

This may be a simple oversight in the pseudo code provided, but you do have a loop in your coroutine… right? Because otherwise you’ll just run through the list once and then the coroutine will “finish” and not be called again…

coRoutine (){
    while(true) { // <- this
        for (gameObject in bigList){
            if(gameObject is not in excludeList){
                DoStuff();
            }
        }
        yield return whatever; // and this
    }
}

Problem fixed!

Thanks for all the suggestions and help. Through a different route I came up with several days break from this I managed to troubleshoot the problem down to my own logic.

There were no problems updating variables, I just was checking in / checking out things incorrectly causing overlap.