LibGDX Simple Slides

Currently working on a game for Wing Wing Shoot Bag using Java with LibGDX. While trying to learn Pixel/Game art I produced a few animated GIFS, one of which would be perfect for the main screen.

Being a little lazy I thought of loading in the individual images and looping through them rather than create one large image and cut it up programmatically for an animation. This worked, I had created a sort of slide player.

After pressing start within the game menu I wanted the current frame to pause and fade out, then the intro of the game would play. The intro follows the movie to which the game is based, several images would fade in, hold then fade out.

Fading in and out
First off I needed to find a way to fade an image in or out, there is a library available to do this: https://code.google.com/p/java-universal-tween-engine/

I followed the guide and setup a Sprite Accessor class: Class source

Slide Manager
Next I created a slide manager class, this would hold an array of slides which could have some simple attributes:

  • sprite;              // The image
  • fade_duration  // Time to fade in or out
  • hold_duration  // Time to hold slide on screen after fade in
  • total_duration  // time for fade in, hold and fade out
  • gap_duration   // time between slides

Classes: Slide ClassSlide Manager

Creating and using the Slide manager
Basically you initiate the new class then add to the array of images with some settings. During the render loop you tell the class to update and it will play your images in order; fading them in and out.

// Declare a new var
SlideManager slide_manager;

// Slides
slide_manager = new SlideManager();

// Add slides that fade in for 4 seconds, holds for 1 seconds
// After fade out leaves a gap of 1 seconds before next slide

slide_manager.add_slide(new Slide(“intro/screens/russian.png”, 4, 1, 1));
slide_manager.add_slide(new Slide(“intro/screens/spy.png”, 4, 1, 1));

// Add a slide with an overlay animation
// Passes animation width, speed and position
slide_manager.add_slide(new Slide(“bck.png”, 2, 0, 1, “frames.png”, 70, 0.1f, 45, 25));

I started playing about with a few variations of slides, would probably move the extras such as animations into an array and create a new animation class to pass with the slide.

This is a render loop for the intro screen, when the slides are done it just loads the next screen:

public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
slide_manager.tick(delta);

// DRAW
batch.begin();
if (!slide_manager.finished){
slide_manager.draw(batch);
}
batch.end();

if (slide_manager.finished){
game.setScreen(game.level_one);
}
}

This is a very quick prototype which only allows simple fading in and out and overlaying of one animation. It requires a library to be imported even though setting the colour(Alpha) of a sprite over time is very simple I could go on to use many more of the libs features.

This class will allows me to quickly create simple comic book style cuts scenes between levels while prototyping.

 

Simple Screen Shake

Lots of games add excitement by using screen shake, when your character gets hit or on certain events a little rumble really lets the player know something has occurred. While prototyping some features of Endure I revisited some old code to add a small rumble when the fishing line breaks:

Small Screen Shake

Large Screen Shake (Over the top)

Code (Simple Rumble Class)

Pastie Source Code

 

public class Rumble {

  public float time;
  Random random;
  float x, y;
  float current_time;
  float power;
  float current_power;

  public Rumble(){
    time = 0;
    current_time = 0;
    power = 0;
    current_power = 0;
  }
  
  // Call this function with the force of the shake 
  // and how long it should last      
  public void rumble(float power, float time) {
    random = new Random();
    this.power = power;
    this.time = time;
    this.current_time = 0;
  }
        
  public void tick(float delta, GameController gc, Hero hero){
      // GameController contains the camera
      // Hero is the character centre screen
    
    if(current_time <= time) {
      current_power = power * ((time - current_time) / time);
      // generate random new x and y values taking into account
      // how much force was passed in
      x = (random.nextFloat() - 0.5f) * 2 * current_power;
      y = (random.nextFloat() - 0.5f) * 2 * current_power;
      
      // Set the camera to this new x/y position           
      gc.camera.translate(-x, -y);
      current_time += delta;
    } else {
      // When the shaking is over move the camera back to the hero position
      gc.camera.position.x = hero.x;
      gc.camera.position.y = hero.y;
    }
  }      
}

This is all the code to achieve a basic screen shake. The timer for the affect works its way down to zero then stops. For large shakes once the rumble is over it will snap back to the character and look very jumpy but this is just a prototype.

To use the class create a new instance of it then conditionally produce a new RUMBLE! Below you see on the line snapping a small shake takes place by changing the power and time parameters, then the main render loop just needs to call the tick function:

public Rumble  rumble;
this.rumble = new Rumble();

if (line.tension > line.max_tension){ // LINE SNAP
  gc.rumble.rumble(.2f, .1f); 
  state = STATE.IDLE;
}

if (gameController.rumble.time > 0){
  gameController.rumble.tick(delta, gameController, hero);
}

So there you go a nice feature to add to any game that could do with some atmosphere or excitement, could be progressed much further and also be used in loads of ways, great for explosions, thunder storms etc.

Thanks for reading !_!

LibGDX Lighting – Day / Night cycle

Recently researched the use of a Shader in libGDX to create a simple day/night cycle. Found some basic tutorials to create a fire at night affect including: Lightmap Shader This basically adds a tint to the background and overlays an image to create a spotlight.

Initiating vars etc:

Vector3 bright = new Vector3(6.3f, 6.3f, 6.7f);
// Load shaders from text files
vertexShader = Gdx.files.internal("data/shaders/vertexShader.glsl").readString();
defaultPixelShader = Gdx.files.internal("data/shaders/defaultPixelShader.glsl").readString();
finalPixelShader =  Gdx.files.internal("data/shaders/pixelShader.glsl").readString();

ShaderProgram.pedantic = false;
defaultShader = new ShaderProgram(Art.vertexShader, Art.defaultPixelShader);
finalShader = new ShaderProgram(Art.vertexShader, Art.finalPixelShader);currentShader = finalShader;
ambientColor = bright;
 
finalShader.begin();
finalShader.setUniformi("u_lightmap", 1);
finalShader.setUniformf("ambientColor", ambientColor.x, ambientColor.y, ambientColor.z, ambientIntensity);
finalShader.end();
// Image for spot light 
light = new Texture(Gdx.files.internal("data/shaders/light.png"));
fbo = new FrameBuffer(Format.RGBA8888, 1024, 788, false);

finalShader.begin();
finalShader.setUniformf("resolution", 1024, 788);
finalShader.end();

Render Loop
After setting up the variables and shader files in the render loop I adjusted the ambientColor over time to give affect of night day.

// Adjust ambientColor to give appearance of night/day  
finalShader.begin();
finalShader.setUniformi("u_lightmap", 1);
finalShader.setUniformf("ambientColor", ambientColor.x, ambientColor.y, ambientColor.z, ambientIntensity);
finalShader.end();

// I added logic to only show spotlight during night
if(show_light){
  fbo.begin();
  fbo.getColorBufferTexture().bind(1);
  light_batch.setShader(defaultShader);
  light_batch.begin();
  light.bind(0);
  light_batch.draw(light, hero.x-l_off+.4f,hero.y-l_off+.2f, light_size,light_size);
  light_batch.end();
  fbo.end();
}
       
// Draw your map here
light_batch.setShader(currentShader);
light_batch.begin();
MapGenerator.draw(gameController.camera, light_batch);
light_batch.end(); 

Night

 Evening
This solution limited me to using one spot light, also my knowledge of OpenGL Shader language is zero. At this point I went back to the LibGDX documentation and came across Box2dLights, a library that uses collision data from Box2D to create lights/shadows.
// BOX2DLIGHTS
private PointLight spriteLight;
private RayHandler rayHandler;

// Create a new Box2D World, this is required. 
World world = new World(new Vector2(), true); 
RayHandler.useDiffuseLight(true);
  
// Setup the new RayHandler, it will use the same camera as the main game
rayHandler = new RayHandler(world);
rayHandler.setCulling(true);
rayHandler.setCombinedMatrix(gameController.camera.combined);
rayHandler.setAmbientLight(1);
 
// Light to follow the hero
spriteLight = new PointLight(rayHandler, 50);
spriteLight.setPosition(hero.x,hero.y);
spriteLight.setDistance(5);
spriteLight.setColor(3, 12, 33, 0.3f);
// Keep the unique ID of the light  
hero_light = spriteLight.hashCode();

// this lights the map (Sun)  
spriteLight = new PointLight(rayHandler, 50);
spriteLight.setPosition(hero.x-20,hero.y-20);
spriteLight.setDistance(250);
spriteLight.setColor(3, 12, 33, 0.5f);
 
// Test shadow being cast by solid object 
PolygonShape tileShape = new PolygonShape();
tileShape.setAsBox(.5f, .5f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = tileShape;
fixtureDef.filter.groupIndex = 0;
BodyDef tileBodyDef = new BodyDef();
float bodyX = hero.x-3;
float bodyY = hero.y-4f;
tileBodyDef.position.set(bodyX, bodyY); 
tileBodyDef.type = BodyType.StaticBody;
Body tileBody = world.createBody(tileBodyDef);
tileBody.createFixture(fixtureDef);

// RENDER LOOP CODE
rayHandler.setCombinedMatrix(gameController.camera.combined, gameController.camera.position.x, gameController.camera.position.y,gameController.camera.viewportWidth, gameController.camera.viewportHeight);
rayHandler.updateAndRender();

Here I set up some basic lights, a small one for the hero and a large light to act as the sun, I added one solid object to show a shadow being cast. Would need to add bodies for each object in the game and update there positions. Here the alpha is set to low on the sun light to give impression of night:

Zoomed out, earlier in the day:
Multiple Lights

Accessing and looping through all lights is simple, we stored the hashcode of the hero light so on each render loop update its position, else change the alpha value; increase/decrease this value to simulate night to day and vice versa.

for (Light light : rayHandler.lightList) {
 if (light.hashCode() == hero_light){
  light.setPosition(hero.x,hero.y); 
 }else{
  light.setColor(1, 1, 1, ambientIntensity);
 }
}

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

 

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 18×18 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.