How to Create a Simple Android Game with AndEngine

This is a blog post by iOS Tutorial Team member Ali Hafizji, an iOS and Android developer working at Tavisca Solutions. In this tutorial, you’re going to get hands-on experience making a simple game on Android using AndEngine, a popular and easy to use game framework. There are many frameworks you can use to make […] By Ali Hafizji.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Loading Game Assets to VRAM

Now that you’ve initialized an instance of the engine, you can load all the assets required by the Tower of Hanoi game into memory. First download the game assets here.

Next create a new folder within the assets folder already present in your project. To do this, right-click on the assets folder and select New->Folder, name the folder “gfx” and copy all the downloaded assets to that folder.

To load these assets, we’re going to add the onCreateResources method. But as you might guess, our new code references several other classes for which we need to add imports. So add the following at the top of the file below the rest of the import statements:

import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.bitmap.BitmapTexture;
import org.andengine.util.adt.io.in.IInputStreamOpener;
import org.andengine.util.debug.Debug;

import java.io.IOException;
import java.io.InputStream;

Now, replace the placeholder content in onCreateResources with the following:

try {
    // 1 - Set up bitmap textures
    ITexture backgroundTexture = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
            return getAssets().open("gfx/background.png");
        }
    });
    ITexture towerTexture = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
            return getAssets().open("gfx/tower.png");
        }
    });
    ITexture ring1 = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
            return getAssets().open("gfx/ring1.png");
        }
    });
    ITexture ring2 = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
            return getAssets().open("gfx/ring2.png");
        }
    });
    ITexture ring3 = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
            return getAssets().open("gfx/ring3.png");
        }
    });
    // 2 - Load bitmap textures into VRAM
    backgroundTexture.load();
    towerTexture.load();
    ring1.load();
    ring2.load();
    ring3.load();
} catch (IOException e) {
    Debug.e(e);
}

In the above code, you first create an ITexture object. ITexture is an interface. An object of this type is initialized to a BitmapTexture object, which, you guessed it, is used to to load a bitmap into VRAM. The above code creates ITexture objects for all the assets you downloaded, and loads them into VRAM by calling the load method on each object.

Now that you have all your assets loaded, you need to extract TextureRegions from your textures. Think of a texture as a giant canvas that has to have width and height values which are a power of 2 (a requirement of OpenGL ES). A TextureRegion, on the other hand, is a part or a region of a texture that does not have to have dimensions which are a power of 2.

Note: Instead of creating textures for each of your assets, you could have loaded all the assets into one texture and extracted the individual assets as TextureRegions. Doing this is out of scope for this tutorial, but I may cover it in detail in a future tutorial.

As you might guess, we have to add a few new import statements first:

import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;

Now, to hold the TextureRegions, add private variables to our class (again, at the top of the file, below the previous private variables):

private ITextureRegion mBackgroundTextureRegion, mTowerTextureRegion, mRing1, mRing2, mRing3;

Finally, add these lines of code to onCreateResources, right after the end of section #2 where you load the bitmap textures into VRAM:

// 3 - Set up texture regions
this.mBackgroundTextureRegion = TextureRegionFactory.extractFromTexture(backgroundTexture);
this.mTowerTextureRegion = TextureRegionFactory.extractFromTexture(towerTexture);
this.mRing1 = TextureRegionFactory.extractFromTexture(ring1);
this.mRing2 = TextureRegionFactory.extractFromTexture(ring2);
this.mRing3 = TextureRegionFactory.extractFromTexture(ring3);

The above code initializes your TextureRegions using the textures that you already loaded into VRAM.

Creating the Game Scene

It’s finally time to create the game scene! Of course, we need another new import:

import org.andengine.entity.sprite.Sprite;

Next, replace the placeholder content in onCreateScene with the following:

// 1 - Create new scene
final Scene scene = new Scene();
Sprite backgroundSprite = new Sprite(0, 0, this.mBackgroundTextureRegion, getVertexBufferObjectManager());
scene.attachChild(backgroundSprite);
return scene;

The above code first creates a Scene object. Next you create a sprite called backgroundSprite and attach the sprite to the scene. Notice that this method requires you to return the scene object. Think of a scene as a container with a number of layers, and each layer can have many sprites (TextureRegions) placed within it.

When creating a Sprite object, you pass four parameters. Here’s a brief description of each parameter:

  • xCoordinate: Defines the X-position of the sprite. The AndEngine coordinate system considers the top-left point as the origin.
  • yCoordinate: Defines the Y-position of the sprite.
  • TextureRegion: Defines what part of the texture the sprite will use to draw itself.
  • VertexBufferObjectManager: Think of a vertex buffer as an array holding the coordinates of a texture. These coordinates are passed to the OpenGL ES pipeline and ultimately define what will be drawn. A VertexBufferObjectManager holds all the vertices of all the textures that need to be drawn on the scene.

Compile and run the application. You should see something like this:

Nice, we’re starting to see something! However, this platform does look a little bit desert-ed (groan) ;]

The Three Towers

It’s time to add the sprites for the towers and rings – the final step before getting things moving with the game logic. Start by adding three private variables to the class. Declare the variables as follows:

private Sprite mTower1, mTower2, mTower3;

Next add the following lines of code to onCreateScene, right before the final return statement:

// 2 - Add the towers
mTower1 = new Sprite(192, 63, this.mTowerTextureRegion, getVertexBufferObjectManager());
mTower2 = new Sprite(400, 63, this.mTowerTextureRegion, getVertexBufferObjectManager());
mTower3 = new Sprite(604, 63, this.mTowerTextureRegion, getVertexBufferObjectManager());
scene.attachChild(mTower1);
scene.attachChild(mTower2);
scene.attachChild(mTower3);

You’ve defined three sprites, each using the TextureRegion of the tower that you loaded in onCreateResources.Then you added these sprites to your scene. That’s all there is to it!

Compile and run. You should now see the three towers placed in their proper positions.

And One Ring to Bind Them

Let’s talk a little about the game logic before you create your rings. Think of the towers as three stacks (I mean the data structure) – you can only remove the top-most element, and when you add an element it will always be on top. You’ll use these stacks when you write the game logic code.

To create the rings, we need to first make a custom class that will extend Sprite. You do this because every ring needs to know which stack it belongs to.

Right-click on the folder containing TowerOfHanoiActivity.java and select New->Class. You should see a dialog which you should fill in similar to the following:

Andengine4

Note that you probably would have “Source folder” and “Package” filled in automatically. All you’d need to do is type in the “Name” and click “Browse…” next to “Superclass” to find the Sprite class from AndEngine. That should create a Java file called “Ring.java.” Place the following code within the class implementation (after the public class line and before the closing curly brace):

    private int mWeight;
    private Stack mStack; //this represents the stack that this ring belongs to
    private Sprite mTower;

    public Ring(int weight, float pX, float pY, ITextureRegion pTextureRegion, VertexBufferObjectManager pVertexBufferObjectManager) {
        super(pX, pY, pTextureRegion, pVertexBufferObjectManager);
        this.mWeight = weight;
    }

    public int getmWeight() {
        return mWeight;
    }

    public Stack getmStack() {
        return mStack;
    }

    public void setmStack(Stack mStack) {
        this.mStack = mStack;
    }

    public Sprite getmTower() {
        return mTower;
    }

    public void setmTower(Sprite mTower) {
        this.mTower = mTower;
    }

Most of the code here is pretty straightforward. The object has three private variables. One is used to keep track of the weight of the tower; this is an integer value, i.e., the higher the value, the bigger the ring. The other two variables are used to store the stack that the ring belongs to and the tower on which it is currently placed.

You’ll also need to add the following import statements to the top of the file:

import java.util.Stack;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;

Now that we have the Ring class, to create and add the rings, add the following lines of code to onCreateScene, right before the return statement:

// 3 - Create the rings
Ring ring1 = new Ring(1, 139, 174, this.mRing1, getVertexBufferObjectManager());
Ring ring2 = new Ring(2, 118, 212, this.mRing2, getVertexBufferObjectManager());
Ring ring3 = new Ring(3, 97, 255, this.mRing3, getVertexBufferObjectManager());
scene.attachChild(ring1);
scene.attachChild(ring2);
scene.attachChild(ring3);

Compile and run to test.

Andengine5

You’ll notice that the rings are now on the first tower but you can’t move the rings. That’s because we haven’t worked out the game logic for placing and moving the rings. So that’s what you’ll do next :]

Ali Hafizji

Contributors

Ali Hafizji

Author

Over 300 content creators. Join our team.