c# - Array Index is out of range
Hello! I'm brand new to c# scripting, so I've been practicing in the roguelike tutorial that unity offers on the learn page. I finished the tutorial, and figured it would be good practice to keep making my own changes to the game, so I'm trying to work through and add more features. The biggest one I'm trying to add now is a new item - an Axe, which allows you to attack enemies, and only spawns once per level.
while I'm pretty sure I've got all of the attacking and moving code set up correctly, I'm getting this "array index out of range" error AFTER I play the game, and try to move once, then the game seems to get stuck in a loop, as I can't move past that.
error is reported on line 148.
IndexOutOfRangeException: Array index is out of range. BoardManager.LayoutObjectAtRandom (UnityEngine.GameObject[] tileArray, Int32 minimum, Int32 maximum) (at Assets/Scripts/BoardManager.cs:148) BoardManager.SetupScene (Int32 level) (at Assets/Scripts/BoardManager.cs:169) GameManager.InitGame () (at Assets/Scripts/GameManager.cs:91) GameManager.Awake () (at Assets/Scripts/GameManager.cs:51) UnityEngine.Object:Instantiate(GameObject) Loader:Awake() (at Assets/Scripts/Loader.cs:17)
any help would be greatly appreciated!
using UnityEngine;
using System;
using System.Collections.Generic; //Allows us to use Lists.
using Random = UnityEngine.Random; //Tells Random to use the Unity Engine random number generator.
public class BoardManager : MonoBehaviour
{
// Using Serializable allows us to embed a class with sub properties in the inspector.
[Serializable]
public class Count
{
public int minimum; //Minimum value for our Count class.
public int maximum; //Maximum value for our Count class.
//Assignment constructor.
public Count (int min, int max)
{
minimum = min;
maximum = max;
}
}
public static int columns = 8; //Number of columns in our game board.
public static int rows = 8; //Number of rows in our game board.
public Count wallCount = new Count (5, 9); //Lower and upper limit for our random number of walls per level.
public Count foodCount = new Count (1, 3); //Lower and upper limit for our random number of food items per level.
public Count sodaCount = new Count (1, 2); //Lower and upper limit for out random number of soda items per level.
public Count axeCount = new Count (1,1); //Only one axe will spawn per level, so upper and lower are the same.
public GameObject exit; //Prefab to spawn for exit.
public GameObject[] floorTiles; //Array of floor prefabs.
public GameObject[] wallTiles; //Array of wall prefabs.
public GameObject[] foodTiles; //food prefab.
public GameObject[] sodaTiles; //soda prefab.
public GameObject[] axeTiles; //axe prefab.
public GameObject[] enemyTiles; //Array of enemy prefabs.
public GameObject[] outerWallTiles; //Array of outer tile prefabs.
private Transform boardHolder; //A variable to store a reference to the transform of our Board object.
private List <Vector3> gridPositions = new List <Vector3> (); //A list of possible locations to place tiles.
private int twoCounter;
//This is called each time a scene is loaded.
void OnLevelWasLoaded(int index)
{
//Add one to the columns and rows board size in BoardManager
columns++;
rows++;
twoCounter++;
if (twoCounter >= 10)
{
twoCounter = 0;
foodCount.minimum++;
foodCount.maximum++;
}
wallCount.minimum = (columns * rows) / 5;
wallCount.maximum = (columns * rows) / 3;
}
//Clears our list gridPositions and prepares it to generate a new board.
void InitialiseList ()
{
//Clear our list gridPositions.
gridPositions.Clear ();
//Loop through x axis (columns).
for(int x = 1; x < columns-1; x++)
{
//Within each column, loop through y axis (rows).
for(int y = 1; y < rows-1; y++)
{
//At each index add a new Vector3 to our list with the x and y coordinates of that position.
gridPositions.Add (new Vector3(x, y, 0f));
}
}
}
//Sets up the outer walls and floor (background) of the game board.
void BoardSetup ()
{
//Instantiate Board and set boardHolder to its transform.
boardHolder = new GameObject ("Board").transform;
//Loop along x axis, starting from -1 (to fill corner) with floor or outerwall edge tiles.
for(int x = -1; x < columns + 1; x++)
{
//Loop along y axis, starting from -1 to place floor or outerwall tiles.
for(int y = -1; y < rows + 1; y++)
{
//Choose a random tile from our array of floor tile prefabs and prepare to instantiate it.
GameObject toInstantiate = floorTiles[Random.Range (0,floorTiles.Length)];
//Check if we current position is at board edge, if so choose a random outer wall prefab from our array of outer wall tiles.
if(x == -1 || x == columns || y == -1 || y == rows)
toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];
//Instantiate the GameObject instance using the prefab chosen for toInstantiate at the Vector3 corresponding to current grid position in loop, cast it to GameObject.
GameObject instance =
Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
//Set the parent of our newly instantiated object instance to boardHolder, this is just organizational to avoid cluttering hierarchy.
instance.transform.SetParent (boardHolder);
}
}
}
//RandomPosition returns a random position from our list gridPositions.
Vector3 RandomPosition ()
{
//Declare an integer randomIndex, set it's value to a random number between 0 and the count of items in our List gridPositions.
int randomIndex = Random.Range (0, gridPositions.Count);
//Declare a variable of type Vector3 called randomPosition, set it's value to the entry at randomIndex from our List gridPositions.
Vector3 randomPosition = gridPositions[randomIndex];
//Remove the entry at randomIndex from the list so that it can't be re-used.
gridPositions.RemoveAt (randomIndex);
//Return the randomly selected Vector3 position.
return randomPosition;
}
//LayoutObjectAtRandom accepts an array of game objects to choose from along with a minimum and maximum range for the number of objects to create.
void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
{
//Choose a random number of objects to instantiate within the minimum and maximum limits
int objectCount = Random.Range (minimum, maximum+1);
//Instantiate objects until the randomly chosen limit objectCount is reached
for(int i = 0; i < objectCount; i++)
{
//Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
Vector3 randomPosition = RandomPosition();
//Choose a random tile from tileArray and assign it to tileChoice
GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];
//Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}
//SetupScene initializes our level and calls the previous functions to lay out the game board
public void SetupScene (int level)
{
//Creates the outer walls and floor.
BoardSetup ();
//Reset our list of gridpositions.
InitialiseList ();
//Instantiate a random number of wall tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);
//Instantiate a random number of food tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
//Instantiate a random number of soda tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom (sodaTiles, sodaCount.minimum, sodaCount.maximum);
//Instantiate a random number of soda tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom (axeTiles, axeCount.minimum, axeCount.maximum);
int enemyCount = 0;
if (level <= 5)
{
//Determine number of enemies based on current level number, based on a logarithmic progression
enemyCount = (int)Mathf.Log(level, 2f);
}
else if (level >5)
{
enemyCount = ((int)Mathf.Log(level, 2f)) + (level / 10);
}
//Instantiate a random number of enemies based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);
//Instantiate the exit tile in the upper right hand corner of our game board
Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
}
}
Answer by TBruce · Apr 06, 2016 at 05:47 PM
@saintshenanigans Have you verified that foodTiles is not null and the Length is greater than 0? Have you verified that foodCount.maximum
Place a debug statement before
LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);
Try making these changes to LayoutObjectAtRandom():
void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
{
if ((tileArray != null) && (tileArray.Length > 0))
{
// make sure that minimum is less than tileArray.Length
if (minimum > (tileArray.Length - 1))
{
minimum = (tileArray.Length - 1);
}
// make sure that maximum is not greater than tileArray.Length
if (maximum > tileArray.Length)
{
maximum = tileArray.Length;
}
if (minimum == maximum)
{
//Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
Vector3 randomPosition = RandomPosition();
//Choose a random tile from tileArray and assign it to tileChoice
GameObject tileChoice = tileArray[minimum];
//Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
else
{
// make sure that minimum is less than maximum
if (minimum > maximum)
{
var temp = maximum;
maximum = maximum;
maximum = temp;
}
//Choose a random number of objects to instantiate within the minimum and maximum limits
int objectCount = Random.Range (minimum, maximum);
//Instantiate objects until the randomly chosen limit objectCount is reached
for(int i = 0; i < objectCount; i++)
{
//Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
Vector3 randomPosition = RandomPosition();
//Choose a random tile from tileArray and assign it to tileChoice
GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];
//Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}
}
}
Thanks a bunch for the reply!
I actually forgot to change the range of the array in the inspector to 1 and add the prefab to it.. I fixed that, and the array error is gone, however, now the item isn't spawning at all, when it should be set to spawn on every level. I was having trouble with my sprite editor, and wasn't able to edit the existing page because I needed more room, so I just created another with the spites I made, and cut them up in the sprite editor.
I've also noticed that when I test my new animation from the new spritesheet, it plays the animation from the old sheet.
Do you know anything about this?
EDIT:
looks like it's spawning, but it's 1/3 the size that it should be... I'm going to mess around with it, I probably messed it up in creation.
It sounds like your prefab is using old information (spritesheet, animation...). I would try creating a new prefab with the new spritesheet and new animation. I hope this works.
Your answer
Follow this Question
Related Questions
C# Unity dot syntax exercise correct solution? 1 Answer
item not adding to list correctly! 1 Answer
How to Destroy game object horizontally and vertically , when hit by a Raycast 0 Answers
Script isn't working. Easy solutions to adding dialogue? Help ASAP - project due in a few days 1 Answer
Audio Source does not contain definition for any of the Play functions... 2 Answers