Roger
Roger

Reputation: 2135

Dynamically adding tiles to a grid based map

I want to have an infinitely explorable map. The plan is to create categories of game tiles (roads, obstacles, buildings), and randomly choose a category of game tile to be added when the player approaches the edge of the existing set of tiles. Tiles will also be destroyed once the player is 2 grid squares away from that tile. Currently I am using a multidimensional array that requires a size initializer.

What I have so far:

public class GameManager : MonoBehaviour
{
    private GameObject[,] tileArray;
    public GameObject groundTile;
    public GameObject player;

    private int tileSize = 80;
    private int nextFarX = 1;
    private int nextFarZ = 1;
    private int nextNearX = -1;
    private int nextNearZ = -1;
    private float padding = .1f;

    private int arrayOffset;
    private int arrayDimension;

    // Use this for initialization
    void Start ()
    {
        arrayDimension = 200;
        arrayOffset = arrayDimension / 2;
        tileArray = new GameObject[,];
        this.AddCubeAt(0, 0);
    }

    // Update is called once per frame
    void Update () {
        var x = Convert.ToInt32(player.transform.position.x / tileSize);
        var z = Convert.ToInt32(player.transform.position.z / tileSize);

        for (int i = -1; i < 2; i++)
        {
            for (int j = -1; j < 2; j++)
            {
                var checkX = x + i;
                var checkZ = z + j;
                if (tileArray[checkX + arrayOffset, checkZ + arrayOffset] == null)
                {
                    //player is less than 2 tiles away from this grid, add a tile
                    this.AddCubeAt(checkX, checkZ);
                }
            }
        }
        // feels like a hack, but it will remove tiles that are not touching the tile that the player occupies
        for (int i = 0; i < 6; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                if (i == 0 | i == 5 | j == 0 | j == 5)
                {
                    if (tileArray[x + (i-2) + arrayOffset, z + (j-2) + arrayOffset] != null)
                    {
                        Destroy(tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset]);
                        tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset] = null;
                    } 
                }
            }
        }
    }

    private void AddCubeAt(int x, int z)
    {
        var pos = new Vector3(x * tileSize, 0, z * tileSize);
        var rot = Quaternion.identity;
        GameObject newCube = (GameObject)Instantiate(groundTile, pos, rot);
        tileArray[x + arrayOffset, z + arrayOffset] = newCube;
    }
}

What is a better way to approach this?

Upvotes: 1

Views: 590

Answers (2)

Roger
Roger

Reputation: 2135

Decided to go with a simple Dictionary and methods to query/update it:

private GameObject RetrieveTileAt(int x, int z)
{
    string key = string.Format("{0}.{1}", x, z);
    if (tileDictionary.ContainsKey(key))
    {
        return tileDictionary[key];
    }
    else
    {
        return null;
    }
}

private void InsertTileAt(int x, int z, GameObject tile)
{
    string key = string.Format("{0}.{1}", x, z);
    tileDictionary[key] = tile;
}

It is not an infinitely sized grid, (int min + int max)squared, but it should be far more than I need.

Upvotes: 0

Vladislav Kurenkov
Vladislav Kurenkov

Reputation: 88

You should familiarize yourself with Graph Data Structure (not adjacency matrix implementation). It's much more appropriate for this task. And, I would solve this

Tiles will also be destroyed once the player is 2 grid squares away from that tile

in another way: Every time player changed his position I would start DFS on target depth (in your case it's 2) and remove found tiles.

Upvotes: 1

Related Questions