2D Procedural Terrain Generation

So I am trying to figure out how to create a procedural terrain generation engine for a 2D game similar to Terraria or Starbound. But I am running into a problem when it comes to generating blocks. Apparently I am generating so many that Unity is having a heart attack and dying. So let’s cover what I have so far:

public int mapWidth, mapHeight;
GameObject[,] blocks;
public GameObject baseBlock;

Where baseBlock is a prefab game object with a 2D box collider and spriterenderer attached, with a default sprite. I found that if I place it within the scene but positioned at Y 10,000 so it’s out of site it greatly shortens map generation time because the base block has already been instantiated when I start cloning it.

Then I test generation using the Start() method, generating those blocks is also straight forward:

blocks = new GameObject[mapWidth, mapHeight];
for(int x = 0; x < blocks.GetLength(0); x++)
  for(int y = 0; y < blocks.GetLength(1); y++)
    blocks[x, y] = (GameObject)Instantiate(baseBlock, Vector2.zero, Quaternian.identity);

That all works just fine save for one problem. If my mapWidth or mapHeight > 256 or so, Unity croaks. Too many Game Objects I guess. I looked into pooling and stuff but that seems unreasonable, requiring the introduction of systems meant for 3D being introduced to your 2D world to create a mesh, etc., etc. My large maps will be 8192x2048 blocks in size, or so I am hoping, so the measly 256x256 blocks I can create right now is a far cry from my objective. What can I do to resolve this?

You should probably set up some dynamic loading/unloading of your gameobjects. So instead of trying to load them all into your scene you are only loading the ones the player can see. You would also want to add an acceptable level of padding to this so you don’t run to the right and fall off the world cause nothing is loaded yet.

Below I have done some of it, and commented some logic that needs to be added in. But that should get you started.

public int loadWidth, loadHeight;
public float updateTime = 1.0f;
private float currTime = 0.0f;
private Vector2 lastPosition;

public int mapWidth, mapHeight;
GameObject[,] blocks;
public GameObject baseBlock;

// Initial load
blocks = new GameObject[mapWidth, mapHeight];
for(int x = currentPosition-(loadWidth/2); x < currentPosition+(loadWidth/2); x++)
  for(int y = currentPosition-(loadHeight/2); y < currentPosition+(loadHeight/2); y++)
    blocks[x, y] = (GameObject)Instantiate(baseBlock, Vector2.zero, Quaternian.identity);
	
// Update
// You will have to change this to fit your code
currTime += Time.deltaTime;
if(currTime > updateTime && lastPosition != currentPosition)
{
	currTime = 0.0f;
	
	// Get min and max values from currentPosition and lastPosition
	int minX, maxX;
	int minY, maxY;
	
	for(int x = minX; x < maxX; x++) {
		for(int y = minY; y < maxY; y++) {
			//Add new objects
		}
	}
	
	// remove old objects
	
	lastPosition = currentPosition;
}