Chunks? Chunk loading and unloading?

Hey guys!

So I’m still working on my 2D side-scrolling Tile game, using no libraries. All pure java. It’s running okay, but I believe this is where I get stuck:

public Level(String name) {
		this.worldName = name;
		
		Tiles = new Tile[100][100];
		
		for (int x = 0; x < Tiles.length; x++) {
			for (int y = 0; y < Tiles[0].length; y++) {
				Tiles[x][y] = new Tile(new Rectangle(x * 32, y * 32, 32, 32));
			}
		}
	}

Now, what I mean by “stuck” is, if I change the “Tiles = new Tile[100][100];” to “Tiles = new Tile[4000][4000];” my game freezes when I hit my play button… Which does this:

/* Initialize everything needed, here. */
	public void init() {
		this.camera = new Camera(0, 0);
		this.level = new Level("test");
		level.Generate();
		
		textures = new TextureLoader("Tiles/Tilesheet.png");
		textures.LoadTiles(); 
		
		player = new Entity0Player(new Vector2(100, 350));
		inputHandler = new InputHandler();
		inputHandler.setGame(this);
		inputHandler.setPlayer(player);
		
		this.addKeyListener(inputHandler);
		this.addMouseListener(inputHandler);
		this.addMouseWheelListener(inputHandler);
		
		this.GAME_WIDTH = getWidth() + 70;
		this.GAME_HEIGHT = getHeight() + 90;
		
		this.xOffset = (int)player.position.x - (GAME_WIDTH / 2);
		this.yOffset = (int)player.position.y - (GAME_HEIGHT / 2);
		this.cameraView = new Rectangle(xOffset, yOffset, GAME_WIDTH, GAME_HEIGHT);
		
		start();
	}

It seems to freeze on the “new Level()” portion because I’m trying to initialize each and every tile of the 4000x4000 tile array. So, my question:
How would I go about chunking so it only creates/initializes the ones needed and then unloads them when out of view to prevent lagging when the game generates a lot of tiles?

Hi, I’m not an expert in this field, but I read once that Minecraft used procedural terrain generation formulas to populate chunks with data. Because the formulas such as sin and cos functions go forever the terrain can go forever, hence the infinite maps. The tile array chunk can be loaded as the player approaches.
Hopefully that gives you some keywords to Google.
Cheers,
Keith

You essentially need to decide how to partition and store your map data.

Minecraft, for example, divides the game map into 16 x 16 x 256 tile “chunks” which are loaded based on proximity to the player, and unloaded as the player moves away.

My guess is that Minecraft’s strategy is to store the chunks in a List of sorts, which can be accessed like a 2d matrix, since individual chunks contain all the possible vertical space.

As for content generation, the chunks are generated procedurally at first, but they are then saved to disk, and loaded from there in subsequent visits.

I’d go for something like this:



public class Chunk
{
   public static final int WIDTH  = 10;
   public static final int HEIGHT = 10;

   protected Tiles[] data;

   public Chunk()
   {
      data = new Tiles[WIDTH * HEIGHT];
   }

   public Tiles getTile(int x, int y)
   {
      return data[(y * WIDTH) + x];
   }

   public Tiles setTile(int x, int y, Tile tile)
   {
      data[(y * WIDTH) + x] = tile;
   }

   public Tiles[] getTiles()
   {
      return new ArrayList(data);
   }

  //TODO: Whatever else you need
}

public class ChunkyMap
{
   HashMap<int, Chunk> chunks;

   protected int height;
   protected int width;

   public ChunkyMap(int width, int height)
   {
      chunks = new HashMap<int, Chunk>();  
      this.height = height;
      this.width = width;
   }

   public Tiles[] getMap(int x, int y, int chunk_radius)
   {
        int chunk_x = x/Chunk.WIDTH;
        int chunk_y = y/Chunk.HEIGHT;

       //TODO: Check if coordinates are out of the map (or do something clever to get infinite maps)

        List<Tiles> retMap = new List<Tiles>();

        int startY = chunk_y - chunk_radius;
        int startX = chunk_x - chunk_radius;
        int endY = chunk_y + chunk_radius;
        int endX = chunk_x + chunk_radius;

        for(int index = (startY * width) + startX; index < (endY * width) + endX) //Note: This is quite possibly wrong...
        {
              if(chunks.containsKey(index))
              {
                    retMap.add(chunks.get(index).getTiles());
              }
              else
             {
                    Chunk newChunk = generateChunkAt(index); //TODO: You know, implement this...
                    chunks.put(index, newChunk);
                    retMap.add(newChunk.getTiles());
             }
         }

         return retMap.toArray();
   }
 
}


Anyway, just a rough idea, I’ve personally never implemented something like this, so keep your grain-of-salt-grabbing pincers handy :wink:

Edit: Fixed some things with the code that were bothering me, but it is still pretty flawed