web analytics
Paste your Google Webmaster Tools verification code here

Game Programming using Android Studio and GDX lib – Part II

libGDX

Introduction

In Part I of this series, we discussed how to set up the GDX library template project to start programming our game.  In this tutorial, we’ll start to dive into the game structure, creating a simple animation, responding to touch on the Android, and playing sound.  When we have finished the tutorial, you will have a simple explosion that occurs when you touch your finger to your tablet or phone.

Game Structure

When we created our Android gdx game template in Part I, it created a class in which we can put all of the code we need to perform our game functions.  The class extends the base class ApplicationAdapter, and we can override the create and render functions to initially create a simple bitmap and render it on the screen.  Luckily, most of this code is generated for you to get you started. The create method of the ApplicationAdapter gives us a place to create all our images, sounds, and other media items.  The render method gives us a place to draw the media element of the game.  The render method is called every .025 seconds by the game loop.  In this method we can move images, update animations, and other screen rendering tasks. The Texture class allows us to load an image file from the assets folder and render it to the screen.  We create the texture we want to use inside of the create method, and we draw the image in the render method.  Generally, its a good idea to put all images you are going to render into something called a SpriteBatch.  The SpriteBatch, batches up all images to render and draws them all at once.  This is a much more efficient way to render images in a game then to render them individually.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyFirstGDXTemplate extends ApplicationAdapter {
 
    Texture img;
    SpriteBatch batch;
 
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("player.png"); // the texture is loaded from the player.png file in the assets folder
      }
 
    @Override
    public void render () {
 
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 
        batch.begin();
        batch.draw(img, 100, 100);
        batch.end();
    }
}
public class MyFirstGDXTemplate extends ApplicationAdapter {

    Texture img;
    SpriteBatch batch;

    public void create () {
        batch = new SpriteBatch();
        img = new Texture("player.png"); // the texture is loaded from the player.png file in the assets folder
      }

    @Override
    public void render () {

        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.begin();
        batch.draw(img, 100, 100);
        batch.end();
    }
}

Handling Touch

In many games, the tablet responds to touch when you place your finger on the device.  The gdx library gives us a way to deal with touch through an interface called the InputProcessor.  When we implement the InputProcessor  on our game class, Android studio prompts us to generate all the interface methods to deal with input.  The following is generated for the InputProcessor interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.mygdx.game;
 
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
 
public class MyFirstGDXTemplate extends ApplicationAdapter implements InputProcessor {
 
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("player.png");
 
    }
 
    @Override
    public void render () {
 
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 
        batch.begin();
        batch.draw(img, 100, 100);
 
    }
 
    @Override
    public boolean keyDown(int keycode) {
        return false;
    }
 
    @Override
    public boolean keyUp(int keycode) {
        return false;
    }
 
    @Override
    public boolean keyTyped(char character) {
        return false;
    }
 
    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
 
    }
 
    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }
 
    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }
 
    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }
 
    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}
package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;

public class MyFirstGDXTemplate extends ApplicationAdapter implements InputProcessor {

    public void create () {
		batch = new SpriteBatch();
		img = new Texture("player.png");

    }

	@Override
	public void render () {

		Gdx.gl.glClearColor(1, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.begin();
		batch.draw(img, 100, 100);

	}

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {

    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

If we run this code on our Android Device in Debug mode and set a breakpoint in the touchDown method that is generated, we see that the program stops in this method when we touch the screen.  We can set our touch coordinates inside this method to use inside our game.

Creating an Animation explosion

Animations are created from images that contain each sequence of the animation.  The TextureRegion class can be used to pull each sub-image of the explosion in the order it animates.  It will pull each image starting from the top left corner and moving right, then moving to the next row when its got the last image in the row until its pulled all 15 images.  Once these images are parsed out, they can be added to the Animation class that will be performing the animation.  In the create method you would add the following.

1
2
3
4
5
6
7
8
9
10
 explosionSheet = new Texture(Gdx.files.internal("explosion.png")); // explosion image sheet shown above
        TextureRegion[][] textureRegions = TextureRegion.split(explosionSheet, explosionSheet.getWidth()/FRAME_COLS, explosionSheet.getHeight()/FRAME_ROWS);              // #10
        explosionFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
        int index = 0;
        for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLS; j++) {
                explosionFrames[index++] = textureRegions[i][j];
            }
        }
        explosionAnimation = new Animation(0.025f, explosionFrames);
 explosionSheet = new Texture(Gdx.files.internal("explosion.png")); // explosion image sheet shown above
        TextureRegion[][] textureRegions = TextureRegion.split(explosionSheet, explosionSheet.getWidth()/FRAME_COLS, explosionSheet.getHeight()/FRAME_ROWS);              // #10
        explosionFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
        int index = 0;
        for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLS; j++) {
                explosionFrames[index++] = textureRegions[i][j];
            }
        }
        explosionAnimation = new Animation(0.025f, explosionFrames);

To perform the explosion in the render method, you need to keep track of the state of the animation.  When you want to animate an explosion, each time the render method is entered, you need to increment the state of the animation to pull the next image. We use a method called getDeltaTime, which gets the next time increment of the game and add it to the current stateTime. Note the code below will also draw the animation where the user touches the screen. We’ll talk more about this in the next section.  Also note that explosionAnimation has a method getKeyFrame.  The first parameter of this method takes the current stateTime to determine which image in the animation sequence to render.  The second parameter indicates whether or not we are looping the animation.  In this example we are not looping, we are  just going through the 15 image sequence one time.  Let’s take a look at the the if statement around the playing of the explosionAnimation.  Inside the if statement, the Animation class has a nice method called isAnimationFinished to allow us to determine when the animation has finished its full sequence.

1
2
3
4
5
6
 stateTime += Gdx.graphics.getDeltaTime(); 
  if (!explosionAnimation.isAnimationFinished(stateTime) && explosionHappening) {
              currentFrame = explosionAnimation.getKeyFrame(stateTime, false);  // #16
             camera.unproject(touchPoint.set(touchCoordinateX, touchCoordinateY, 0));
             batch.draw(currentFrame, touchPoint.x, touchPoint.y);
         }
 stateTime += Gdx.graphics.getDeltaTime(); 
  if (!explosionAnimation.isAnimationFinished(stateTime) && explosionHappening) {
              currentFrame = explosionAnimation.getKeyFrame(stateTime, false);  // #16
             camera.unproject(touchPoint.set(touchCoordinateX, touchCoordinateY, 0));
             batch.draw(currentFrame, touchPoint.x, touchPoint.y);
         }

Triggering the Explosion off of a Touch

In a previous section, we talked about the touch InputProcessor interface.  What we want to happen, is as soon as the user touches the screen, the explosion animation occurs. In  other words, all 15 frames are played.  In the touchDown method of the InputProcessor, we’ll want to kick off our explosion.

1
2
3
4
5
6
7
8
 @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        touchCoordinateX = screenX;
        touchCoordinateY = screenY;
        stateTime = 0;
        explosionHappening = true;
        return true;
    }
 @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        touchCoordinateX = screenX;
        touchCoordinateY = screenY;
        stateTime = 0;
        explosionHappening = true;
        return true;
    }

This method captures the touch coordinates where we want the explosion to happen. It also resets the animation stateTime so that we start our explosion at the beginning of the sequence.  Finally it sets a flag that we have are in the process of an explosion.

Camera Coordinates

Touch coordinates are returned in screen coordinates, so we need to translate them back to world coordinates.  For this we require a camera.  Camera’s have all kinds of cool uses, but for this demonstration, we are just using it to translate our touch coordinates to match where are finger touches on the screen so we can draw our animation in the correct place.  First we need to initialize the camera in our create method shown below:

1
2
3
4
5
6
7
8
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(camera.viewportWidth * .5f, camera.viewportHeight * .5f, 0f);
 
<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;">To initialize the camera, we need to construct the camera with the width and height of the graphic area.  Then we need to set the  camera position to be smack in the middle of the screen.  The camera uses 3D coordinates, but we are only concerned with the X and Y coordinates for the explosion, so we set the Z position to zero and the x and y coordinates of the camera to the screens midpoint.
 
Now that we have our camera created the way we want it, we can unproject the touch points in the render method to reflect the game world coordinates using a Vector3 class .  The touchPoint, which is the instance of the Vector3 class,  can then be used to set the animation location.
 
</span>
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(camera.viewportWidth * .5f, camera.viewportHeight * .5f, 0f);

<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;">To initialize the camera, we need to construct the camera with the width and height of the graphic area.  Then we need to set the  camera position to be smack in the middle of the screen.  The camera uses 3D coordinates, but we are only concerned with the X and Y coordinates for the explosion, so we set the Z position to zero and the x and y coordinates of the camera to the screens midpoint.

Now that we have our camera created the way we want it, we can unproject the touch points in the render method to reflect the game world coordinates using a Vector3 class .  The touchPoint, which is the instance of the Vector3 class,  can then be used to set the animation location.

</span>
1
2
camera.unproject(touchPoint.set(touchCoordinateX, touchCoordinateY, 0));
batch.draw(currentFrame, touchPoint.x, touchPoint.y);
camera.unproject(touchPoint.set(touchCoordinateX, touchCoordinateY, 0));
batch.draw(currentFrame, touchPoint.x, touchPoint.y);

 Making a Boom!

The explosion wouldn’t just seem like an explosion without a sound to accompany it.  Making a sound in gdx lib is very easy.  In our create method we simply create a new Sound object.  The sound file (boom.m4a) that it accesses needs to be placed in the assets folder generated for the project. 

1
sound = Gdx.audio.newSound(Gdx.files.internal("boom.m4a"));
sound = Gdx.audio.newSound(Gdx.files.internal("boom.m4a"));

In the touch method we’ll simply play the sound when the user touches the screen as well as kick off the explosion animation:

1
2
3
4
5
6
7
8
9
@Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        sound.play();
        touchCoordinateX = screenX;
        touchCoordinateY = screenY;
        stateTime = 0;
        explosionHappening = true;
        return true;
    }
@Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        sound.play();
        touchCoordinateX = screenX;
        touchCoordinateY = screenY;
        stateTime = 0;
        explosionHappening = true;
        return true;
    }

Conclusion

In order to create a game, we first need to get familiar with the tools available in the gdx library for game creation.  In this second tutorial we became familiar with drawing images,  animations, detecting touch, and playing sounds.  In the next tutorial we will continue to create our game and make the images interact with each other.


Mike is a software engineer with a love for tinkering with smart phone devices. He spends a lot of time moving pictures to his SD card, because the Android keeps running out of memory. In his spare time, he travels to different parts of the world and takes one of his Android devices with him.

Share

Share This Post

Related Articles

6 Responses to “Game Programming using Android Studio and GDX lib – Part II”

  1. Victor says:

    Nice tutorial looking for part 3

  2. BK says:

    Do you need to set explosionHappening = false; somewhere? if so where can we set it?

  3. Corbin says:

    needs: camera.update();
    after setting its postition.

    also needs: Gdx.input.setInputProcessor(this);
    somewhere in the create method

  4. woag says:

    I take tutorial 3 is never coming?

  5. Fandi says:

    1. You should put link to your tutorial 3 here.
    2. You might want to provide source code download.
    3. The render function needs camera.update(); to work properly.
    4. Might as well put sound = Gdx.audio.newSound(Gdx.files.internal(“boom.mp3”));
    5. And also explosionFrames= new TextureRegion[FRAME_ROWS * FRAME_COLS];

    That could get people understand the tutorial faster i think.

Leave a Reply

*

© 2016 ToDroid. All rights reserved.
Disclaimer: The content on this site is copyrighted. Do not copy the content. The content on this site must not be reproduced anywhere else.