0
\$\begingroup\$

I have a 2D world in form of a Block[][]-Array that holds all the blocks of the world. Every block has it's own Box2D Body (I want a "minecraft"-like 2D world for this project). Naturally I don't want to calculate all the box2D-bodies at the same time and I don't want to render what's not on screen neither (SpriteBatch).

So I divided my huge world into "Chunks". They are all of the same width and height. Now I'm a bit stunned though.

Each chunk starts at (0,0) which is the lower left corner of the chunk. Now in my player-class I do the following (if the player has moved)

public void calculateChunksToRender()
{
    for(int x = (int) this.getPosition().x - Chunk.chunkWidth * 2 - (Chunk.chunkWidth / 4); x >= 0 && x <= game.getMap().getWidth() - Chunk.chunkWidth && x<= (int) this.getPosition().x + Chunk.chunkWidth; x++)
    {
        if(x % Chunk.chunkWidth == 0)
        {
            Vector2 chunkPosition = new Vector2(x, 128);
            System.out.println(chunkPosition);
            chunksToRender.put(chunkPosition, game.getChunkMap().get(chunkPosition));
        }
    }

As the start point of the x-coordinate in the chunk is on the left side, I go 1 3/4 chunks to left and render it, if still visible. Why 1 3/4? Because that way when I'm 3/4 to the right I don't see the left chunk anymore, so I don't need to render it. For the right chunk I do the same, but only with Chunkwidth... I guess it's pretty self-explanatory though.

Obviously this is just the X-dimension and I'm not sure if there isn't a far better way to do this. Why? Because, well, right now I have 3 chunks to render, but basically I have a 8-neighbourhood around the one chunk the player is currently on/in. I fear that I will have to render/calculate (the physics for) far too many bodies the way I'm doing it right now. Currently I have 12k bodies in memory at any given time and around 45-60fps. But that's just 3 chunks!

Each block has its sprite attached to it through the box2D body (userData), maybe I should separate them and separate rendering/physics calculation as well? Not sure though, because if a player jumps to another chunk I want him to collide with the blocks there immediately not after a delay (so he is stuck in the middle).

I also tried to calculate the nearest chunk (just go left on the x-axis and down on the y-axis until you find a chunk) and calculate the surrounding ones, but that's much more of a performance hit (logically)

Any ideas/optimizations?

Kindest regards, Ohuro

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Firstly, going left and down to find the nearest chunk isn't necessary - chunk/local (that's the pair of terms I use in my engine) can be calculated like this:

ChunkX = Floor(PlayerX / ChunkWidth)
ChunkY = Floor(PlayerY / ChunkHeight)

The position relative to that position can be calculated like this:

LocalX = Floor(PlayerX % ChunkWidth)
LocalY = Floor(PlayerY % ChunkHeight)

This (in case it isn't obvious) means that to get the chunk coordinates you divide by the chunk size on each axis, and to get the coordinates relative to that chunk you get the remainder that doesn't evenly divide into those sizes.

Calculating adjacent chunks to one shouldn't be expensive at all - you just increment the coordinates on each axis. I'm not sure what you're doing currently, but I'd do something like this:

List<Chunk> GetSurroundingChunks(Vec2 position, int range = 1)
{
    List<Chunk> chunks = new List<Chunk>();
    int cx = position.X / ChunkWidth;
    int cy = position.Y / ChunkHeight;
    for (int y = cy - range; y < cy + range; y++)
    {
        for (int x = cx - range; x < cx + range; x++)
        {
            chunks.Add(WhereverChunksComeFrom[x, y]);
        }
    }
    return chunks;
}

That of course does a square around the given position, but it could be modified to do a circle or what-have-you.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .