Saturday 19 October 2013


Random Island Generator

After making a few maps with Tiled I realized it was slow and tedious, I thought a procedural island would be doable, I read a few articles on different methods and decided to go with one which was simple enough for me to code.

Step 1
Create a 18x18 array of Tiles, this is a simple class with variables, name, x, y, number, texture, code. The texture for each tile is set to water:

 private void create_water_map(){
  int id = 0;
  SQUARE = 18;

  for (int i = 0; i < LAYERS; i++) {
    for (int y = 0; y < SQUARE; y++) {
      for (int x = 0; x < SQUARE; x++) { 
 Tile tile = new Tile(x << 5, y << 5, x, y, "WATER", Art.water, id);
 id += 1;
 tileArray_1.add(tile);
      }
    }  
   }
 }
Step 2

Take the centre tile and spiral out, for the first 3 or 4 passes set the Tile to grass, then set the tile to grass if random number < value, the chance gets less as the number of the cycle goes up.
private void create_mini_island(){
  int number_of_cycles = 7;
  int move_amount = 0;
  int random_cycle_no = 3;
  int tile_count = SQUARE * SQUARE;
  int tile_no = tile_count/2 + (SQUARE/2);
  int prev_tile_no = tile_no;
  
  Tile current_tile = tileArray_1.get(tile_no);
  current_tile.texture = Art.grass;
  current_tile.name = "GRASS";
  
  for(int cycle = 1; cycle <= number_of_cycles;cycle++){ 
    int rnd = 100 - (cycle*12);
  
    for(int d = 0; d < 4; d++){
      if(d == 0 || d == 2){
        move_amount += 1;
      }
      for (int m = 1; m <= move_amount; m ++ ){
        if (d == DOWN){
   tile_no -= SQUARE;     
 }else if (d == LEFT){
         tile_no -= 1;             
 }else if (d == UP){
   tile_no += SQUARE;       
 }else if (d == RIGHT){
   tile_no += 1;
 }
 
        process_direction(tile_no,prev_tile_no, tile_count, "GRASS", current_tile, Art.grass, rnd, cycle, random_cycle_no);    
        prev_tile_no = tile_no; 
      }
    }
  }
}

Step 3
The map resembles a basic island but is way too small, now loop through the array and split each tile up into many more and set the border to water, this will help make the island less block like later on.



private void enlarge_mini_island(){
  int x,y,start_x,start_y;
  int count = -1;
  int t = -1;
  int split_by = 8;
  land_keep_percent = (int) (split_by * 0.8);
  
  for (Tile tile : tileArray_1) {
    count ++;
    for (int h = 0; h < split_by; h++){
      if (count == t){
 for (int w = 0; w < split_by; w++){
   int row = tile.number / SQUARE;
   int column = tile.number % SQUARE;
   // replace hard coded new width and height 144 and 1008
   int id = w + ((tile.number)*split_by) + (h*144) + (row * 1008);
   
          if (count == t){System.out.println(id + " tile: " + count + " w:" + w + " h:" + h + " row: " + row );}
     start_x = (column*split_by) + w;
     x = (start_x << 5);
     start_y = (row * split_by) + h;
     y = (start_y << 5);
     Tile new_tile;
     // make centre tiles water
     if (w < 1 || w > land_keep_percent || h < 1 || h > land_keep_percent){
       new_tile = new Tile(x, y, row, column, "WATER", Art.water, id);
     } else {
       new_tile = new Tile(x, y, row, column, tile.name, tile.texture, id);
     }
            
            tileArray_2.add(new_tile);
     if (w == 1 && h == 1 && new_tile.name.equals("GRASS")){
       new_tile.marker = true;
       tile_connector.add(new_tile);
            }
        }
      }
    }
  Collections.sort(tileArray_2);  
}

Step 4
 For each tile added to the connector array check down to see if there is land, if yes then turn the tiles below into grass, repeat this for left also which now gives us this:


Step 5
Smoothing out the land to make the grass areas less box like, loop through all the tiles, if the tile is water and touching at least x number of grass tiles then turn it into grass.

Repeat

 Step 6
Loop through the array of tiles again making water tiles touching grass randomly into grass.

Step 7
Now that the island is finished loop through the array once more, every tile that is water and touching grass becomes sand. Run through this again randomly this time so some shores are thicker.

Step 8
Next for each tile that is sand and touching grass calculate which sand to grass tile it should be. 
Check the 3 tiles above, to the left and right and the 3 tiles below use this to create a code. If the water tile code is 001 01 001 then it has 3 sand tiles to the right so show the correct tile.

The sand to grass tiles:

 Repeat this process for water touching sand.


The next stages include creating rivers, placing rocks etc and identifying areas to place trees and so on. I have included some code snippets just to give an idea how how parts of this work, its quite simple and takes only a moment to run through. 

1 comment: