Why does my code dividing a 2D array into chunks fail?

I have a 2D-Array representing my world. I want to divide this huge thing into smaller chunks to make collision detection easier.

I have a Chunk class that consists only of another 2D Array with a specific width and height and I want to iterate through the world, create new Chunks and add them to a list (or maybe a Map with Coordinates as the key; we'll see about that).

world = new World(8192, 1024);

Integer[][] chunkArray;

for(int a = 0; a < map.getHeight() / Chunk.chunkHeight; a++)
{
for(int b = 0; b < map.getWidth() / Chunk.chunkWidth; b++)
{
Chunk chunk = new Chunk();
chunkArray = new Integer[Chunk.chunkWidth][Chunk.chunkHeight];

for(int x = Chunk.chunkHeight*a; x < Chunk.chunkHeight*(a+1); x++)
{
for(int y = Chunk.chunkWidth*b; y < Chunk.chunkWidth*(b+1); y++)
{
// Yes, the tileMap actually is [height][width] I'll have
// to fix that somewhere down the line -.-
chunkArray[y][x] = map.getTileMap()[x*a][y*b];
// TODO:Attach to chunk
}
}

}
}

System.out.println(chunkList.size());


The two outer loops get a new chunk in a specific row and column. I do that by dividing the overall size of the map by the chunkSize.

The inner loops then fill a new chunkArray and attach it to the chunk. But somehow my maths is broken here.

Let's assume the chunkHeight = chunkWidth = 64.

For the first Array I want to start at [0][0] and go until [63][63]. For the next I want to start at [64][64] and go until [127][127] and so on. But I get an out of bounds exception and can't figure out why.

Any help appreciated!

Actually I think I know where the problem lies:

chunkArray[y][x] can't work, because y goes from 0-63 just in the first iteration. Afterwards it goes from 64-127, so sure it is out of bounds.

Still no nice solution though :/

EDIT:

if(y < Chunk.chunkWidth && x < Chunk.chunkHeight)
chunkArray[y][x] = map.getTileMap()[y][x];


This works for the first iteration... now I need to get the commonly accepted formula.

• Is Chunk.chunkWidth a const int size? If so what value have you given it? Commented Aug 19, 2014 at 13:53
• Both, width and height are public static final Integer = 64; Sorry, I thought that was clear from my description (non-native speaker, sorry!) Commented Aug 19, 2014 at 13:55
• You mentioned "Lets assume the chunkHeight" but if they are static finals then they cannot change, so assumption is not necessary. Commented Aug 19, 2014 at 13:57
• Ya, you're right. I cannot change them at runtime, but I can change them before compiling. But what I meant was the basic maths :) Commented Aug 19, 2014 at 14:01
• This question has an XY problem. I think we could edit it to ask "How do I do X" (with your solution as an answer) instead of "What is the bug in my implementation of X". That would yield a more generally useful question and be a lot clearer to read. Do you think that would work?
– Anko
Commented Aug 19, 2014 at 14:23

Note that even though your chunkArray instances are all supposed to cover different areas of your world, their indices still all range from 0 to Chunk.chunkWidth and 0 to Chunk.chunkHeight respectively.

Therefore, you should make sure that whenever you access chunkArray the x- and y- indices do not go out of these ranges. The easiest way to make sure they won't is to actually change the two inner-most for-loops like so:

int offsetX = b * Chunk.chunkWidth;
int offsetY = a * Chunk.chunkHeight;
Integer[][] tileMap = map.getTileMap();

for(int y = 0; y < Chunk.chunkHeight; y++)
{
for(int x = 0; x < Chunk.chunkWidth; x++)
{
chunkArray[x][y] = tileMap[offsetX + x][offsetY + y];
}
}


A faster way to achieve the same thing would be to use the built-in System.arraycopy:

int offsetX = b * Chunk.chunkWidth;
int offsetY = a * Chunk.chunkHeight;
Integer[][] tileMap = map.getTileMap();

for(int x = 0; x < Chunk.chunkWidth; x++)
{
System.arraycopy(tileMap[offsetX + x], offsetY, chunkArray[x], 0, Chunk.chunkHeight);
}


Here is my two cents:

All the work can be found on here too so you can run it and see how it works http://ideone.com/xKWAip

Separate it into pieces and you can see how it'll work with a wee access expression after flattening the initial map array.

Here is what I used to generate your map (at the moment it's square only but as long as your width and length are divisible by your chunk size you're fine):

public static int[][] GenMap(int mapSize)
{
int[][] arrayStuff = new int[mapSize][mapSize];
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
arrayStuff[x][y] = y + (mapSize * x);
}
}
return arrayStuff;
}


Here we Generate the chunks by flattening the map array and then using a chunk map coordinate of (i, j) and a chunk coordinate of (x, y) to then look through x and y within i and j.

Once that is looped through you can use the expression: y + (x * mapLength) + (chunkSize * i) + (chunkSize * mapLength * j) to find the index of the flattened array, providing the values you need in a [0, 1, 2, 3], [16, 17, 18, 19], [32, 33, 34, 35], [48, 49, 50, 51] format for your chunk info.

public static List<int[][]> GenChunks(int[][] map, int mapLength, int chunkSize)
{
int[] inputArray = new int[map.length * map[0].length];
for(int a = 0; a < map.length; a++)
{
for(int b = 0; b < map[0].length; b++)
{
inputArray[(a * map.length) + b] = map[a][b];
}
}

List<int[][]> chunksList = new ArrayList<int[][]>();

for (int i = 0; i < mapLength / chunkSize; i++)
{
for (int j = 0; j < mapLength / chunkSize; j++)
{
int[][] newChunk = new int[chunkSize][];

for (int x = 0; x < chunkSize; x++)
{
newChunk[x] = new int[chunkSize];

for (int y = 0; y < chunkSize; y++)
{
int offset = j * chunkSize * mapLength;
newChunk[y][x] = inputArray[y + (x * mapLength) + (chunkSize * i) + (chunkSize * mapLength * j)];
}
}

}
}

return chunksList;
}


Example usage:

public static void main (String[] args) throws java.lang.Exception
{
int mapSize = 8;
int chunkSize = 2;

int[][] mapArray = GenMap(mapSize);

System.out.println("Start chunks");

List<int[][]> chunks;
chunks = GenChunks(mapArray, mapSize , chunkSize);
}