2D Sorting map tiles into map chunks

Started by
1 comment, last by BlueSin 10 years, 3 months ago

So I am having a ridiculous problem I cannot seem to wrap my head around. I have been working at it for days, and I know the solution is simple I just cannot see it, so I need an outside opinion. I am working on procedural map generator. When I generate the map, the first thing I am doing is initializing map chunks. These chunks will contain several tiles each and will be used to only draw the chunks that are currently on the screen. All other chunks will not be drawn.

So I begin by creating chunks:


// Creates map chunks
        private static Map CreateChunks(Map map)
        {
            // Initialize map chunk rows
            map.Chunks = new MapChunk[map.GetMapWidth / MAP_CHUNK_WIDTH][];

            // Traverse chunk rows
            for (int chunkX = 0; chunkX < map.Chunks.Length; chunkX++)
            {
                // Initialize chunk column
                map.Chunks[chunkX] = new MapChunk[map.GetMapHeight / MAP_CHUNK_HEIGHT];

                // Traverse chunk columns
                for (int chunkY = 0; chunkY < map.Chunks[chunkX].Length; chunkY++)
                {
                    // Initialize chunk
                    map.Chunks[chunkX][chunkY] = new MapChunk(MAP_CHUNK_WIDTH, MAP_CHUNK_HEIGHT);
                }
            }

            // Return map
            return map;
        }

Then I create tiles within those chunks:


// Create map tiles
        private static Map CreateTiles(Map map)
        {
            // The current X position of the map
            float mapX = 0;
            // The current Y position of the map
            float mapY = 0;

            // Traverse chunk rows
            for (int chunkX = 0; chunkX < map.Chunks.Length; chunkX++)
            {
                // Traverse chunk columns
                for (int chunkY = 0; chunkY < map.Chunks[chunkX].Length; chunkY++)
                {
                    // Initialize tile rows
                    map.Chunks[chunkX][chunkY].Tiles = new MapTile[MAP_CHUNK_WIDTH][];

                    // Traverse chunk rows
                    for (int tileX = 0; tileX < map.Chunks[chunkX][chunkY].Tiles.Length; tileX++)
                    {
                        // Initialize tile columns
                        map.Chunks[chunkX][chunkY].Tiles[tileX] = new MapTile[MAP_CHUNK_HEIGHT];

                        // Traverse tile columns
                        for (int tileY = 0; tileY < map.Chunks[chunkX][chunkY].Tiles[tileX].Length; tileY++)
                        {
                            // initialize this tile
                            map.Chunks[chunkX][chunkY].Tiles[tileX][tileY] = new MapTile(
                                0, null, new Rectangle(
                                    (int)mapX * map.GetTileWidth, 
                                    (int)mapY * map.GetTileHeight, 
                                    map.GetTileWidth, map.GetTileHeight
                                    ), 
                                Noise.GetNoise(mapX * 0.1f, mapY * 0.1f, map.GetSeed));

                            // Increase mapY
                            mapY++;
                        }

                        // Increase mapX
                        mapX++;
                        // Reset map Y
                        mapY = 0f;
                    }
                }
            }

            

            // Return map
            return map;
        }

So, in theory Chunk[0][0].Tile[0][0] should be positioned at Vector (0,0). Which it is. And in theory the second tile in the row Chunk[0][0].Tile[1][0] should be positioned at Vector (24, 0) (tiles are 24 x 24). Which it is. The first tile in the second row Chunk[0][0].Tile[0][1] should be at Vector (0, 24). Which it is. All of that works fine.

The problem comes when we move on to the next chunk. Chunk [1][0] is to the right of Chunk[0][0]. Chunk [0][1] should be below Chunk[0][0]. However the vector of Chunk[1][0].Tile[0][0] is (18432, 0). Chunk[0][1].Tile[0][0] has a Vector (0, 2304). Which means they are reversed, in theory Chunk[1][0] should be Vector (2328, 0) (I need to increase mapX/mapY between chunk changes. But given the way it stands now Chunk[0][1] is where Chunk[1][0] should be. Chunk[1][0] current vector is just messed up. I know I need to play around with the increase of mapX/mapY and reset of mapX/mapY to change it. But I have tried every imaginable combination and it just isn't working. Any help?

Advertisement

Personally, I avoid 2d arrays as I find them confusing. I'm building a game currently that has a similar design with tiles and zones, and I used 1-dimensional arrays as they make more sense to me.

Try doing something like this in your chunk and tile creator:


int offset;
for (int chunkX = 0; chunkX < map.Chunks.Length; chunkX++)
{
    // Traverse chunk columns
    for (int chunkY = 0; chunkY < map.Chunks[chunkX].Length; chunkY++)
    {
        offset = (chunkY * MAP_CHUNK_WIDTH) + chunkX;
        map.Chunks[offset] = new MapChunk(MAP_CHUNK_WIDTH, MAP_CHUNK_HEIGHT);
    }
}


On a related note, I find it's not good to use functions as part of the loop condition in a for statement, eg: map.Chunks.Length. If there's a chance that could change, the code will re-evaluate that value every loop. If you know its fixed, you can assign it to a variable outside the loop first.

[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

Thanks so much for your tips Postie, I really appreciate it! Before checking this though I actually was able to get it resolved by modifying the Create Tiles code to this:


// Create map tiles
        private static Map CreateTiles(Map map)
        {
            // The current X position of the map
            float mapX = 0;
            // The current Y position of the map
            float mapY = 0;

            // Traverse chunk rows
            for (int chunkX = 0; chunkX < map.Chunks.Length; chunkX++)
            {
                // Traverse chunk columns
                for (int chunkY = 0; chunkY < map.Chunks[chunkX].Length; chunkY++)
                {
                    // Initialize tile rows
                    map.Chunks[chunkX][chunkY].Tiles = new MapTile[MAP_CHUNK_WIDTH][];

                    // Traverse tile rows
                    for (int tileX = 0; tileX < map.Chunks[chunkX][chunkY].Tiles.Length; tileX++)
                    {
                        // Initialize tile columns
                        map.Chunks[chunkX][chunkY].Tiles[tileX] = new MapTile[MAP_CHUNK_HEIGHT];

                        // Traverse tile columns
                        for (int tileY = 0; tileY < map.Chunks[chunkX][chunkY].Tiles[tileX].Length; tileY++)
                        {
                            int chunkStartX = (int)chunkX * (map.GetTileWidth * MAP_CHUNK_WIDTH);
                            int chunkStartY = (int)chunkY * (map.GetTileHeight * MAP_CHUNK_HEIGHT);

                            // initialize this tile
                            map.Chunks[chunkX][chunkY].Tiles[tileX][tileY] = new MapTile(
                                0, null, new Rectangle(
                                    (int)(chunkStartX + (mapX * map.GetTileWidth)), 
                                    (int)(chunkStartY + (mapY * map.GetTileHeight)),
                                    map.GetTileWidth, map.GetTileHeight
                                    ), 
                                Noise.GetNoise(mapX * 0.1f, mapY * 0.1f, map.GetSeed));

                            // Increase mapY
                            mapY++;
                        }

                        // Increase mapX
                        mapX++;
                        // Reset mapY
                        mapY = 0f;
                    }
                    // Reset mapY
                    mapX = 0f;
                }
            }            

            // Return map
            return map;
        }

I just need to optimize it in this case. But I fully agree with your advice on using .Length. However, the map is generated once and once generated it is static. The map size and chunk size can never be changed, nor will this code block ever run again (unless a new map is created). Thanks again!

This topic is closed to new replies.

Advertisement