How to create a random tileset in Unity2D


When it comes to the background, classic shmups usually use something like infinite scrolling. Because we are not making a normal shmup with spaceships and other flying stuff we wanted to handle this completely different.

Therefore we created a static background, which is not moving during the actual battle. To give the user some feedback regarding progress, we also move the background after defined waves or a boss fight.

To avoid creating hundreds of full sized background assets we thought of randomly create these backgrounds out of a tileset image.


This is actually quite easy, the only thing you need is a image with a defined grid of single tiles. Next thing you will need is something to draw the tiles on. I used the unity plane component with a mesh renderer for that.

First step, initialize the mesh:

int numTiles = size_x * size_y;
int numTris = numTiles * 2;

int vsize_x = size_x + 1;
int vsize_y = size_y + 1;
int numVerts = vsize_x * vsize_y;

Vector3[] vertices = new Vector3[ numVerts ];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];

int[] triangles = new int[ numTris * 3 ];

int x, z;
for(z=0; z < vsize_y; z++) {
    for(x=0; x < vsize_x; x++) {
        vertices[ z * vsize_x + x ] = new Vector3( x*tileSize, 0, -z*tileSize );
        normals[ z * vsize_x + x ] = Vector3.up;
        uv[ z * vsize_x + x ] = new Vector2( (float)x / size_x, 1f - (float)z / size_y );
    }
}

for(z=0; z < size_y; z++) {
    for(x=0; x < size_x; x++) {
        int squareIndex = z * size_x + x;
        int triOffset = squareIndex * 6;
        triangles[triOffset + 0] = z * vsize_x + x +           0;
        triangles[triOffset + 2] = z * vsize_x + x + vsize_x + 0;
        triangles[triOffset + 1] = z * vsize_x + x + vsize_x + 1;

        triangles[triOffset + 3] = z * vsize_x + x +           0;
        triangles[triOffset + 5] = z * vsize_x + x + vsize_x + 1;
        triangles[triOffset + 4] = z * vsize_x + x +           1;
    }
}

// Create a new Mesh and populate with the data
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uv;

// Assign our mesh to our filter/renderer/collider
MeshFilter mesh_filter = plane.GetComponent();
MeshCollider mesh_collider = plane.GetComponent();

mesh_filter.mesh = mesh;

 

Next step, split your background image into single tiles:

private Color[][] SplitTiles() {
    int numTilesPerRow = texture.width / tileResolution;
    int numRows = texture.height / tileResolution;

    Color[][] tiles = new Color[numTilesPerRow*numRows][];

    for(int y=0; y < numRows; y++) {
        for(int x=0; x < numTilesPerRow; x++) {
            tiles[y*numTilesPerRow + x] = texture.GetPixels( x*tileResolution , y*tileResolution, tileResolution, tileResolution );
        }
    }

    return tiles;
}


Final step, draw your random tiles on the mesh:

int texWidth = size_x * tileResolution;
int texHeight = size_y * tileResolution;
Texture2D newTexture = new Texture2D(texWidth, texHeight,texture.format, false);

Color[][] tiles = SplitTiles();

for(int y=0; y < size_y; y++) {
    for(int x=0; x < size_x; x++) {
        Color[] p = tiles[Random.Range(0, 30)];
        newTexture.SetPixels(x*tileResolution, y*tileResolution, tileResolution, tileResolution, p);
    }
}
newTexture.anisoLevel=1;
newTexture.mipMapBias=0f;
newTexture.filterMode = FilterMode.Point;
newTexture.wrapMode = TextureWrapMode.Clamp;
newTexture.Apply();

MeshRenderer mesh_renderer = _plane.GetComponent();
mesh_renderer.sharedMaterials[0].mainTexture = newTexture;

With a shader on top the final result looks like this

Download Unity 5 Sample Project

As with every previous tutorial, we provide you with a sample project for Unity 5.

2 Comments

Alexander Haider

Even though Alex may be the quiet one but his godlike development skills will render you speechless for quite a while. Some people say: Wherever there's a problem there's an Alex to fix it.