Instantiating tiles to "stream" in a world

So here’s what I’m trying to do:

I’m building a large 2d world based off of a height map that’s eventually converted to tile values. Basically a giant 2d array.

The world will be too large to keep entirely in memory, and I want the player to be able to seamlessly walk from one end to the other.

The first issue then is how do I store the data on disk and load it, and how do I take what’s in memory (as it is more than I can/should draw at one time) and only display what’s around the player.

My current tests involve the latter case, and I’m not loading anything from disk. I have the 2d array in memory. I have a defined “chunk” size, which is the amount of content I intend on instantiating at one time. When the player leaves the current “chunk”, I instantiate the new tiles around the player character.

The problem is that this results in a huge pause in the action, and I’m not sure if I’m taking the right approach using Unity’s instantiation and GameObjects.

Has anyone else dealt with this or has some clue about the direction I should be heading?

wait what is this “height map” for? Do you mean that you have a texture that the pixels of which represent data for a specific area of your 2d world? (that wouldn’t make it a “height map”, “height map” is the use of a texture/image to store the data of the height for a terrain at given points).

As for your world. What is it made out of? Is it a set of tiles/prefabs that repeat? Or is everything unique?

If it’s all unique… well you’re shit out of luck. All unique things need to be loaded into memory before use. And you can’t load them all up front due to memory constraints.

If it’s all reusable tiles. Then you load in pool of them at the get go. You pull from this pool for whatever local tiles you need. You should always load enough into your pool to cover and given region of your overall map that you might be in. So if you know that you’ll never have more than 5 of Tile A on screen at a time… you load 5 of Tile A.

Yeah, the bit about the heightmap was probably a bit unclear, and I could have left it out for clarity’s sake. I’m using a heightmap to determine elevation in the world. The values are stepped, basically, and I have tiles that represent the elvation change with a cliff wall. I keep the height data so I can offset the higher tiles once there’s been an elevation change. This is inconsequential to the problem I’m facing, however.

So yes, I do have a pool of reusable tiles I’m working with. Each tile is about 2mx2m of space, and they can range from flat grassy pieces, to beach front pieces, etc. Since it’s all generated, I have no idea if I’m going to need more than, say 5, of any given specific piece. My plan was to have one of each GameObject I’m using for tiles in memory, then instantiate those as I need as the player crosses the map.

Is there a better way to do that? All I’m doing is changing the transforms on the copies. I don’t need to alter any of them individually, so I don’t know if there’s a cheaper way to bang out some meshes. I see these minecraft-like engines popping up, and they seem to handle populating the world with a lot of meshes with no hitching.

The “minecraft” way of handling this is to create one mesh from many blocks, or “tiles” in your case. The textures don’t blend from one tile to the next, which is really convenient. It basically lets you use a texture atlas to draw your terrain, based on the index of the texture at that tile.
So, these engines don’t draw each block as a separate game object. that would be nutso crazo.
I’m having a little trouble visualizing what you are doing. Is this an isometric view of landscape, looking down?
It sounds like you are creating individual gameobjects for each um…tile. Like a gameobject for a tile of grass. Another next to it for a tile of sand. Is that about right?

You should be able to calculate some max though.

You say you have this “chunk size” that is the most you’d be showing at any given time. OK… lets say this chunk size is N x N tiles, making A tiles (A for area). That’s a maximum of A tiles on screen at a time. Now we have a theoretical maximum. All tiles can only have at most A on screen if they were the only tiles on screen.

We can reduce this maximum for several types of tiles as well. You bring up that your tiles stack in reference to the height map. So like your cliff tiles may could be used a lot of the time because you stack them on top of each other. I bet you also have tiles that don’t get stacked… you probably wouldn’t stack water tiles. So you’ll probably need fewer than those than you would cliff tiles. Found your medium.

Another might be you have ‘edge’ tiles. Edges are only used so often. You know that in any given region of size A that only half of them could ever be edge tiles (you’d have to do your own math to deduce the actual number). That means you have a A / 2 limit on edge tiles that need to ever be loaded.

I do a similarish thing in mine. I have very large tiles (10x10) which means only about 9 can be on screen at a time… so I have 9 of each at a time. I also know that only 3 beach tiles can be on screen at a time. So I only have 3 of each beach tile loaded.

If you can’t reduce the time needed to instantiate everything you want, just don’t try to do it within one frame. Split the work you do across multiple frames. Coroutines are good for that.

jc_lvngstn :
Correct. Each tile is about 5’x5’ of world, and it’s structured more or less like the old 2d tile mapped games.

I’m either going to go with textures that explicitly acknowledge the tiled structure of things or make the grass texture tiling so that there won’t be obvious seams between the tile elements. Something like Neverwinter Nights, or this thing I found : http://img109.imageshack.us/img109/879/terraintrees.jpg

The problem is the world is going to need to be large, and I need a way to load this stuff in and dump the old stuff as the player moves across the map.

I would think you would only instantiate the 5x5 tiles (however many there are) at the beginning…and from then on, you just change the vertices ( if necessary) and the uv data. Well…and the location of the tiles as they are left behind, and are re-positioned in front of the player.

But honestly…I’ve never made a game like this, so that’s just off the top of my head. There are probably even more efficient ways.

Looking at that screenshot…it looks like it would be somewhat straightforward, depending on whether or not the terrain height is just like a heightmap, or can actually be 3d with tunnels and such.

But you don’t “dump” the old stuff, per se. If your player moves east far enough, you transplant the tiles from the west side to the east side, and give them a different textures, mesh, or whatever. That shouldn’t take long at all. And you could spread this out over several frames…say 1 tile generated every 5 frames.

I worked on something similar to this.

You have two sets of arrays. One is the actual ‘map data’. The other is ‘view data’.

The map data can be HUGE, it is basically just a 2d array of tile types and any additional data you need for those tiles.

The view data is the actual instantiation of the tiles from the map data, in the ‘3d world’. In my implementation, I kept the current viewable area, along with the surrounding tiles, so if the user moved in any direction, the tiles would be available, without any obvious popping in.

As the user moves around, you load the meshes for the surrounding area, and remove the ones that are no longer in the immediate area.

To help understand the concept… imagine a normal array [0, 1, 2, 3, 4, 5] If I am on number 3, I would also load the data from 2 and 4. If I then move to 2, I load the data from 1, and remove the data from 4. If I continue and move to 1, I load the data from 0 and remove the data from 3.

So in that example, the ‘view data’ is: index-1, index, index+1. The ‘map data’ is the entire array.

It worked out really well. The map data is very small, so you can have very HUGE maps, and keep them in memory.

That’s basically exactly what I’ve set out to do.

A few questions/issues, though.

  • My world data is going to be around 10k by 10k, plus you can transition to dungeons that have their own (albeit small) sets of data. My assumption was that this will be too big to have hanging around in memory.
  • When you’re offloading stuff that has left the view and loading new stuff on the front, how do you avoid pauses? Are you using coroutines as someone above recommended? I’ve worked with threading before in other languages/frameworks, but I’ve yet to dabble in that with unity.
  • For the sections that only exist in world data and not in view data, how do you handle things like AI pathing and other simulation issues? Is there just some concept of LoD that allows them to work with just world data and no physical meshes to interact with?

So you’re saying you can transplant a GameObject from one area to another and give it different mesh data? Would that reduce the framerate hit from instantiating something from scratch?

I also have to look into the “spreading out over several frames” coroutine stuff. That might be the major hurtle I have to deal with.