Terrain Generator Problem: Index is less than 0 or more than or equal to the list count

I have made some 64x64 heightmap tiles in the hopes of making a Terrain Generator script ala Diablo or other RPGs. However, when using multiple nested FOR loops and IF statements, Unity throws up an index error after the first cycle (I know this by print debugging how much of the Array was completed). I’m new to programming and would love to know why I’m getting this index error. Probably the loop going too high… lines 67-68 are when it becomes a little suspect.

//this script randomly generates tile-based terrain for level 1
/*Please note:
1 = High Tile					2 = Low Tile
3 = Up Tile						4 = Down Tile
5 = Left Tile					6 = Right Tile

21 = Concave Top Left			22 = Concave Top Right
23 = Concave Bottom Left		24 = Concave Bottom Right

31 = Convex Top Left			32 = Convex Top Right
33 = Convex Bottom Left			34 = Convex Bottom Right
*/

//the terrain pieces
var terrainHigh : Transform;
var terrainLow : Transform;
var terrainUp : Transform;
var terrainDown : Transform;
var terrainLeft : Transform;
var terrainRight : Transform;
var terrainConcTL : Transform;
var terrainConcTR : Transform;
var terrainConcBL : Transform;
var terrainConcBR : Transform;
var terrainConvTL : Transform;
var terrainConvTR : Transform;
var terrainConvBL : Transform;
var terrainConvBR : Transform;

//if you change the dimension length and width of your heightmaps, change it here, too
var gridDimension = 64;

//change either of these values to change the dimensions of the levels maximum size
var gridRows = 10;
var gridCols = 10;

//the array where the terrain data is stored
var terrainArray = new Array(gridRows * gridCols);
	
/*TEMPORARY, no need to read: These show what pieces are allowed to be next to others, a simplified version is below to save on processing
var oneDown = [1,3,21,22]; var twoDown = [2,4,33,34]; var threeDown = [2,4,33,34]; var fourDown = [1,3,21,22]; var fiveDown = [5,23,31]; var sixDown = [6,24,32]; var twoOneDown = [5,23,31]; var twoTwoDown = [6,24,32]; var twoThreeDown = [1,3,21,22]; var twoFourDown = [1,3,21,22]; var threeOneDown = [2,4,33,34]; var threeTwoDown = [2,4,33,34]; var threeThreeDown = [5,23,31]; var threeFourDown = [6,24,32];
var oneAcross = [1,5,21,23]; var twoAcross = [2,6,32,34]; var threeAcross = [3,22,31]; var fourAcross = [4,24,33]; var fiveAcross = [2,6,32,34]; var sixAcross = [1,5,21,23]; var twoOneAcross = [3,22,31]; var twoTwoAcross = [1,5,21,23]; var twoThreeAcross = [4,24,33]; var twoFourAcross = [1,5,21,23]; var threeOneAcross = [2,6,32,34]; var threeTwoAcross = [3,22,31]; var threeThreeAcross = [2,6,32,34]; var threeFourAcross = [4,24,33];
*/
	
//these arrays store what tiles are allowed to be below a given tile
//1, 4, 23, 24 share a down Array
var oneDown = [1, 3, 21, 22];
//2, 3, 31, 32 share a down Array
var twoDown = [2, 4, 33, 34];
//5, 21, 33 share a down Array
var fiveDown = [5, 23, 31];
//6, 22, 34 share a down Array
var sixDown = [6, 24, 32];
	
//these arrays store what tiles are allowed to be across from a given tile
//1, 6, 22, 24 share a down Array
var oneAcross = [1, 5, 21, 23];
//2, 5, 31, 33 share a down Array
var twoAcross = [2, 6, 32, 34];
//3, 21, 32 share a down Array
var threeAcross = [3, 22, 31];
//4, 23, 34 share a down Array
var fourAcross = [4, 24, 33];


//this massive loop assigns a tile number for every tile in the terrainArray
for ( var row = 0 ; row < gridRows ; row++ )
{
	for ( var col = 0 ; col < gridCols ; col++ )
	{
		
		//this IF statement puts a HIGH tile if the current tile is on the border
		if ( row == 0 || col == 0 || row == gridRows || col == gridCols )
			{
			terrainArray[row * gridRows + col] = 1;
			}
				
		else print(terrainArray);
			
			//this IF statement puts a CONCAVE TOP LEFT in the top left
			if ( row == 1 && col == 1 )
				{
				terrainArray[row * gridRows + col] = 21;	
				}
				
			else print(terrainArray);
		
				//setting up two new array pieces, which will be combined into one later on
				var firstPart = [];
				var secondPart = [];
			
					//these IF statements check what tile is above the current
					if ( terrainArray[(row-1)* gridRows + col] == 1 || terrainArray[(row-1)* gridRows + col] == 4 || terrainArray[(row-1)* gridRows + col] == 23 || terrainArray[(row-1)* gridRows + col] == 24 )
					{firstPart = oneDown;}
					else if ( terrainArray[(row-1)* gridRows + col] == 2 || terrainArray[(row-1)* gridRows + col] == 3 || terrainArray[(row-1)* gridRows + col] == 31 || terrainArray[(row-1)* gridRows + col] == 32 )
					{firstPart = twoDown;}
					else if ( terrainArray[(row-1)* gridRows + col] == 5 || terrainArray[(row-1)* gridRows + col] == 21 || terrainArray[(row-1)* gridRows + col] == 33 )
					{firstPart = fiveDown;}
					else if ( terrainArray[(row-1)* gridRows + col] == 6 || terrainArray[(row-1)* gridRows + col] == 22 || terrainArray[(row-1)* gridRows + col] == 34 )
					{firstPart = sixDown;}
			
					//these IF statements check what tile is to the left of the current
					else if ( terrainArray[row * gridRows + (col - 1)] == 1 || terrainArray[(row-1)* gridRows + col] == 6 || terrainArray[(row-1)* gridRows + col] == 22 || terrainArray[(row-1)* gridRows + col] == 24 )
					{secondPart = oneAcross;}
					else if ( terrainArray[row * gridRows + (col - 1)] == 2 || terrainArray[(row-1)* gridRows + col] == 5 || terrainArray[(row-1)* gridRows + col] == 31 || terrainArray[(row-1)* gridRows + col] == 33 )
					{secondPart = twoAcross;}
					else if ( terrainArray[row * gridRows + (col - 1)] == 3 || terrainArray[(row-1)* gridRows + col] == 21 || terrainArray[(row-1)* gridRows + col] == 32 )
					{secondPart = threeAcross;}
					else if ( terrainArray[row * gridRows + (col - 1)] == 4 || terrainArray[(row-1)* gridRows + col] == 23 || terrainArray[(row-1)* gridRows + col] == 34 )
					{secondPart = fourAcross;}
		
						//converting the arrays into Javascript
						var convOne : Array = new Array(firstPart);
						var convTwo : Array = new Array(secondPart);
		
						//joins the two smaller arrays					
						var joinedArray = convOne.Concat(convTwo);
							
						//sorts the arrays numerically
						joinedArray.Sort();
							
						//setting up a finished array so we can put any double-ups inside, then converting it into Javascript
						var finishedArray = [];
						var finArr : Array = new Array(finishedArray);
							
						//a custom loop to push any duplicates into a new array
							for ( var i = 0; i < joinedArray.length; i++ )
								{	
								
								if ( joinedArray *== joinedArray[i+1] )*
  •  							{*
    

_ var num = joinedArray*;_
_
finArr.Push(num);_
_
}_
_
}*_

* //takes the finished array, and chooses a random number from it*
* var answer = finArr[Random.Range(0, finArr.length)];*

* //places the final random number into the current tile*
_ terrainArray[row * gridRows + col] = answer; _

* }*
}

//creating the terrain from array

for (var r = 0; r < gridRows; r++ )
*{ *
* for (var c = 0; c < gridCols; c++ )*
* { *

_ if ( terrainArray[r * gridRows + c] == 1 ) //Draw High Tile_
* {*
_ Instantiate (terrainHigh, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 2 ) //Draw Low Tile_

* {*
_ Instantiate (terrainLow, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 3 ) //Draw Up Tile_

* {*
_ Instantiate (terrainUp, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 4 ) //Draw Down Tile_

* {*
_ Instantiate (terrainDown, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 5 ) //Draw Left Tile_

* {*
_ Instantiate (terrainLeft, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 6 ) //Draw Right Tile_

* {*
_ Instantiate (terrainRight, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 21 ) //Draw Concave Top Left Tile_

* {*
_ Instantiate (terrainConcTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 22 ) //Draw Concave Top Right Tile_

* {*
_ Instantiate (terrainConcTR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 23 ) //Draw Concave Bottom Left Tile_

* {*
_ Instantiate (terrainConcBL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 24 ) //Draw Concave Bottom Right Tile_

* {*
_ Instantiate (terrainConcTR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 31 ) //Draw Convex Top Left Tile_

* {*
_ Instantiate (terrainConvTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 32 ) //Draw Convex Top Right Tile_

* {*
_ Instantiate (terrainConvTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 33 ) //Draw Convex Bottom Left Tile_

* {*
_ Instantiate (terrainConvTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
else if ( terrainArray[r * gridRows + c] == 34 ) //Draw Convex Bottom Right Tile_

* {*
_ Instantiate (terrainConvTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);_
* }*
* }*
}

Hi all, I fixed the problem… although not sure how, and here is the current result:

Not bad for my first foray into programming! Obviously there are problems with this:

  1. the edges aren’t contained yet
  2. the player can’t reach a destination
  3. some of the edges aren’t matched properly at the bottom

But for the most part, this is at least something to build off of, and I’ve coded it in a way that is flexible so that I can change the size of the grid at will.

For those interested, here is the current code in Javascript / Unityscript:

//this script randomly generates tile-based terrain for level 1
/*Please note:
1 = High Tile					2 = Low Tile
3 = Up Tile						4 = Down Tile
5 = Left Tile					6 = Right Tile

21 = Concave Top Left			22 = Concave Top Right
23 = Concave Bottom Left		24 = Concave Bottom Right

31 = Convex Top Left			32 = Convex Top Right
33 = Convex Bottom Left			34 = Convex Bottom Right
*/

//the terrain pieces
var terrainHigh : Transform;
var terrainLow : Transform;
var terrainUp : Transform;
var terrainDown : Transform;
var terrainLeft : Transform;
var terrainRight : Transform;
var terrainConcTL : Transform;
var terrainConcTR : Transform;
var terrainConcBL : Transform;
var terrainConcBR : Transform;
var terrainConvTL : Transform;
var terrainConvTR : Transform;
var terrainConvBL : Transform;
var terrainConvBR : Transform;

//if you change the dimension length and width of your heightmaps, change it here, too
var gridDimension = 64;

//change either of these values to change the dimensions of the levels maximum size
var gridRows = 10;
var gridCols = 10;

//the array where the terrain data is stored
var terrainArray = new Array(gridRows * gridCols);
	
/*TEMPORARY, no need to read: These show what pieces are allowed to be next to others, a simplified version is below to save on processing
var oneDown = [1,3,21,22]; var twoDown = [2,4,33,34]; var threeDown = [2,4,33,34]; var fourDown = [1,3,21,22]; var fiveDown = [5,23,31]; var sixDown = [6,24,32]; var twoOneDown = [5,23,31]; var twoTwoDown = [6,24,32]; var twoThreeDown = [1,3,21,22]; var twoFourDown = [1,3,21,22]; var threeOneDown = [2,4,33,34]; var threeTwoDown = [2,4,33,34]; var threeThreeDown = [5,23,31]; var threeFourDown = [6,24,32];
var oneAcross = [1,5,21,23]; var twoAcross = [2,6,32,34]; var threeAcross = [3,22,31]; var fourAcross = [4,24,33]; var fiveAcross = [2,6,32,34]; var sixAcross = [1,5,21,23]; var twoOneAcross = [3,22,31]; var twoTwoAcross = [1,5,21,23]; var twoThreeAcross = [4,24,33]; var twoFourAcross = [1,5,21,23]; var threeOneAcross = [2,6,32,34]; var threeTwoAcross = [3,22,31]; var threeThreeAcross = [2,6,32,34]; var threeFourAcross = [4,24,33];
*/
	
//these arrays store what tiles are allowed to be below a given tile
//1, 4, 23, 24 share a down Array
var oneDown = [1, 3, 21, 22];
//2, 3, 31, 32 share a down Array
var twoDown = [2, 4, 33, 34];
//5, 21, 33 share a down Array
var fiveDown = [5, 23, 31];
//6, 22, 34 share a down Array
var sixDown = [6, 24, 32];
	
//these arrays store what tiles are allowed to be across from a given tile
//1, 6, 22, 24 share an across Array
var oneAcross = [1, 5, 21, 23];
//2, 5, 31, 33 share an across Array
var twoAcross = [2, 6, 32, 34];
//3, 21, 32 share an across Array
var threeAcross = [3, 22, 31];
//4, 23, 34 share an across Array
var fourAcross = [4, 24, 33];

//this first loop makes every tile a high tile by default
for ( var t = 0 ; t < gridRows * gridCols ; t++ )
{
terrainArray[t] = 1;
}


//this massive loop assigns a tile number for every tile in the terrainArray
for ( var p = gridRows + 1 ; p < gridRows * gridCols ; p++ )
{
	
	//this IF statement puts a CONCAVE TOP LEFT in the first playable tile
	if ( p == gridRows + 1 )
		{
		terrainArray[p] = 21;	
		}
					


	if ( gridCols + 1 < p && p < ( gridRows - 1 ) * gridCols )
		{
				
			//setting up two new array pieces, which will be combined into one later on
			var firstPart = [];
			var secondPart = [];
												
			//these IF statements check what tile is above the current
			if ( terrainArray[ p - gridCols ] == 1 || terrainArray[ p - gridCols ] == 4 || terrainArray[ p - gridCols ] == 23 || terrainArray[ p - gridCols ] == 24 )
			{firstPart = oneDown;}
			if ( terrainArray[ p - gridCols ] == 2 || terrainArray[ p - gridCols ] == 3 || terrainArray[ p - gridCols ] == 31 || terrainArray[ p - gridCols ] == 32 )
			{firstPart = twoDown;}
			if ( terrainArray[ p - gridCols ] == 5 || terrainArray[ p - gridCols ] == 21 || terrainArray[ p - gridCols ] == 33 )
			{firstPart = fiveDown;}
			if ( terrainArray[ p - gridCols ] == 6 || terrainArray[ p - gridCols ] == 22 || terrainArray[ p - gridCols ] == 34 )
			{firstPart = sixDown;}
			
			//these IF statements check what tile is to the left of the current
			if ( terrainArray[ p - 1 ] == 1 || terrainArray[ p - 1 ] == 6 || terrainArray[ p - 1 ] == 22 || terrainArray[ p - 1 ] == 24 )
			{secondPart = oneAcross;}
			if ( terrainArray[ p - 1 ] == 2 || terrainArray[ p - 1 ] == 5 || terrainArray[ p - 1 ] == 31 || terrainArray[ p - 1 ] == 33 )
			{secondPart = twoAcross;}
			if ( terrainArray[ p - 1 ] == 3 || terrainArray[ p - 1 ] == 21 || terrainArray[ p - 1 ] == 32 )
			{secondPart = threeAcross;}
			if ( terrainArray[ p - 1 ] == 4 || terrainArray[ p - 1 ] == 23 || terrainArray[ p - 1 ] == 34 )
			{secondPart = fourAcross;}
		
			//converting the arrays into Javascript
			var convOne : Array = new Array(firstPart);
			var convTwo : Array = new Array(secondPart);
		
			//joins the two smaller arrays					
			var joinedArray = convOne.Concat(convTwo);
						
			//sorts the arrays numerically
			joinedArray.Sort();
						
			//setting up a finished array so we can put any double-ups inside, then converting it into Javascript
			var finishedArray = [];
			var finArr : Array = new Array(finishedArray);
							
				//a custom loop to push any duplicates into a new array
				for ( var i = 0; i < joinedArray.length - 1; i++ )
					{	
								
					if ( joinedArray *== joinedArray[i+1] )*
  •  				{*
    

_ var num = joinedArray*;_
_
finArr.Push(num);_
_
}_
_
}*_

* //takes the finished array, and chooses a random number from it*
* var answer = finArr[Random.Range(0, finArr.length)];*

* //places the final random number into the current tile*
* terrainArray[p] = answer; *
* } *
}

//creating the terrain from array

for (var r = 0; r < gridRows; r++ )
*{ *
* for (var c = 0; c < gridCols; c++ )*
* { *

_ if ( terrainArray[r * gridRows + c] == 1 ) //Draw High Tile_
* {*
_ Instantiate (terrainHigh, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 2 ) //Draw Low Tile_

* {*
_ Instantiate (terrainLow, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 3 ) //Draw Up Tile_

* {*
_ Instantiate (terrainUp, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 4 ) //Draw Down Tile_

* {*
_ Instantiate (terrainDown, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 5 ) //Draw Left Tile_

* {*
_ Instantiate (terrainLeft, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 6 ) //Draw Right Tile_

* {*
_ Instantiate (terrainRight, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 21 ) //Draw Concave Top Left Tile_

* {*
_ Instantiate (terrainConcTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 22 ) //Draw Concave Top Right Tile_

* {*
_ Instantiate (terrainConcTR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 23 ) //Draw Concave Bottom Left Tile_

* {*
_ Instantiate (terrainConcBL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 24 ) //Draw Concave Bottom Right Tile_

* {*
_ Instantiate (terrainConcBR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 31 ) //Draw Convex Top Left Tile_

* {*
_ Instantiate (terrainConvTL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 32 ) //Draw Convex Top Right Tile_

* {*
_ Instantiate (terrainConvTR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 33 ) //Draw Convex Bottom Left Tile_

* {*
_ Instantiate (terrainConvBL, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);
* }*
if ( terrainArray[r * gridRows + c] == 34 ) //Draw Convex Bottom Right Tile_

* {*
_ Instantiate (terrainConvBR, Vector3(r * gridDimension, 0, c * gridDimension), transform.rotation);_
* }*
* }*
}