[C#] Working code broke after Unity update

Hello all!

After updating Unity to version 4.3 (and MOnoDevelop to 4), this code - which was working fine - suddenly started returning “Array index out of range” in the line mentioned below. The weirdest part is that conditions manager for “characters”, which’s the same code, works fine, but not “enemies”.

And again: it was working fine before the update!

public class BattleLogic : MonoBehaviour {

	public List<CharacterStats> characters = new List<CharacterStats>();
	public List<EnemyDatabase> enemies = new List<EnemyDatabase>();	

	IEnumerator PrePhaseProcessing (){

		//CONDITIONS MANAGER FOR ALLIES
		for (int i = 0; i < characters.Count; i++){
			if (characters[i].conditionsCounter[6] > 0){
				if (characters[i].conditionsCounter[6] == 1)
					//do something
				characters[i].conditionsCounter[6]--;
			}
		}
		
		//CONDITIONS MANAGER FOR ENEMIES
		for (int i = 0; i < enemies.Count; i++){
			if (enemies[i].conditionsCounter[6] > 0){ //ARRAY OUT OF RANGE HERE!
				if (enemies[i].conditionsCounter[6] == 1)
					//do something
				enemies[i].conditionsCounter[6]--;
			}
		}
		
		yield return null;
		
	}
}

public class EnemyDatabase : MonoBehaviour {
		
	public int[] conditionsCounter = new int[15];

}


public class CharacterStats : MonoBehaviour {	
	
	public int[] conditionsCounter = new int[15];

}

I wanted to rollback to the previous version (which’s way better IMO), but I believe it may break my code even more…

So, any ideas?

It’s always a good idea to test code that you post - tested this code (with the tiny addiditon of StartCoroutine in Start in battlelogic), and it works fine with no errors
So the problem is something else, either some code not posted, or the scene is set up wrong (since you said its fine for characters but not enemies, are there any enemies assigned in the public list of enemies in battlelogic, and do those enemies have a conditioncounter created in the inspector)

Indeed, the size of conditionsCounter in inspector was 0, I haven’t noticed that. Then I tried doing this…

public class EnemyDatabase : MonoBehaviour {

	public int[] conditionsCounter;
	
	void Start (){

		conditionsCounter = new int[15];

	}
}

It worked!

Seriously, I’m pretty sure it’s some kind of bug with the new version, it makes no sense…

Actually, it didn’t work, conditionsCounter now has 15 elements, but “enemies*.conditionsCounter.Length” is 0 right before the broken line.*

bump

No one? :frowning:

It seems to me that it would be possible for your arrays to be serialized by the editor reset to 0 if you’ve changed it in the inspector before.

Try putting the line that initializes the array in the Start method of the monobehaviour, or mark the field as Non-serialized, see http://docs.unity3d.com/412/Documentation/ScriptReference/NonSerialized.html

Edit: Just saw in your previous post you tried the start method.

Is it possible that the Script execution order needs to be updated? For instance, is the code that throws the error being executed in a Start function of another script that takes place before the Start function that creates the arrays?

It should not be the case. Here’s the order if you want to double check:

	IEnumerator Start () {			
			
		Instatiations(); //instatiates the objects, hence running the Start function of "enemies"
		
		while (battle){
			yield return StartCoroutine (PrePhaseProcessing()); //here is the faulty code
			yield return StartCoroutine (PreparationPhase());
			yield return StartCoroutine (ActionSelectPhase());
			yield return StartCoroutine (BattlePhase());
		}
	}

As you can see, Instatiations takes place before the conditions check.
Also, “characters” condition manager takes place before “enemies” and it works fine.

There must be something in the inspector that is setup wrong, because the code you posted works fine.

Are you sure it’s code related? Seems weird for code to just break in this fashion, but inspector values changing on an update isn’t so out of scope.

Here’s the inspector, everything looks fine: http://tinypic.com/r/n30zki/5

As I said, I think it’s a bug because it was working fine before updating Unity to 4.3.

No - it’s almost definitely your code. Debug conditionCounter.Count before you execute your loop to make sure.

Already did, it says 0 even with inspector showing 15.

Then it’s 0 at the time that code is executed - plain and simple. Why don’t you set the size to 15 in the Inspector instead of via code? Sounds like the problem lies in your execution order.

It can’t be, the objects are instantiated before that, hence their Starts run before too. Plus, the code above it (which’s the same works fine). Here’s the entire code until the array error (which was in place and untouched for almost a month):

public class BattleLogic : MonoBehaviour {
	
	public List<CharacterStats> characters = new List<CharacterStats>();
	public List<EnemyDatabase> enemies = new List<EnemyDatabase>();	
	private float position = -4; //used for instatiation
	private int counter; //used for instantiation and party character action control
	private bool battle = true;


	IEnumerator Start () {			
			
		generalStats = (GeneralStats)FindObjectOfType(typeof(GeneralStats));
		specialDatabase = (SpecialDatabase)FindObjectOfType(typeof(SpecialDatabase));
		itemDatabase = (ItemDatabase)FindObjectOfType(typeof(ItemDatabase));		
		
		Instatiations();		
		
		while (battle){
			yield return StartCoroutine (PrePhaseProcessing());			
			yield return StartCoroutine (PreparationPhase());
			yield return StartCoroutine (ActionSelectPhase());
			yield return StartCoroutine (BattlePhase());
		}
		selectingParty = false;
		selectingAction = false;
	}
	
	void Instatiations (){
		
		foreach (GameObject character in generalStats.CharactersInParty){
		 	characters.Add (((GameObject)Instantiate(character, new Vector3 (5f, 0.38f, position), Quaternion.identity)).GetComponent<CharacterStats>());
			position -= 2.5f;			
			if (counter == 3)
				break;
			counter++;
		}
		
		position = -4f;
		foreach (GameObject enemy in generalStats.EnemyList){
			enemies.Add (((GameObject)Instantiate(enemy, new Vector3 (-5f, 0.38f, position), Quaternion.identity)).GetComponent<EnemyDatabase>());
			position -= 2.5f;			
		}
		counter = 0;
	}
	
	IEnumerator PrePhaseProcessing (){

		//CONDITIONS MANAGER
		for (int i = 0; i < characters.Count; i++){
			if (characters[i].conditionsCounter[6] > 0){
				if (characters[i].conditionsCounter[6] == 1)
					specialDatabase.Haste (characters[i], false);
				characters[i].conditionsCounter[6]--;
			}
		}
		
		for (int i = 0; i < enemies.Count; i++){
			Debug.Log (enemies[i].conditionsCounter.Length);
			if (enemies[i].conditionsCounter[6] > 0){
				if (enemies[i].conditionsCounter[6] == 1)
					specialDatabase.Haste (enemies[i], false);
				enemies[i].conditionsCounter[6]--;
			}
		}
		//CONDITIONS MANAGER
		
		yield return null;
		
	}
}

public class GeneralStats : MonoBehaviour {
	
	public List<GameObject> CharactersInParty = new List<GameObject>();
	//this list is filled manually in inspector

}

//CharacterStats is attached to hero prefabs
public class CharacterStats : MonoBehaviour {	
	
	public int[] conditionsCounter;
	
	void Start () {		

		conditionsCounter = new int[15];
	}
}

//EnemyDatabase is attached to enemy prefabs
public class EnemyDatabase : MonoBehaviour {
		
	public int[] conditionsCounter;
	
	void Start () {

		conditionsCounter = new int[15];
	}
}

Feel free to try it yourself, and if it succeeds I will try reinstalling Unity.

Clearly it can be, because it is. :slight_smile:

Again - why don’t you just set the size of the array in the Inspector?

I’d also re-think your coroutine loop. There’s no reason for PrePhaseProcessing to be a coroutine and it’s not even clear what that method is doing. Since your Start method is already a coroutine why don’t you just call those 4 methods and then yield return null at the end?

Lastly, what is conditionCounter and what are you trying to achieve? Why are you attempting to access index 6 directly?

I’m not getting, why do you ask me to set he size in inspector if it already shows the correct size?

I just tried PrePhaseProcessing as void and the problem persists. They are coroutine because the execution has to be ordered and I need a few WaitForSeconds.

ConditionCounter is manages the characters conditions such as Poison, Haste, etc. Each element is a different condition (and there are 16 of them), and each needs to do a different thing each turn. I made them an array just to save space. Don’t try to diverge the focus of the problem :smile:

The problem is your code - I was offering suggestions to make your code better.

Clearly there is an issue where you are attempting to access something before it has been fully initialized. If you set the size in the Inspector then you can omit your initialization code in Start and perhaps alleviate the issue. I suggested this because you never gave a good reason (or any reason for that matter) as to why you were initializing it in code.

I’m also still not clear how an array of integers translate to conditions. If each index is a different condition than what does the value contained at that index mean? It seems like a very convoluted implementation.

The value means how many turns there are left for the (de)debuff to run out, each turn it reduces one, and 0 means you’re clean.

Yes, you’re right, I added a WaitForSeconds(1) and the code worked, but I still don’t believe it should be failing at all. Why it’s not initialized if the instatiation is done before? Also, why it wasn’t failing before Unity update? Any chances of this being a bug?

Yes it is a bug and you find it right in your code. You have to initialize your stuff before you use it.

Ok genius, how do you explain it working on the previous Unity version?