- Home /
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[i] == joinedArray[i+1] )
{
var num = joinedArray[i];
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);
}
}
}
Answer by JVILL · Jan 23, 2013 at 06:57 AM
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[i] == joinedArray[i+1] )
{
var num = joinedArray[i];
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);
}
}
}
Your answer
Follow this Question
Related Questions
Dealing with placing large amounts of objects via script? 1 Answer
shoot script is not working 1 Answer
not working- GameObject.GetComponent(MeshFilter).mesh; 1 Answer
Use raycast to see if something else than terrain is under 1 Answer
How would I make an instantiated object appear at exact level of my terrain 1 Answer