Large 2D tile-based grid

Hey guys!

I’m a fairly new Unity developer (this is my first forum post) and if have some questions about generating a large tile-based grid. I’ve read through quite a few threads about this topic but haven’t found too much directly applicable to what I’m trying to accomplish. Ideally I’d like to procedurally generate a 512x512 flat grid with many different materials for different tiles. The camera is top-down orthographic view, that follows the player. I’m not using physics so I’m not using mesh colliders.

I very quickly learned that instantiating 512 x 512 tiles is NOT the best way to do this.

So what are some hot tips? Should I just instantiate the tiles around the player and create others as they move towards it? Would that cause too many draw calls? Can I programatically draw the tiles onto a single plane?

I’d appreciate any guidance you can give me

Use the Mesh class to create a grid of quads, although it will need to be more than one mesh considering the number of tiles. Use UVs and a texture atlas rather than multiple materials.

–Eric

I would use an array of objects. 512x512. You of course will need an array or “map” of overall objects as well. You then need to know what point you are at. and what point you were at. Every time your previous point is not your current point, just get the x, y difference and destroy the previous objects, Create the new objects on the other side. You can tell which objects are what, by simply using the object array, since it will be indexed correctly. Previously destroyed objects wont take up any processing power so you should be good.

If you run into processing errors on things like the Andoid or IPhone then you will need to revisit how you use the objects. (perhaps moving them and keeping all your “unused” cells and reusing ones again instead of constantly destroying and creating.

Draw calls are summed by the number of objects on the screen and number of textures. Things culled out do not affect the draw call number. Things like number of textures and number of objects affect draw calls. :wink:

That’s 262,144 objects…you can’t instantiate that many (64K limit last I checked). Not to mention the massive amount of overhead that would use even if it were possible.

–Eric

Works just fine… it is 262,144 null references… you only use 31x31 at any given time or so. So yes, it will work fine.

Here is the starter concept:

var player : Transform;
var tiles : GameObject[];
var mapSize : int = 512;
var gridSize : int = 5;
var visibleGrid : int = 31;
private var objs : GameObject[,];
private var objectMap : int[,];
private var lastPosition : Vector3;


function Start(){
	objs = new GameObject[mapSize, mapSize];
	if(visibleGrid  1 == 0) visibleGrid++;
	Initialize();
}

function Update(){
	var position = GetPosition();
	if(lastPosition != position){
		DoMapMove();
	}
	lastPosition = position;
}

function Initialize(){
	for(var z=0; z<mapSize; z++){
		for(var x=0; x<mapSize; x++){
			if(objs[z, x]) Destroy(objs[z, x]);
		}
	}
	
	var halfView = Mathf.FloorToInt(visibleGrid / 2);
	var max = mapSize - halfView;
	lastPosition = GetPosition();
	var origin = lastPosition;
	origin.x = Mathf.Clamp(origin.x - halfView, 0, max);
	origin.y = 0.0;
	origin.z = Mathf.Clamp(origin.z - halfView, 0, max);
	
	for(z=0; z<visibleGrid; z++){
		for(x=0; x<visibleGrid; x++){
			var tileIndex = objectMap[origin.z + z, origin.x + x];
			if(tileIndex > tiles.Length)tileIndex = 0;
			objs[origin.z + z, origin.x + x] = tiles[tileIndex];
		}
	}
}

function GetPosition(){
	var position = player.position / gridSize;
	position.x = Mathf.Floor(position.x);
	position.y = 0.0;
	position.z = Mathf.Floor(position.z);
	return position;
}

function DoMapMove(){
	// erase the outgoing edge
	// draw the incoming edge
}

Thanks for the advice guys. This has been a massive help

Oooo… here is a thought

Have a grid 31x31, fill that grid with the tiles that are around you. ( say you are in the middle at 16,16)

move 1 square left, and you are at 17, 17 Nothing on the map changes but column 0, where it loads up the new column from your map. You would need a formula to calculate where any given map piece is in relation to the player, but it would work.

I’d recommend just making the grid using the Mesh class; that way you can have all tiles at once without performance or memory problems, and you don’t need “tricks” to get it to work.

–Eric

31 tiles at any one time would be sort of lame, anyway… Minecraft at least 512x512 at any given moment if you’re on the surface.

Minecraft doesn’t have a top-down orthographic camera.

Yeah, its not that kind of game. The perspective is similar to old-school Zelda

A single mesh (or at least minimal meshes) would be the easiest to keep track of if I can get the performance out of it (And work out how Texture2d works). Data for the tiles will be stored in a 2d-array regardless for pathfinding. This is also a vanity project, so platform restrictions aren’t truly an issue.

Since you can have a max of 65,536 vertices in a mesh, you’d need 16 meshes total to do 512x512 quads.

–Eric

Ahh my bad, I missed that part.

My suggestion was for objects, not for single un-enhanced boxes. If you wanted a tile that was… a tile not a bare little box or plane. I am talking an object with multiple sub objects or things that go on… scripts that can be attached. Effects or whatever.

Having a single mesh for each texture type would be the way to go for blank tiles. Incredibly easy to create. As long as you didn’t have more than 16384 tiles of the same texture it would work perfectly. You could build the entire mesh at start time and display whatever you wanted. Again, very simple, not a huge problem for creation. (cube limit would be 2730)

Yeah, I’m pretty sold on the mesh idea. Still trying to wrap my brain around how to set all the vertices and triangles. Is there a simpler way than setting the points for every single quad in the mesh? or does anyone have an algorythm for creating them?

p.s. loving how supportive the unity community is. Thanks again

You have to set all the vertices for all quads, but you can of course just do it in a loop. See TerrainObjExporter for a script that creates a grid of quads (you would want the code that creates two triangles rather than a single quad, and it will require adapting naturally, since among other things all 4 vertices in a quad should be unique rather than shared in this case, but at least it should get you started).

–Eric

Thanks, I’ll check it out now. I got the mesh dividing along one axis but once I started thinking about positioning vertices and triangles with nested loops, I decided my day at work had been far too long for me to try to work it out from scratch