- Home /
Building a multidimensional array for grid movement.
G'day guys.
Some time ago I built the first working prototype of my first 3D game project, a maze game with movement similar to Pacman. It works as desired, but I'd like to improve code efficiency. Currently, there are 4 movement functions (one for each direction, it's necessary for the system I've created), each moving the player exactly '1' unit in the desired direction.
Herein lies the problem: I have an IF statement for each of the 70+ 'positions', each setting which bearings (north, east, south and west) are true. Again, I'm using the direction booleans for other mechanisms such as AI, so I'd like to keep it.
Each 'position' has an IF statement like this:
if (transform.position.z == 0 && transform.position.x == 0){
north = true;
south = false;
east = true;
west = false;
junction = true;
}
I'd like to replace this with a multidimensional array, perhaps that holds one of the 8 possible combinations of available directions for each grid. I know it could also be possible to simply have the movement script detect if the next 'grid' is an available direction.
The only problem is I can't seem to get the array working. I've tried numerous times, but can't seem to get it functioning.
I'm trying to incorporate it into my movement script, an example of which is:
if (actualBearing == 'North' && north == true) {
moving = true;
startPosition = transform.position;
endPosition = transform.position + Vector3.forward * stepDistance * 1;
stepStartTime = Time.time;
pivot() ;
}
I apologise that I've posted on a similar topic before, but after trying many different approaches, I'm still unable to find a way to integrate an array system into my working code. Something along the lines of this would be good:
var grid = new int[
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
]
Coupled with an action in each of the four movement directions that 'moves' a grid counter to mirror the player's movement in the scene would be magnificent, but so far my attempts yield no tangible success.
Any advice would be greatly appreciated,
Cheers, - Stew
EDIT! : I have got an array version working, but encountering an error when I try to enable the available directions. My array looks like this:
private var grid = [ ['1','1','1','1','1','0','1','1','1','1'], ['1','0','0','0','1','1','1','0','0','1'], ['1','1','1','0','0','1','0','0','1','1'], ['1','0','1','1','1','1','1','1','1','0'], ['1','0','0','0','1','0','1','0','1','0'], ['1','1','1','1','1','0','1','1','1','1'], ['0','0','1','0','1','1','1','0','0','1'], ['1','1','1','1','1','0','1','1','0','1'], ['1','0','0','1','0','0','0','1','0','1'], ['1','1','1','1','1','1','1','1','1','1'] ];
private var rowIndex = 0; private var colIndex = 0;
This works for movement - I use code like (grid[rowIndex+1][colIndex]) == '1') to check the player can move. But I now need to - before that - make sure the directions are only available when the neighboring 'grid' is available ( == '1' ). I've been experimenting with the below code, but it keeps returning the error 'array index is out of range'.
function checkNorthSouth () {
if ((grid[rowIndex+1][colIndex]) == '1'){
north = true;
}
else if ((grid[rowIndex-1][colIndex]) == '1'){
south = true;
}
}
Anybody know why? (see below)
EDIT (FINAL) : I've got my script to where I need it to be. I changed the array to use INT instead of strings, and to resolve the issue of the index being 'out of range', I simply created a 'border tile' around the map - an extra two rows and two columns, each '0' value. It's a simple fix, but practical. I'll now be moving on to build an 'enemy' AI script.
I'd like to thank everybody who took the time to read, understand or even post on this question. Seeing how you guys work to resolve an issue led me to search for solutions of my own, and as a result I'm growing considerably more comfortable with Javascripting in Unity.
Cheers guys!
You should consider using an enum for your bearing. It will save you from checking each direction
Yes, and you should consider using FlagsAttribute and store each direction in precomputed array. This way you can just do a simple bit test to see if you can go that direction.
(Resurrected comment from deleted answer:) Here's the problem - in the play preview in Unity, it lags a bit. When I build and play, it's fine. - Well, for one, you're storing strings in the array and perfor$$anonymous$$g string tests. It's a bit redundant if you're storing numeric values anyhow. Change your code to use integers ins$$anonymous$$d and you should see some improvement. You can also try change your array from jagged to rectangular since a jagged array creates a level of indirection (Jagged arrays may have variable length sub-arrays).
Answer by Statement · Mar 13, 2011 at 02:35 PM
I decided to write an example of how you can make use of an edge array. The script doesn't do anything other than building the edges (for faster lookups runtime). I also changed the grid type from string array to int array since it only contained 0 or 1 anyways. To see if you can walk from one position to another, you can just call
if (Test(x, y, Edges.North))
{
// Ok, we can walk north from x, y.
}
Below is full source:
private var width = 10; private var height = 10;
private var grid = [ [1,1,1,1,1,0,1,1,1,1], [1,0,0,0,1,1,1,0,0,1], [1,1,1,0,0,1,0,0,1,1], [1,0,1,1,1,1,1,1,1,0], [1,0,0,0,1,0,1,0,1,0], [1,1,1,1,1,0,1,1,1,1], [0,0,1,0,1,1,1,0,0,1], [1,1,1,1,1,0,1,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1] ];
private var edges : Edges[,];
@System.Flags enum Edges { None = 0, East = 1, North = 2, West = 4, South = 8, // Edit: added Edges.All as shortcut for East|North|West|South All = 15 };
// Let's build the edges so we don't need to do a lot of checking. BuildEdges();
function BuildEdges() { edges = new Edges[width, height];
for (var y = 0; y < height; ++y)
{
for (var x = 0; x < width; ++x)
{
edges[x, y] = FindEdges(x, y);
}
}
}
function FindEdges(x : int, y : int) : Edges { var edge = Edges.None;
if (Grid(x, y - 1) == 1)
edge |= Edges.North;
if (Grid(x - 1, y) == 1)
edge |= Edges.West;
if (Grid(x + 1, y) == 1)
edge |= Edges.East;
if (Grid(x, y + 1) == 1)
edge |= Edges.South;
return edge;
}
function Grid(x : int, y : int) : int { if (x < 0 || x >= width) return 0; if (y < 0 || y >= height) return 0; return grid[x][y]; }
// Use Test as such: // if (Test(x, y, Edges.West)) // MoveWest();
function Test(x : int, y : int, direction : Edges) : boolean { if (x < 0 || x >= width) return false; if (y < 0 || y >= height) return false;
return (edges[x, y] & direction) == direction;
}
WOW!!!!! Impressive effort. Someday I'm going to take the time to read all of this. Another time I'm going to need find the time to absorb and understand what this does. For now, Just WOW!
Well dissidently, I can see if I can make you help understand it more. The grid (jagged) array represents the level in terms of movement. 1 means you can walk on a point, and 0 means you can't. You can get query this to check if a point is accessible or not with grid[x][y] == 1. Then, for performance reasons, I pre-calculate all the connections for all the grid points so you don't have to test neighbors realtime. That is, I amortize the runtime cost to a slightly heavier start up cost. I use the edges[,] rectangular array for this. (jagged or rectangular really doesn't matter much)
edges is similar to grid, but it describes the directions you can take from a point. I used an enum which stores each direction in a bit (thats why they are 1, 2, 4 ,8). This means I can store a value such as BOTH west and north in one value. I find out the cases by checking if the neighboring grid points are 1 and merge them together and finally store the combined value in the right location in edges. Then it's done. We've pre-calculated all possible directions for every point. When we want to check if we can go north from 4, 1, we can see if edges[4, 1] contains north by bitmasking it.
You can even check multiple directions at once, say, you want to be able to make a super attack only if you stand at a junction where all neighboring directions are walkable. Then you can try it with Test(x, y, Edges.East | Edges.North | Edges.West | Edges.South). It returns true only if the point has connections to all of those directions.
Also, to handle edge cases I chose to block walking outside of the map by returning 0 in the Grid function if the point is out of range. I do similar tests in Test function, although it might seem a bit odd since you're testing a point you can consider "being on". Also, thanks for the discussion, I see a slight index error in my code I'll fix right away.
Answer by Ashkan_gc · Mar 13, 2011 at 02:51 PM
so the remaining problem is about out of range exception. if rowIndex is 0 and you tell it to read rowIndex-1 then it would try to read rowIndex of -1 which not exist so you should check for 0 and arrayLength -1 before doing the if statement. array.GetLength is the method that you can get the length of a special dimention with it.
Actually, it's a jagged array so I doubt you will be able to use GetLength, unless you do arr.GetLength(0) and arr[y].GetLength(0), in which case you can do arr.Length and arr[y].Length just as well. Would it been a rectangular array it would worked like a charm! +1
Your answer
![](https://koobas.hobune.stream/wayback/20220613112548im_/https://answers.unity.com/themes/thub/images/avi.jpg)