Saturday 26 October 2013

2D Projectile Motion

Recently added trees to the game, when one of these objects is broken it should break down into wood and leaf blocks. I would like these the tree to fall apart and fall to the ground and maybe even bounce. So I need a function where I can apply some force in a direction to any block and make it move/fly/

After some research found a wiki page on projectile motion:

Wiki: Projectile Motion

Here is a simple function that takes a velocity (speed) and an angle and generates all the points through the flight of the object.

Test Function
void projectile(double velocity, double angle, float delta) {    
  double vx, vy, ux, uy, tt, terminal_v;
  double gravity = 9.8;
   
  ux = velocity * Math.cos(angle * Math.PI / 180);
  uy = velocity * Math.sin(angle * Math.PI / 180);  
  terminal_v = uy/gravity;
  
  tt = time_x*time_x;
  vy = uy * time_x - 0.5 * - -gravity * tt;
    
  if (time_x < terminal_v*2){
    Vector2 t = new Vector2((float) vx + hero.x ,(float) vy + hero.y);
    DotArray.add(t);
  }
  
  time_x += delta;
}
ux - the initial velocity accross
uy the initial velocity upwards

terminal_v is the time it takes for the object to stop moving upwards, if you double this you get the total flight time (Given the object takes off from and lands at zero Y).

For each time render is called (usually 60fps) calculate the position of the object at the current flight time and add it to an array.

In the draw part of the code I just draw each co-ordinate held in the array of vectors. This needs work as it only works for positive x (Left to right) and is hard coded to run from the hero current position but this is just a test.

Was unsure how to square a double so just multiples time.
tt = time_x*time_x;
Screen Shot

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.