libGDX Eample
libGDX Eample
Game design is hard, but if you break up the process into small, achievable goals,
you’ll be able to produce wonders. In this simple game tutorial, you will learn how to make a basic
game from scratch. These are the essential skills that you will build on in future projects. You may
watch the video tutorial, however you should come back here for the code examples.
As you can see with the live demo, we’re going to make a basic game where you control a bucket to
collect water droplets falling from the sky. There is no score or end goal. Just enjoy the experience!
Here are the steps that we will use to split up the game design process:
Prerequisites
Loading Assets
Rendering
Input Controls
Game Logic
Further Learning
PrerequisitesPermalink
There are a few things that you need to do before you begin this tutorial.
Make sure to follow the setup instructions on [Link] to configure Java and your IDE. You
need to know how to create a project and run it with the appropriate Gradle commands.
Package: [Link]
Include the Core and Desktop platforms. You may include others, however they will not be
discussed in this tutorial. Choosing other platforms at this stage can introduce new issues
you are not prepared for.
Open the project in your chosen IDE. If you have a knowledge of Java code, your experience in
libGDX will be a lot easier. However, you should still be able to follow along in this tutorial even if you
only have a minimal understanding of how code works.
Comments will be used throughout the code examples to explain the facets of this tutorial. You do
not have to copy these comments when writing your code:
Import statements are an important part of Java programming. Thankfully, they are automatically
added by modern IDE’s as you type your code. They are omitted in the examples, but assume they
are necessary in your code. They appear at the top of the file under the package statement.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
There are times where something named in libGDX is named the same as something found in
another package. As you type Rectangle in IDEA, for example, it will prompt you to press alt+enter to
autocomplete the import. Always opt for the libGDX named class in the subsequent menu. These are
usually in the package [Link]
Decimal numbers in OpenGL based games (like those made with libGDX) are usually described with
floating point variables like 22.5f. Forgetting the “f” can cause build errors. float is preferred
over double (such as 22.5) because it uses less memory, it’s what’s supported by most hardware, and
it’s what OpenGL usually expects. You can check what parameters a method expects by
pressing ctrl+p in IDEA.
Whenever you see ellipses ... in the code examples below, assume that other code has been removed
for brevity. Use the context of the lines you can see to figure out where you should be in the file. If
you’re completely lost, the complete example is listed at the bottom.
Before we can test our game, we should set the size of the desktop window. Any configuration that
needs to happen for the desktop version of your game needs to be set in the LWJGL3Launcher class.
Find this file in the project folder:
Copy code...
[Link]("Drop");
[Link](true);
[Link]([Link]().refreshRate +
1);
return configuration;
Loading AssetsPermalink
2D games made in libGDX need assets: images, audio, and other resources that comprise the project.
In this case, we’ll need a bucket, a raindrop, a background, a water drop sound effect, and music. If
you’re pretty resourceful, you can make these on your own. For simplicity’s sake, you can download
these examples which are optimized for this tutorial.
[Link]
[Link]
[Link]
drop.mp3
music.mp3
Just having these saved on your computer is not enough. These files need to be placed in the assets
folder of your project. Look inside the project folder:
There are many folders in here for the different backends that libGDX supports. Assets is a folder
shared by all the backends. Whatever you save in here gets distributed with your game. For example,
your desktop game will include these files inside your JAR distributable. This is what you give your
users so they can play your game.
Note that file name casing and extensions are important in libGDX. There is a difference
between [Link], drop.mp3, and Drop.mp3. And annoyingly, this usually doesn’t break your game
until you try to make a release. Always refer to the in-editor project browser as file extensions are
hidden by default in the Windows File Explorer.
libGDX has an emphasis on code. Every asset you use must be loaded through code before you can
use it in the rest of your game. This needs to happen when the game starts. Open the Core project >
[Link]. This file is the main file we’re going to work in.
Declare your variables at the top of the file right underneath the public class Main line. You’ll need a
variable for every asset you plan to use:
Texture backgroundTexture;
Texture bucketTexture;
Texture dropTexture;
Sound dropSound;
Music music;
However, you should not create these objects at the constructor or init level. This would fail because
libGDX needs to load first. Enter the following code in the create method:
Copy code@Override
This loads the assets into memory after libGDX has started. See that the background image is loaded
as a texture. Textures are the way that games keep images in video ram. It’s actually not efficient to
have different textures for each element in the game. It should be one big Texture for them all. Learn
about TexturePacker in the wiki. For now, we’ll keep these as separate textures because it’s easier to
explain this way.
Similarly, we have Sound to handle the raindrop audio file in our project. Sounds are loaded
completely into memory so they can be played quickly and repeatedly. Music, on the other hand, is
too large to keep entirely in memory. It’s streamed from the file in chunks. There is no precise rule
about what should or should not be a sound versus a music, but you may consider any audio shorter
than 10 seconds to be a sound.
Copy code@Override
...
dropSound = [Link]([Link]("drop.mp3"));
music = [Link]([Link]("music.mp3"));
We have many assets to manage now. We should use an AssetManager to handle them. That can be
found in the wiki too. Again, that’s outside the scope of this tutorial. Let’s keep it simple.
The work we’ve done so far is in the create method. Create executes immediately when the game is
run, so of course it makes sense to load our assets there. What are these other methods for? The
libGDX life cycle lists these in more detail.
create(), render(), resize(int width, int height), pause(), resume(), and dispose() are all included in
your class because you are implementing the ApplicationListener interface. You will use these
methods to create your game and all future games you make in libGDX. You’ll find that a lot of
advanced systems you can use abstract the direct use of these methods, however these remain at
the foundation of your code.
Most of the code in this example will be in the create and render methods. For example, we won’t be
using dispose because it’s not necessary for us to clean up resources in a simple app like this. This is
more relevant for games with multiple screens.
RenderingPermalink
Now let’s talk about rendering. For the most part, all modern games just manipulate textures,
drawing them to the screen to give you the final image you see: the frame.
This process is repeated many times per second to give the illusion of motion. That’s what we’re
going to do here. Let’s start with some boilerplate code. What is meant by boilerplate code is that
you’ll use this same code again and again without much change. And you’ll see this pattern in all the
games you make. Declare new variables:
...
SpriteBatch spriteBatch;
FitViewport viewport;
Copy code@Override
...
A viewport controls how we see the game. It’s like a window from our world into another: the game
world. The viewport controls how big this “window” is and how it’s placed on our screen. There are
many kinds of viewports you can use. A simple one to understand is the FitViewport which will
ensure that no matter what size our window is, the full game view will always be visible. The
parameters determine how large our visible game world will be in game units. It will “fit” into the
window. Each viewport also has a camera which controls what part of the game world is visible and
at what zoom. Learn more about viewports and cameras in the wiki.
You should always remember to update the viewport in the resize method:
Copy code@Override
public void resize(int width, int height) {
Our code is going to get more complex now. A good practice is to divide your code into separate
methods. We’ll prepare for this by adding new methods to be used inside the render method:
Copy code@Override
input();
logic();
draw();
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link]();
[Link]([Link]); clears the screen. It’s a good practice to clear the screen every frame.
Otherwise, you’ll get weird graphical errors. You can use any color you want, but we’ll just settle on
Black this time.
Ever wonder why your favorite games sometimes have poor FPS or Frames Per Second? Stuttering
gameplay is often related to the number of textures being rendered and the capabilities of your
player’s graphics card. There are tricks to alleviate this. For one, it is more efficient to send all your
draw calls at once to the graphics processing unit (GPU). The process of drawing an individual texture
is called a draw call. The SpriteBatch is how libGDX combines these draw calls together.
It is important to order the begin and end lines appropriately. You should never draw from a
SpriteBatch outside of a begin and an end. If you do, you will get an error message.
Copy [Link]();
[Link]();
So, let’s do that. The coordinates we provide determine where the bucket will be drawn on the
screen. The coordinates begin in the bottom left and grow to the right and up. Our game world is
described in imaginary units best defined as meters. For reference our bucket is 100 pixels wide and
100 pixels tall. For simplicity, we will decide that 100 pixels will equal 1 meter, making our bucket 1x1
meters. This ratio of pixels per meter can be anything you want, but make sure whatever you choose
is a simple value that makes sense in your game world. This is typically the size of your tiles or the
height of the player character. Your game logic should really know nothing about pixels.
Add the line to draw the bucket:
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link]();
This code should now draw our bucket at the bottom of the screen in the lower left corner. You can
run this game by calling the appropriate Gradle command in IDEA or implement whatever steps are
needed for your chosen development environment as listed in the setup guide. If all things have
gone well, you should see our brave, lone bucket sitting in the darkness of the void.
Let’s cheer up this scene with the background. Drawing the background is similar to drawing the
bucket. It is drawn at the width/height of the viewport to ensure that the entire view is covered:
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link]();
You can run the game and you’ll see the background.
But what happened to our bucket? We need to talk about draw order. Drawing happens
consecutively in the order you list it in code. This is what really happens:
3. The background is drawn over everything. This final image is then shown on the screen.
This process is repeated every frame. To resolve this problem, we simply we need to reorder our
draw calls.
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link]();
Ensure that your game shows the background and the bucket. We’ll skip rendering the droplets for
now and return to it when we have the logic to create them.
Input ControlsPermalink
It’s not fun to have a game without some sort of movement or action on screen. Let’s enable the
player’s ability to control the bucket. As you know, there are all sorts of ways to get input from a user.
We’ll focus on a few: the keyboard, mouse, and touch.
We need some way of keeping track of where the player bucket is in the game world. Texture does
not store any position state. Sure, you can tell SpriteBatch where to draw it every frame by using the
provided overloaded methods. What if you want to rotate it? Resize it? These methods get incredibly
complicated the more you want to do.
Let’s use a Sprite instead. Sprite is capable of doing all these things and keeping state. This means
that it will remember its properties instead of you having to define them every frame.
Copy code@Override
...
Erase the [Link](bucketTexture, 0, 0, 1, 1); line for the bucket. The Sprite draw code is
written in a different way:
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link]();
If you run the game again, there shouldn’t be any difference in the output. That’s good! If you don’t
see the bucket, make sure you adjusted the line indicated above correctly.
KeyboardPermalink
Now to capturing player input. This is how you detect if a player is pressing keys on the keyboard.
This needs to happen in the input method
if ([Link]([Link])) {
This is known as keyboard polling. Every time a frame is drawn, we’re going to check if a key is
pressed. There is a list of pretty much every conceivable key in [Link]. We want to
react to the user pressing the right arrow key.
That’s great, but what is supposed to happen when the key is pressed? We need to move the
coordinates of the bucket sprite.
if ([Link]([Link])) {
The variable speed dictates how fast the bucket moves. Adding to the x makes the bucket move to
the right. This basically means “set the bucket x to what it currently is right now plus a little bit
more”. Subtracting from the x makes the bucket move to the left.
An unfortunate side effect of having our logic inside the render method is that our code behaves
differently on different hardware. This is because of differences in framerate. More frames per
second means more movement per second.
To counteract this, we need to use delta time. Delta time is the measured time between frames. If
we multiply our movement by delta time, the movement will be consistent no matter what hardware
we run this game on.
if ([Link]([Link])) {
This effectively means that the number we select here is how far the bucket moves in one second.
Remember to use delta time whenever you are calculating something that happens over time. Adjust
the number to a value that moves the bucket at an acceptable speed like 4f. Now let’s copy the code
for movement to the left. Flip the plus to a minus to move to the left.
if ([Link]([Link])) {
} else if ([Link]([Link])) {
}
Run the game again to make sure you can move the bucket left and right with the keyboard.
Mouse and Touch controls are related. To react to the user clicking or tapping the screen, call the
following method:
if ([Link]([Link])) {
[Link](speed * delta);
} else if ([Link]([Link])) {
[Link](-speed * delta);
Now the player has clicked the screen, but where did they click? We can use the methods
[Link]() and [Link]() for this. Unfortunately, these values are in window coordinates
which don’t correlate to our selected pixels per meter. The coordinates are also upside down
because Window coordinates start from the top left. We need to declare a Vector2 object to do some
math.
...
Vector2 touchPos;
Copy code@Override
...
}
Notice that we have created a single instance variable for the Vector2 instead of creating it locally. By
reusing this Vector2, we prevent the game from triggering the garbage collector frequently which
causes lag spikes in the game. This is how we use the Vector2 to move the bucket:
if ([Link]([Link])) {
[Link](speed * delta);
} else if ([Link]([Link])) {
[Link](-speed * delta);
if ([Link]()) {
This converts the window coordinates to coordinates in our world space. This code actually supports
mobile devices as well, however you should read about some other input features that libGDX
provides you. Run the game and click the screen to move the bucket.
Game LogicPermalink
The player can move left and right now, but they can go completely off the screen. We need to
prevent the player from doing that. libGDX provides some helpful methods in the MathUtils class.
We can achieve our goal by using the clamp() method. Remember that the left side of the screen
starts at 0. This code detects if the bucket goes too far left. If it does, it snaps its position at the
farthest it’s allowed to go. Add the following lines to the logic method:
Try the game out. This kind of works, but it lets the bucket go just a little too far right. In fact, it’s one
whole unit too far to the right. This is because the bucket sprite has an origin on the bottom left of
the image. To resolve this, we need to subtract the width of the bucket from the right edge.
Now to spawn the rain drops. We will have more than one raindrop, so we need a list to keep track of
them. Thankfully, libGDX has many useful collections to help with this. Declare the list:
...
Array<Sprite> dropSprites;
...
As before, it is advised to organize your code into methods. Create a new method to create a droplet.
Place it after your draw method.
...
}
private void createDroplet() {
float dropWidth = 1;
float dropHeight = 1;
[Link](dropWidth, dropHeight);
[Link](0);
[Link](worldHeight);
@Override
The size is the same as the player. Setting the y position at the top of the screen will make it appear
as if it’s falling from the sky. The [Link](dropSprite); line adds the drop to the list of drops
that we can manage in our render loop.
...
createDroplet();
Drawing each drop is pretty simple. Add the sprite drawing code to the draw method:
[Link]();
[Link]([Link]().combined);
[Link]();
[Link](spriteBatch);
[Link](spriteBatch);
[Link]();
If you run the program now, you’ll see nothing happen. That’s because the droplet doesn’t have any
movement code. Begin coding the logic for the droplets after the bucket logic:
We have a problem here. The rain drop only spawns on the left side every time. You could change the
position, of course, but there is no variability. No randomness. We need it to be a random position
between 0 and the width of the world.
float dropWidth = 1;
float dropHeight = 1;
[Link](dropWidth, dropHeight);
[Link](worldHeight);
[Link](dropSprite);
Again, we’re subtracting the width of the sprite so none of the raindrops appear outside of the view.
Success!
That’s only one droplet though. When it rains, we should have multiple droplets over the course of
time. Let’s move the droplet spawning code to the logic method. This will make droplets repeatedly
every frame. Cut the line from the create method:
[Link](-2f * delta);
createDroplet();
If you run this, you’ll see that we have a catastrophe! There are too many droplets.
There should be a delay between each spawn. Whenever we need something to be done repeatedly
over time with a delay, we can create a timer. Declare a new variable to store the time:
Copy codepublic class Main implements ApplicationListener {
...
float dropTimer;
dropTimer will keep track of how much time has elapsed between each spawn. Modify the code in
the logic method:
[Link](-2f * delta);
dropTimer accumulates the time that passes between every frame. If it’s been more than a second, it
will update the recorded time and proceed to create the droplet. This works as expected now.
These droplets will fall off the screen never to be seen again. Java doesn’t forget though. These
droplets will remain in memory forever. If you profile your game you’ll see that we have a memory
leak.
If the player would leave the game on for a really long time, it will crash. So, we should remove the
drop sprite from the list when it falls off screen. We need to make some considerable modifications
to the logic for loop. Erase your loop in the logic method:
[Link](-2f * delta);
// if the top of the drop goes below the bottom of the view, remove it
dropTimer += delta;
dropTimer = 0;
createDroplet();
Removing items in a list while you are iterating through it can cause some unforeseen bugs. That’s
why we are iterating through the list backwards so you don’t skip any indexes. Make sure to learn
about other collections available like the SnapshotArray and the DelayedRemovalArray for more
complex projects.
We have made great progress, however the drops don’t interact with the bucket. This is where we
incorporate some rudimentary collision detection. This can be achieved with the Rectangle class. We
need two rectangles to make comparisons. One for the bucket and one to be reused with every drop.
...
Rectangle bucketRectangle;
Rectangle dropRectangle;
Copy code@Override
...
The code now sets the rectangles to the position and dimensions of the Sprites.
[Link](-2f * delta);
dropTimer += delta;
if (dropTimer > 1f) {
dropTimer = 0;
createDroplet();
[Link](dropRectangle) checks if the bucket overlaps the drop. If it does, the Sprite
will be removed from the list of drop Sprites. That means it will no longer be drawn or acted upon. It
simply doesn’t exist anymore, making it look like the bucket collected it. Make sure your game works
as expected. You’re almost done!
It’s very easy to add a line to play a sound effect now that we are at the end of our workflow. We
want the drop sound (the sound effect loaded at the beginning of this tutorial) to play when the
bucket collides with the drop. It should not play when the drop falls out of the level.
[Link](-2f * delta);
[Link](i);
dropTimer += delta;
dropTimer = 0;
createDroplet();
The music should play at the beginning of the game. It needs to loop continuously until the player is
done playing the game. The file is also a little loud, so it should play at half volume. Volume is a value
from 0f to 1f with 1f being the normal volume of the file.
Copy code@Override
...
[Link](true);
[Link](.5f);
[Link]();
Further learningPermalink
So, you’re at the final steps of making a game. You should test the game out. Tweak values to make
the game easier or harder. This can be done by changing how fast the bucket moves and what rate
the droplets spawn.
If you want to let your friends and colleagues try your game out, you’ll need to make a distributable
that they can play. No one is going to want set up an IDE and copy your entire project just to play it.
See the page on Deploying your application.
Now that you’ve completed the simple game, it’s time to extend the simple game. This project
managed to put all of its code in a single class. This was in the service of making it simple, but it is a
terrible way to organize code. The next tutorial will teach you about the Game class and how to
implement Screen to arrange your project. It will also cover other important improvements to your
game. For example, these instructions skipped the use of the dispose() method because it’s not
relevant for single page project. When working with multiple screens, you may want to dispose of
resources from the last screen to release the memory for new resources in your game.
Game design is a constant journey of learning. The wiki goes further in depth regarding all the
subjects you have learned here. Look into collections, TexturePacker, AssetManager, audio, memory
management, and user input.
This tutorial focused entirely on desktop development. There are many more considerations you
must make before you explore Android, iOS, and HTML5 development. There is an extensive article
on considerations for HTML5, for example. Java is not truly “write once, run anywhere” but libGDX
takes you pretty close to that goal.
The following is the full example code of the game described throughout this tutorial. It’s here for
reference if you get stuck on any of the steps. Don’t cheat yourself by copying the whole thing!
Learning how to program is mainly you asking yourself questions and trying to resolve issues on your
own first.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].Vector2;
import [Link];
import [Link];
import [Link];
Texture bucketTexture;
Texture dropTexture;
Sound dropSound;
Music music;
SpriteBatch spriteBatch;
FitViewport viewport;
Sprite bucketSprite;
Vector2 touchPos;
Array<Sprite> dropSprites;
float dropTimer;
Rectangle bucketRectangle;
Rectangle dropRectangle;
@Override
dropSound = [Link]([Link]("drop.mp3"));
music = [Link]([Link]("music.mp3"));
[Link](1, 1);
[Link](true);
[Link](.5f);
[Link]();
@Override
@Override
input();
logic();
draw();
if ([Link]([Link])) {
[Link](speed * delta);
} else if ([Link]([Link])) {
[Link](-speed * delta);
if ([Link]()) {
[Link]([Link](), [Link]());
[Link](touchPos);
[Link](touchPos.x);
}
private void logic() {
[Link](-2f * delta);
else if ([Link](dropRectangle)) {
[Link](i);
[Link]();
dropTimer += delta;
dropTimer = 0;
createDroplet();
}
[Link]([Link]);
[Link]();
[Link]([Link]().combined);
[Link]();
[Link](spriteBatch);
[Link](spriteBatch);
[Link]();
float dropWidth = 1;
float dropHeight = 1;
[Link](dropWidth, dropHeight);
[Link](dropSprite);
@Override
@Override
@Override
}
Example 2: Break out Game
[Link]
import [Link];
import [Link];
import [Link];
import [Link].GL20;
ShapeRenderer shape;
@Override
@Override
[Link]([Link]);
[Link]();
render() runs every frame, which is probably about 60 times per second right now!
We’re drawing a circle at 50, 50 with a radius of 50. Because it’s drawn from the center, it touches
the left and bottom edges of the screen.
Right, it’s pretty boring at the moment. Let’s get this shape moving!
To do this, we need to draw it at location specified by a variable and change that variable over time.
Add some variables to the top of the class:
int x = 50;
int y = 50;
and draw the circle at the x and y variables we create, along with incrementing the x variable.
@Override
x += 5;
[Link]([Link]);
[Link](x, y, 50);
[Link]();
Fantastic! A moving circle! Well… it’s leaving a trail. That’s because we need to set the screen back to
black at the start of our render method.
[Link](GL20.GL_COLOR_BUFFER_BIT);
int xSpeed = 5;
...
x += xSpeed;
if (x > [Link]()) {
xSpeed = -5;
if (x < 0) {
xSpeed = 5;
}
}
[Link]() is the width of the screen in pixels. Once it gets past this, we reverse the
direction of the circle by changing the xSpeed variable. Simple enough! Plus we need to remember to
reverse it again so it doesn’t go off the left side of the screen too.
Ok, bouncing ball, pretty simple. Our logic is getting a bit tangled though and I think it’s time to stick
it in a class.
import [Link];
import [Link];
int x;
int y;
int size;
int xSpeed;
int ySpeed;
this.x = x;
this.y = y;
[Link] = size;
[Link] = xSpeed;
[Link] = ySpeed;
x += xSpeed;
y += ySpeed;
xSpeed = -xSpeed;
ySpeed = -ySpeed;
}
}
[Link](x, y, size);
I added vertical bounces and a definable speed. It’s not too complicated but you should read it
carefully to ensure you understand it. Instead of checking if the ball goes off the left or right side of
the screen, we can simplify by just inverting the speed if either happens.
Now we can just replace the code in our main class with this:
import [Link];
import [Link];
import [Link];
import [Link].GL20;
ShapeRenderer shape;
Ball ball;
@Override
@Override
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]();
[Link]([Link]);
[Link](shape);
[Link]();
}
}
Ahh, much tidier. And we can change a bunch of stuff about the ball very simply from here!
import [Link];
import [Link];
ShapeRenderer shape;
...
Fill this list with balls in create()! And use our random to generate some random numbers between 0
and the argument we pass in. I’ve used different random bounds for each argument to keep things a
bit sane.
[Link](new Ball([Link]([Link]()),
[Link]([Link]()),
Then in render(), update and draw each ball in turn instead of just doing it to the single ball.
[Link]([Link]);
[Link]();
[Link](shape);
[Link]();
Excellent! Now we’re getting somewhere. We have some clean code and a cool effect with very little
effort. Just drawing circles and a tiny bit of maths.
What can we turn this into? How about the classic Breakout! We already have bouncing balls and
balls bouncing off walls so we’re half way there! Unfortunately it’s probably the easy half but coding
problems are the fun!
[Link]
package [Link].ex1;
import [Link];
int x,y,width,height;
boolean destroyed;
this.x = x;
this.y = y;
[Link] = width;
[Link] = height;
[Link]=destroyed;
package [Link].ex1;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
int x=20,y=20,xSpeed=3,ySpeed=3,rX=0,rY=0,rWidth=100,rHeight=10,rSpeed=5;
@Override
@Override
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]([Link]);
for(Block b:blocks) {
[Link](shape);
[Link]();
x+=xSpeed;
y+=ySpeed;
if(x<0||x>[Link]()) {xSpeed=-xSpeed;}
if(y<0||y>[Link]()) {ySpeed=-ySpeed;}
[Link]([Link]);
[Link](x,y,10);
[Link]();
[Link]([Link]);
if([Link]([Link])) {rX-=rSpeed;}
if([Link]([Link])) {rX+=rSpeed;}
[Link]();
if(CircleRectCollision(x,y,rX,rY,10,rWidth,rHeight)) {
[Link]([Link]);
ySpeed=-ySpeed;
[Link]([Link]);
//[Link](shape);
if(CircleRectCollision(x,y,b.x,b.y,10,[Link],[Link])){
[Link]([Link]);
ySpeed = - ySpeed;
[Link] = true;
Block b = [Link](i);
if ([Link]) {
[Link](b);
i--;
[Link]();
}
static public Boolean CircleRectCollision(float x,float y,float rX,float rY,float radius, float width, float
height)
float cSqr = a * a + b * b;
@Override
}
Random Walker
A random walker is a simple idea: start at some point, and then every frame, move in a random
direction. As time goes on, you’ll randomly walk all around the screen. You can think of this like
randomly scribbling on a piece of paper.
This might sound simple (and it is), but it’s also useful in all kinds of applications and explores the
idea of emergence: the process of complicated (and sometimes beautiful) patterns emerging from
simple rules.
I could babble all day about emergence (the random walker is one of my favorite algorithms), so let’s
just get to the code:
float x;
float y;
void setup() {
size(200, 100);
x = width/2;
y = height/2;
//gray background
background(200);
frameRate(1000);
void draw() {
stroke(0);
//randomly move
x += random(-1, 1);
y += random(-1, 1);
//prevent going off left or right
x = width;
x = 0;
y = height;
y = 0;
point(x, y);
This code does what we described above: starts a point in the middle of the screen, randomly moves
that point every frame, and then just draws the point.
From here we could expand our code to include another random walker:
float blackX;
float blackY;
float whiteX;
float whiteY;
void setup() {
size(200, 100);
blackX = width*.25;
blackY = height/2;
whiteX = width*.75;
whiteY = height/2;
background(128);
frameRate(1000);
void draw() {
stroke(0);
blackX = width;
blackX = 0;
blackY = height;
point(blackX, blackY);
stroke(255);
whiteX = width;
whiteX = 0;
whiteY = height;
whiteY = 0;
point(whiteX, whiteY);
This program adds another set of variables and does the exact same logic.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
float x;
float y;
ShapeRenderer shape;
@Override
x = [Link]()/2;
y = [Link]()/2;
@Override
//[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link](1, 0, 0, 1, true);
x += [Link]().nextInt(-1, 1);
y += [Link]().nextInt(-1, 1);
//prevent going off left or right
x = [Link]();
x = 0;
y = [Link]();
y = 0;
[Link]([Link]);
[Link]([Link]); // White
// End drawing
[Link]();
@Override
Animation
Now you know how to call and create functions, how to use and create variables, and how to
use if statements.
You’ve seen that the draw function is called 60 times per second, and you know how to use
operators like + and - to get new values.
What is animation?
In a way, animations are an illusion. When you watch a video (whether that’s a cartoon, a tv show, or
a movie), what you’re really seeing is a series of still images, or frames.
By showing a series of frames sequentially, animations trick your brain into seeing a moving object:
The above animation is slow, so you can still see the individual frames. Typically, animations look
much more smooth if they have more frames and the difference between each frame is smaller (in
other words, if the ball doesn’t move so far each frame).
This tutorial introduces techniques you can use to create animations in Processing.
State
When you think about animation, it’s helpful to think about what displays each frame. Try to break
the scene down into a series of variables. Those variables represent the state of the scene.
For example, the state of a ball might be represented by circleX and circleY variables. You might pass
those variables into the ellipse function to draw a circle at a specific position.
To change the state of the circle, you would modify those variables. Increasing the circleX variable
would move the circle right, and increasing the circleY variable would move the circle down.
You’ve already seen the first two steps; next you’ll learn more about the third step.
Reassigning Variables
One thing you might not have seen yet is that after you create a variable, you can reassign it by
giving it a new value.
To reassign a variable, you type its name, then the equals operator =, and then the new value it
should have.
circleY = 100;
At the end of this code, circleY now holds the value 100.
Notice that you don’t give the variable a type when you reassign it, because it already has a type.
Creating a variable (giving it a type and a name) is called declaring a variable. The first time you point
it to a value using the = operator (which is often in the same line as declaring it) is called initializing a
variable. If you then change the value of the variable, that’s called reassigning the variable.
// declaration
float circleY;
// initialization
circleY = 50;
// reassignment
circleY = 100;
In other words, you only have to give a variable a type when you’re declaring it, not when you’re
initializing or reassigning it.
Modifying Variables
And you know that you can use variables anywhere you can use a value, and that you can use
operators to get new values.
This code uses the height variable and divides it by 2 to get a new value, and then points circleY to
that value.
You can combine those ideas to change a variable over time, by basing its new value on its old value.
// reassignment
circleY = circleY + 1;
At the end of this code, circleY will point to the value 51.
If this is confusing, try reading the right side of the reassignment line first: the code takes circleY,
which is 50, and then adds 1 to get 51. The code then reassigns circleY so it points to that value
instead of its old value.
This might not seem very interesting yet, but it becomes much more useful when you combine it
with the draw function.
Remember that Processing automatically calls the draw function 60 times per second. So if
your draw function draws a scene based on a set of variables, and then changes those variables, then
the next frame will show something different.
Here’s an example:
// state
float circleY = 0;
void setup() {
size(200, 200);
void draw() {
background(32);
// modify state
circleY = circleY + 1;
First, this code declares a variable named circleY and initializes it to point to the value 0. Every time
the draw function is called, the code draws a gray background, and then draws a circle with a vertical
position of circleY. Then, the code adds 1 to the circleY variable!
The next time draw is called, circleY will be 1, which causes the circle to be drawn just a little bit
lower in the window. Then circleY will be 2, then 3, then 4, etc. The code repeats that 60 times per
second, which makes it look like the circle is falling.
Scope
Notice that the above code declares the circleY variable at the top of the sketch, outside
the draw function. Code that’s outside of any functions is run once at the very beginning of the
program.
What if you declared the circleY variable inside the draw() function?
void setup() {
size(200, 200);
void draw() {
// state
float circleY = 0;
background(32);
// modify state
circleY = circleY + 1;
Every frame, this program declares a variable named circleY and initializes it to point to 0. It then
clears out old frames, draws a circle, and reassigns the value. But then at the beginning of the next
frame, the code declares a new variable named circleY and initializes it to 0. Every frame will show
the same thing, and the circle won’t move at all.
In other words, the variable “forgets” its old value, since it’s recreated every frame. If you want a
variable to remember its value between frames, then you have to declare it at the top of your sketch,
outside of any functions!
Similarly, what if you declared the circleY variable inside the setup function?
void setup() {
size(200, 200);
// state
float circleY = 0;
void draw() {
background(32);
circleY = circleY + 1;
You might think this makes sense because the setup function is only called once at the beginning of
the program, but this code has a big problem: if you declare a variable inside a function, you can only
access it inside that function! Since you declare the circleY variable inside the setup function, you
can only access it inside the setup function. So when you try to use it in the draw function, you’ll get
an error.
The places you can access a variable is called the variable’s scope. To make sure you can access a
variable between multiple calls to the draw function, you have to declare it at the top of the sketch. I
call this a sketch-level variable.
A common thing to do is declare a variable at the top of the sketch, then initialize it in
the setup function, and then reassign it in the draw function:
// state
float circleY;
void setup() {
size(200, 200);
circleY = height / 2;
void draw() {
background(32);
// modify state
circleY = circleY + 1;
}
This program declares the circleY variable at the sketch level. Then in the setup function, it sets the
size and initializes the circleY variable to the value calculated from height / 2. If you tried to do this
calculation at the top of the sketch, it wouldn’t work because the size hasn’t been set yet!
Finally, the draw function uses the circleY variable to draw the scene, and then reassigns it to create
an animation.
Resetting
Now you have an animation, but the circle falls off the bottom window and never comes back.
Chances are that’s not what you want.
To fix this, you can use an if statement to check whether the circle has fallen off the bottom of the
window. You know the circle is below the bottom of the window when circleY is greater than height.
When this happens, you can reassign circleY to move the circle back to the top of the window.
// state
float circleY = 0;
void setup() {
size(200, 200);
void draw() {
background(32);
// modify state
circleY = circleY + 1;
// reset state
circleY = 0;
}
This code is mostly the same: it declares a variable named circleY, initialize it to 0, and uses that
variable to draw a circle. It then reassigns circleY every frame, which creates an animation.
The new part is the if statement. After reassigning the circleY variable, the code checks whether the
new value is greater than height. If it is, then the circleY variable is reassigned to the value 0. The
next time the draw function is called, circleY will be 0, the circle will be drawn at the top of the
window, and the animation starts over again.
Bouncing
When the circle reaches the bottom of the window, you could make it bounce instead of teleporting
it back to the top of the window.
One way to do this is to use a ySpeed variable to hold the direction the circle should travel. Then
when you detect the circle has fallen off the bottom of the window (when circleY > height), you can
reassign the ySpeed variable:
// state
float circleY = 0;
float ySpeed = 1;
void setup() {
size(200, 200);
void draw() {
background(32);
Now when circleY > height, the code multiplies the ySpeed variable by -1, which makes it negative.
Adding that to circleY causes circleY to decrease, which moves the circle up.
You can expand that to make the ball bounce off all of the sides of the screen:
// state
float circleY = 0;
float xSpeed = 1;
float ySpeed = 1;
void setup() {
size(200, 200);
void draw() {
// modify state
This program creates variables to hold the position of the ball (circleX and circleY), and two variables
to hold the speed of the ball (xSpeed and ySpeed). Every frame, the code draws a ball at that
position, and then modifies the position by that speed. It then uses an if statement to check whether
the ball has gone off the left or right side of the window, and reverses the xSpeed variable if it has.
Similarly, it uses another if statement to check whether the ball has gone off the top or bottom of the
window, and reverses the ySpeed variable if it has. This causes the ball to bounce off every side of
the window.
Clearing Old Frames
All of the above programs call background(32) to draw a gray background at the start of every frame.
This “paints over” anything drawn by previous frames, clearing out anything that was already in the
window.
This approach of clearing out old frames is useful for most animations, but it depends on what kind
of effect you’re going for. See what happens if you remove the background(32) call from the above
program:
If you don’t clear out old frames, then the frames “stack” as you draw the new frame directly on top
of the old frames.
The random flower program from the creating functions tutorial is an example that intentionally
draws new frames on top of old frames without clearing them out:
Smiley Face
package [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
import [Link];
import [Link];
import [Link];
import [Link];
@Override
@Override
[Link]([Link]);
[Link]([Link]);
[Link]([Link]);
[Link]([Link]);
[Link]([Link]);
[Link]();
@Override
}
Multiple Screen Game
Now we know how to create a game that contains interactive animations. This is okay for testing
things out or for simple games, but most real games will contain multiple screens, for example you
might contain a title screen, a settings screen, a main game screen, and a game over screen. This
tutorial introduces the Game and Screen classes, which provide a framework for showing multiple
screens.
Before we get into the libGDX approach to this problem, it’s worth mentioning that we can actually
already handle this with a simpler approach. This will only work for basic games, but it introduces
some ideas that we’ll reuse when we switch to the more advanced approach.
Our goal is to show different screens that display their own content and react differently to user
input. One simple way to handle this is to use a set of variables that track which screen we’re
showing, and then check those variables in the render() and event functions to decide what to
display or which action to take.
For example, we might use an enum to track the current state of the game:
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].Vector2;
import [Link];
enum Screen{
}
Screen currentScreen = [Link];
SpriteBatch batch;
ShapeRenderer shapeRenderer;
BitmapFont font;
float xSpeed = 4;
float ySpeed = 3;
@Override
[Link](new InputAdapter() {
@Override
currentScreen = Screen.MAIN_GAME;
currentScreen = [Link];
}
return true;
@Override
if(currentScreen == Screen.MAIN_GAME){
currentScreen = Screen.GAME_OVER;
return true;
});
@Override
if(currentScreen == [Link]){
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]();
[Link]();
}
circleX += xSpeed;
circleY += ySpeed;
xSpeed *= -1;
ySpeed *= -1;
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]([Link]);
[Link](0, 1, 0, 1);
[Link]();
[Link](.25f, 0, 0, 1);
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]();
[Link]();
}
}
@Override
[Link]();
This code uses an enum to represent the current state of the game. It checks the current mode to
decide what to do with user input and what to render, and it switches between modes to change the
current screen. This example code creates a game that contains a title screen, a main game screen
where the user clicks a bouncing green circle, and a game over screen.
This code could be modified to use separate functions or classes for the levels, or it could
use boolean or String values to represent the game screen. But the point is that it’s possible to track
the current screen and check it to determine what to render and how to react to user input- but why
not let libGDX do that for us?
The above approach will work for simple games, but it will get cumbersome if your game contains
many screens with their own event logic and rendering code. In this case, you probably want to
encapsulate each screen into its own class and pass the shared resources between them. Instead of
doing this yourself, libGDX provides a Game class and a Screen interface that make this a bit easier.
Generally a libGDX project will contain one class that extends Game and then a bunch of classes that
implement Screen.
Game
The Game class extends ApplicationAdapter so you can use it as the entry point of your core project
(which will be used by the entry points of the platform-specific projects). It also provides handy
functions for switching between screens.
Your project will usually only contain one class that extends Game. This class will contain shared
resources, but it won’t contain any logic or rendering code specific to any one screen.
Screen
The Screen interface contains its own lifecycle functions that are called by libGDX and allow you to
isolate screen-specific logic in a separate class.
Your project will usually contain multiple classes that implements Screen: one for each screen in your
game.
Example
It’s probably easier to show an example. Here’s a version of our above HelloWorldGame that uses
the Game and Screen framework.
HelloWorldGame
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
ShapeRenderer shapeRenderer;
BitmapFont font;
@Override
setScreen(new TitleScreen(this));
@Override
[Link]();
[Link]();
[Link]();
Notice that this class now extends Game and it no longer contains any logic or rendering code. The
only interesting line of code is this one:
setScreen(new TitleScreen(this));
The setScreen() is inherited from the Game class, and it allows us to switch between different
screens. This line of code creates a TitleScreen and passes a reference of the HelloWorldGame into
the constructor using the this keyword- we’ll see why in a second.
In other words, this class now creates some of the shared rendering variables, and then creates
a TitleScreen. Here’s what the TitleScreen looks like:
TitleScreen
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
HelloWorldGame game;
[Link] = game;
@Override
[Link](new InputAdapter() {
@Override
if (keyCode == [Link]) {
[Link](new GameScreen(game));
return true;
});
@Override
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]();
[Link]([Link], "Title Screen!", [Link]() * .25f,
[Link]() * .75f);
[Link]();
@Override
[Link](null);
This class extends ScreenAdapter (which is a way to implement Screen without defining every
possible function), and provides a constructor that stores the instance of HelloWorldGame passed
into its constructor.
The show() function is automatically called when this Screen becomes the current screen of the
game, and it sets up an input processor. Note that we only have to care about the input specific to
this screen.
The render() function is called repeatedly (usually 60 frames per second) as long as this screen is the
current screen. In this function, we draw the title screen. Not much to see here, but note that we’re
using the batch and font created in the main HelloWorldGame class. This allows us to only create
objects once instead of recreating a bunch of the same thing in every screen class. This is one reason
we passed the HelloWorldGame instance into the constructor.
Finally, the hide() function is called whenever this Screen stops being the current screen of the game.
This function removes the input processor we setup in the show() function, so we don’t receive any
more events after this screen has been hidden.
This brings us back to the input processor we created in the show() function. This input processor
checks whether the user has typed the space key, and if so, it sets the current screen to an instance
of the GameScreen class. (This is the other reason we passed the HelloWorldGame instance into the
constructor.) The Game framework automatically hides this screen (calling the hide() function in the
process) and shows the GameScreen.
GameScreen
package [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
import [Link];
import [Link].Vector2;
HelloWorldGame game;
float xSpeed = 4;
float ySpeed = 3;
[Link] = game;
@Override
[Link](new InputAdapter() {
@Override
[Link](new EndScreen(game));
}
return true;
});
@Override
circleX += xSpeed;
circleY += ySpeed;
xSpeed *= -1;
ySpeed *= -1;
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]([Link]);
[Link](0, 1, 0, 1);
[Link]();
@Override
[Link](null);
}
This class contains all of our game logic. Similar to the TitleScreen class, its constructor takes
a HelloWorldGame argument so it can access the shared resources. The show() function sets up an
input processor that listens for touch events. Again, notice that we only have to check for events
specific to the game screen.
The render() function draws our circle bouncing around the screen. Notice that it’s using the shared
resources in the main HelloWorldGame instance.
When the user clicks the circle, we make the EndScreen the current screen. Here’s
the EndScreen class:
EndScreen
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].GL20;
HelloWorldGame game;
[Link] = game;
@Override
[Link](new InputAdapter() {
@Override
[Link](new TitleScreen(game));
return true;
});
@Override
[Link](.25f, 0, 0, 1);
[Link](GL20.GL_COLOR_BUFFER_BIT);
[Link]();
[Link]();
@Override
[Link](null);
This is pretty similar to the TitleScreen class. Again, we only care about the input and rendering
specific to this screen, and we call the setScreen() function on our main HelloWorldGame instance to
go back to the title screen when the user presses enter.