4
\$\begingroup\$

I'm currently in the process of making a 2D tile based game. This game has an "infinite" world that can be traversed and modified as needed. I am creating the chunks with a mesh and I apply a texture to them. The chunks texture updates every time I set a tile with a new Sprite.

Each time I set a new tile, the surrounding tiles from the same chunk recalculate based on their adjacent tiles and they set their sprite accordingly (Auto-tiling). This works perfectly fine and I have no issues, unless the tile is along the edge of the chunk.

If the tile is along the edge of the chunk, it updates the texture of the chunk perfectly but the adjacent chunk textures aren't updated. Now, I am using the below code to obtain the adjacent chunks based on the tiles position. This works, however it is extremely ugly and unreadable.

if (tileX == 0 || tileY == 0 || tileX == chunkSize - 1 || tileY == chunkSize - 1)
{
    var chunksToUpdate = new List<Vector3Int> ();
    var position = chunk.Position;

    if (tileX == 0 && tileY == 0)
    {
        chunksToUpdate.Add (new Vector3Int (position.X - chunkSize, position.Y, position.Z)); //left
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y - chunkSize, position.Z)); //down
        chunksToUpdate.Add (new Vector3Int (position.X - chunkSize, position.Y - chunkSize, position.Z)); //downleft

    }
    else if (tileX == 0 && tileY == chunkSize - 1)
    {
        chunksToUpdate.Add (new Vector3Int (position.X - chunkSize, position.Y, position.Z)); //left
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y + chunkSize, position.Z)); //up
        chunksToUpdate.Add (new Vector3Int (position.X - chunkSize, position.Y + chunkSize, position.Z)); //upleft

    }
    else if (tileX == chunkSize - 1 && tileY == 0)
    {
        chunksToUpdate.Add (new Vector3Int (position.X + chunkSize, position.Y, position.Z)); //right
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y - chunkSize, position.Z)); //down
        chunksToUpdate.Add (new Vector3Int (position.X + chunkSize, position.Y - chunkSize, position.Z)); //downright

    }
    else if (tileX == chunkSize - 1 && tileY == chunkSize - 1)
    {
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y + chunkSize, position.Z)); //up
        chunksToUpdate.Add (new Vector3Int (position.X + chunkSize, position.Y, position.Z)); //right
        chunksToUpdate.Add (new Vector3Int (position.X + chunkSize, position.Y + chunkSize, position.Z)); //upright

    }
    else if (tileX == 0)
    {
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y + chunkSize, position.Z)); //up

    }
    else if (tileX == chunkSize - 1)
    {
        chunksToUpdate.Add (new Vector3Int (position.X + chunkSize, position.Y, position.Z)); //right

    }
    else if (tileY == 0)
    {
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y - chunkSize, position.Z)); //down

    }
    else if (tileY == chunkSize - 1)
    {
        chunksToUpdate.Add (new Vector3Int (position.X, position.Y + chunkSize, position.Z)); //up

    }

Clarification: I am checking to see if tileX or tileY are along the edges of the chunk. If they are then I add a new Vector3Int to the list. I also only attempt to obtain the chunks that will be affected by the chunks texture update.

After this, I loop through all of the Vector3Int's in the chunksToUpdate list and update them like so.

foreach (var pos in chunksToUpdate)
{
    MeshChunk updateChunk = GetChunk (pos);

    if (updateChunk != null)
    {
        UpdateChunkTiles (updateChunk);
    }
}

I'm not looking for any criticism about my naming conventions or formatting. I'm wondering if there is a more elegant way of handling this scenario? Can it be refactored to take up less space and its readability improved.

\$\endgroup\$
  • \$\begingroup\$ No one has a more elegant solution? Or I've completed butchered my post and barely anyone understands it? \$\endgroup\$ – Mike Hunt Feb 2 '16 at 6:46
  • \$\begingroup\$ your post is good :) I can't think of any way to improve it, that's how all my infinite world generation code looks too \$\endgroup\$ – Keith M Feb 3 '16 at 18:53
  • 1
    \$\begingroup\$ Jamal thanks for editing my post and cleaning it up. @KeithM Thanks but surely there is some genius out there that can come up with an algorithm to make it look cleaner :) \$\endgroup\$ – Mike Hunt Feb 4 '16 at 8:15
2
\$\begingroup\$

Well, I suggest next approach

        if (tileX != 0 && tileY != 0 && tileX != chunkSize - 1 && tileY != chunkSize - 1)
        {
            return;
        }

        var leftChunk = tileX == 0;
        var rightChunk = tileX == chunkSize - 1;
        var downChunk = tileY == 0;
        var upChunk = tileY == chunkSize - 1;


        if (leftChunk)
        {
            chunksToUpdate.Add(new Vector3Int(position.X - chunkSize, position.Y, position.Z)); // Left
            if (downChunk)
            {
                chunksToUpdate.Add(new Vector3Int(position.X - chunkSize, position.Y - chunkSize, position.Z)); // DownLeft
            }
            else if (upChunk)
            {
                chunksToUpdate.Add(new Vector3Int(position.X - chunkSize, position.Y + chunkSize, position.Z)); // UpLeft
            }
        }
        else if (rightChunk)
        {
            chunksToUpdate.Add(new Vector3Int(position.X + chunkSize, position.Y, position.Z)); // Right
            if (upChunk)
            {
                chunksToUpdate.Add(new Vector3Int(position.X + chunkSize, position.Y + chunkSize, position.Z)); // UpRight
            }
            else if (downChunk)
            {
                chunksToUpdate.Add(new Vector3Int(position.X + chunkSize, position.Y - chunkSize, position.Z)); // DownRight
            }
        }
        if (downChunk)
        {
            chunksToUpdate.Add(new Vector3Int(position.X, position.Y - chunkSize, position.Z)); // Down
        }
        else if (upChunk)
        {
            chunksToUpdate.Add(new Vector3Int(position.X, position.Y + chunkSize, position.Z)); // Up
        }

It makes code a little bit more readable by using bool named variables and also has less code lines and if else branching.

Moreover, it is often (almost every time) better to have less nesting via inverting if statement like I did. So basically I quit if it is not an edge tile.

\$\endgroup\$
  • \$\begingroup\$ Thanks! That is much better and so much easier to read. I knew there would be someone out there who could come up with a more elegant way. Much appreciated :) \$\endgroup\$ – Mike Hunt Feb 8 '16 at 23:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.