- LibGDX Game Development By Example
- James Cook
- 1316字
- 2021-07-16 20:35:55
Game update cycle
Before we jump straight into some coding action, let's first take a look at a couple of core classes that will make our lives easier. When you created your project with the setup tool, the core of the game, the MyGDXGame
class, which is the default name of the class, extends a class called ApplicationAdapter
. This in turn implements an interface called ApplicationListener
. Now, you might think these are good enough for us to get going; however, there is a better class that we can extend and that is the Game
class.
What is so special about this class? Essentially, it is ApplicationListener
that delegates the game to a screen. Every bar method, such as onCreate()
, is implemented. This will save us lots of time going forward.
The following code is the Game
class from the LibGDX framework:
public abstract class Game implements ApplicationListener { protected Screen screen; @Override public void dispose () { if (screen != null) screen.hide(); } @Override public void pause () { if (screen != null) screen.pause(); } @Override public void resume () { if (screen != null) screen.resume(); } @Override public void render () { if (screen != null) screen.render(Gdx.graphics.getDeltaTime()); } @Override public void resize (int width, int height) { if (screen != null) screen.resize(width, height); } public void setScreen (Screen screen) { if (this.screen != null) this.screen.hide(); this.screen = screen; if (this.screen != null) { this.screen.show(); this.screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); } } public Screen getScreen () { return screen; } }
As we can see in the preceding code, the Game
class is abstract, this will require us to provide our own implementation. Then, as mentioned earlier, it delegates life cycle calls to the Screen
class.
The Screen
class is used to define what a player is looking at, such as the main menu or the game screen. It has various methods that may be overridden. Let's take a look at the following code snippet:
public interface Screen { public void show (); public void render (float delta); public void resize (int width, int height); public void pause (); public void resume (); public void hide (); public void dispose (); }
It has the same method signature as the ApplicationListener
class. However, there is an additional method, show()
, which is called when the screen becomes the current screen in the game.
We wouldn't want from implement all those methods every time we wanted to create a Screen
class implementation. Luckily, LibGDX has an adapter class, ScreenAdapter
, which is purely for convenience and contains zero logic. It implements the methods with empty bodies. I won't show the code structure here, I will leave it to you to look it up if you like.
Out of the life cycle methods that are mentioned here, we are only interested in a couple of these to start off with, show()
and render()
.
The render()
method is called on every cycle. By default, this is 60 times a second. This is configurable; however, we are happy with 60fps (frames per second) for now. In the default project, you will see that there is some interesting code already. What's happening here is that, with every frame, the screen is being cleared with the background color, which is red in this case, and rendering the LibGDX logo from scratch. This is achieved with the calls to glClearColor()
and glClear()
. Later, we will look at how we can clear with other colors.
Let's get our Game
class up and running. Initially, it will not do much, but it will set us up to make our game.
First, let's generate a new project. This time, we will use some proper names as opposed to the defaults. To create the Snake game, we set the tool as follows:

Once you have the project that is generated from the LibGDX setup application, import it into your IDE; if you are using Eclipse, refer to the previous chapter.
The Game
class that is generated for you extends ApplicationAdapter
by default.
public class SnakeGame extends ApplicationAdapter {
Let's change the extended class to Game
:
public class SnakeGame extends Game {
Ensure that the imports are updated at the top of the class:
import com.badlogic.gdx.Game;
You will now notice that, essentially, nothing has changed. If you run the project again—via DesktopLauncher
—it will still show the red screen with the LibGDX logo.
But why is this happening? We haven't set a Screen
class for game object to use. The keen-eyed among you will have spotted that this is because we are still overriding the render()
method. Thus, the delegation to the Screen
class is not happening.
Before we remove the override, let's create our Screen
class. Create a class called GameScreen
and make it extend by the class ScreenAdapter
:
public class GameScreen extends ScreenAdapter {
As all the interface methods are implemented in the ScreenAdapter
class, you will notice that the IDE does not request that you implement anything.
Let's return to our SnakeGame
class and remove the default project example code, so all we are left with is the create()
method's override:
public class SnakeGame extends Game { @Override public void create() { } }
In the create()
method, we can set a new instance of our GameScreen
method:
public class SnakeGame extends Game { @Override public void create() { setScreen(new GameScreen()); } }
If you run the project again, this time you will see that we just have a black screen; however, now the rendering is coming from the screen. Let's draw something on the screen!
Texture rendering
Now we have a blank screen, but let's make our screen do something! To start off with, let's put the default project code—the lovely LibGDX logo—onto the screen. You will notice that we don't have a create()
method to put the object initialization in. We do, however, have a show()
method. Let's put it in there. So now your GameScreen
class should look something like this:
public class GameScreen extends ScreenAdapter { private SpriteBatch batch; private Texture img; @Override public void show() { batch = new SpriteBatch(); img = new Texture("badlogic.jpg"); } @Override public void render(float delta) { Gdx.gl.glClearColor(1, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); batch.draw(img, 0, 0); batch.end(); } }
If you run the project again, you will see we are back to where we started. Before we go any further, I am going to provide a little explanation to what is going on, in the code, here.
Next we need something that will draw our textures; this is where the batch
classes come in. A Batch is used to draw 2D rectangles that reference a texture. Among the different Batch class implementations is SpriteBatch, which is the one we will use for our game.
A texture is a bitmap image that gets drawn on the screen through mapping. The texture class wraps an OpenGL texture without having to worry too much about the internal workings of OpenGL—remember we are here to make games!
When using the texture
class, we should ensure that our textures are managed; by this, we mean that if the OpenGL context is lost, for example, that loss can happen by the user switching to another application, then our managed textures will automatically get reloaded for us. Excellent!
Everything we have talked about so far, somewhere in the inner workings of LibGDX, holds on to real resources, such as memory. To ensure that our games are well behaved and do not eat all available system memory, we have to remember to dispose of our SpriteBatch and textures when we are done using them. You will notice that they all have a dispose()
method in them. When called, this will release all resources associated with that object. The Screen
class has a dispose()
method. We will look at that later on.