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…
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)
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.
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.
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
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?