Thursday, May 16, 2013

2D Grid on a 3D Terrain

Quick post tonight.

I wanted to mess about with an idea that has bouncing around my head.  Taking a Unity terrain and building a 'grid' over it, similar to what you would find in most tactical turn based games.

So to start:
Create a Terrain.  Resolution does not matter, the grid will adapt.
Create an empty gameobject, I called mine GridOrigin.
Attach the following script to it.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Grid : MonoBehaviour {

public Terrain terrain; //terrain grid is attached to
public bool ShowGrid = false;
public int CellSize = 10;

private Vector3 terrainSize;
private Vector3 origin;

private int width;
private int height;

private List<GameObject> objects;

void Start ()
{
terrainSize = terrain.terrainData.size;
origin = terrain.transform.position;

width = (int)terrainSize.z / CellSize;
height = (int)terrainSize.x / CellSize;

objects = new List<GameObject>();

BuildGrid();
}

void Update ()
{
foreach(GameObject obj in objects)
obj.SetActive(ShowGrid);
}

void BuildGrid()
{
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
Vector3 pos = GetWorldPosition(new Vector2(x,y));
pos += new Vector3(CellSize / 2, terrain.SampleHeight(GetWorldPosition(new Vector2(x,y))), CellSize /2);
go.transform.position = pos;
if(x==0)
{
go.renderer.material.color = Color.red;
}
if(y==0)
go.renderer.material.color = Color.green;

go.transform.localScale = new Vector3(CellSize /2, CellSize /2, CellSize/2);
go.transform.parent = transform;
go.SetActive(false);

objects.Add(go);
}
}
}

public Vector3 GetWorldPosition(Vector2 gridPosition)
{
return new Vector3(origin.z + (gridPosition.x * CellSize), origin.y, origin.x + (gridPosition.y * CellSize));
}

public Vector2 GetGridPosition(Vector3 worldPosition)
{
return new Vector2(worldPosition.z / CellSize, worldPosition.x / CellSize);
}
}

Attach your terrain to the script.

When you run, you should see your terrain as normal:

In the GridOrigin object in the inspector, you can toggle a visual display of the grid on and off.  The cubes appear in the exact centre of the gridcell.  Green is X dimension and red is Z.

Each gridcell can be referenced by supplying an X and a Y local co-ordinate.  5,7 for example, refers to the grid cell that is 5 cells in the x dimension and 7 cells in the Z dimension.

There are two methods at the end of the script GetWorldPosition and GetGridPosition.  This is really the heart of the script - GetWorldPosition will return a Vector3 that corresponds to the passed GridLocation.  You can use this to position objects.  For example, if you wanted to move your skeleton object to the grid location 5,7 you can use skeleton.transform.position - grid.GetWorldPosition(5,7).  GetGridPosition will return the grid location of a passed Vector3 as a Vector2.

Using a loop you can quickly create and place a horde of enemies.  900 skeletons in this case...