libGDX:
Implemen.ng
a
Simple
Game
Jussi
Pohjolainen
Tampere
University
of
Applied
Sciences
Starter
Class:
Desktop
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration config = new
LwjglApplicationConfiguration();
config.title = "Gorba's Revenge";
config.width = 800;
config.height = 480;
new LwjglApplication(new MyGame(), config);
}
}
// In Android, the resolution is set by operating system!
public class MyGame implements ApplicationListener {
// Method called once when the application is created.
public void create () { }
// Method called by the game loop from the application
// every time rendering should be performed. Game logic
// updates are usually also performed in this method.
public void render () { }
// This method is called every time the game screen is re-sized
// and the game is not in the paused state. It is also called once
// just after the create() method.
// The parameters are the new width and height the screen has been resized to in pixels.
public void resize (int width, int height) { }
// On Android this method is called when the Home button is
// pressed or an incoming call is received. On desktop this is called
// just before dispose() when exiting the application.
// A good place to save the game state.
public void pause () { }
// This method is only called on Android, when the application
// resumes from a paused state.
public void resume () { }
// Called when the application is destroyed. It is preceded by a call to pause().
public void dispose () { }
}
Assets
• Drag
sounds,
images
to
android/assets
folder
– Desktop
app
has
a
link
to
that
folder
Asset
loading
public class MyGame implements ApplicationListener {
private Texture gorbaImage;
private Sound soundEffect;
private Music backgroundMusic;
@Override
public void create() {
// gorba.png uploaded to GPU and is ready to be used by OpenGL. Image format
// must be .jpg, .png, .bmp
gorbaImage = new Texture(Gdx.files.internal(”gorba.png"));
// Stored in RAM
soundEffect = Gdx.audio.newSound(Gdx.files.internal("beep.wav"));
// Streamed from wherever it’s stored
backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal("ussranthem.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
}
public void dispose() {
// Good practice to dispose (clean) assets
gorbaImage.dispose();
soundEffect.dispose();
backgroundMusic.dispose();
}
Rendering:
Camera
• Camera
is
like
“virtual
window
into
our
world”
– What
part
of
the
“world”
is
visible?
• Camera
– OrthographicCamera
• When
the
human
eye
looks
at
a
scene,
objects
in
the
distance
appear
smaller
than
objects
close
by.
Orthographic
projec.on
ignores
this
effect
– PerspectiveCamera
• Closer
objects
appear
bigger
in
Perspec.veCamera
Using
Camera
public class SimpleGame extends ApplicationAdapter {
private OrthographicCamera camera;
@Override
public void create() {
camera = new OrthographicCamera();
// Sets this camera to an orthographic projection,
// centered at (viewportWidth/2, viewportHeight/2),
// with the y-axis pointing up or down.
// true => y points down, false => y points up
camera.setToOrtho(false, 800, 480);
Word
about
OpenGL
• OpenGL
(Open
Graphics
Library)
is
a
cross-‐language,
mul.-‐plaRorm
applica.on
programming
interface
(API)
for
rendering
2D
and
3D
vector
graphics.
• The
API
is
typically
used
to
interact
with
a
graphics
processing
unit
(GPU),
to
achieve
hardware-‐
accelerated
rendering.
• Widely
used
in
CAD,
virtual
reality,
scien.fic
visualiza.on,
informa.on
visualiza.on,
flight
simula.on,
and
video
games.
• libGDX
uses
OpenGL
ES
and
has
interface
also
for
direct
access
for
OpenGL
Texture
Mapping
• A
Texture
wraps
a
standard
OpenGL
ES
texture.
– A
texture
is
an
OpenGL
Object
that
contains
one
or
more
images
that
all
have
the
same
image
format.
• Image
loaded
into
the
GPU’s
memory
in
raw
format
• Texture
mapping
is
process
of
working
out
where
in
space
the
texture
will
be
applied
– “To
s.ck
a
poster
on
a
wall,
one
needs
to
figure
out
where
on
the
wall
he
will
be
gluing
the
corners
of
the
paper”
– Space
ó
Wall
– Mesh
(Rectangle)
ó
Paper
– Image
on
paper
ó
Texture
SpriteBatch
• SpriteBatch
class
takes
care
of
texture
mapping
• Convenience
class
which
makes
drawing
onto
the
screen
easy
public class SimpleGame extends ApplicationAdapter {
private Texture gorbaImage;
private OrthographicCamera camera;
private SpriteBatch batch;
@Override
public void create() {
camera = new OrthographicCamera();
batch = new SpriteBatch();
// Sets this camera to an orthographic projection, centered at (viewportWidth/2, viewportHeight/2),
// with the y-axis pointing up or down. true => y points down, false => y points up
camera.setToOrtho(false, 800, 480);
gorbaImage = new Texture(Gdx.files.internal("littlegorba.png"));
}
@Override
public void render() {
// Let's use the coordinate system specified by the camera
batch.setProjectionMatrix(camera.combined);
// SpriteBatch is ready for commands
batch.begin();
// Draw a texture to x = 100, y = 100
batch.draw(gorbaImage, 100, 100);
batch.draw(gorbaImage, 140, 100);
batch.draw(gorbaImage, 180, 100);
batch.draw(gorbaImage, 220, 100);
// No commands anymore, proceed to process the batch of commands
// received
batch.end();
}
}
Clear
Screen
@Override
public void render() {
// Direct OpenGL call
// float red [0,1]
// green
// blue
// alpha
// https://www.opengl.org/sdk/docs/man/html/glClearColor.xhtml
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
// Clear the screen with the color chosen
// http://www.opengl.org/sdk/docs/man/html/glClear.xhtml
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// SpriteBatch is ready for commands
batch.begin();
// Draw a texture to x = 100, y = 100
batch.draw(gorbaImage, 100, 100);
batch.draw(gorbaImage, 140, 100);
batch.draw(gorbaImage, 180, 100);
batch.draw(gorbaImage, 220, 100);
// No commands anymore, proceed to process the batch of commands
// received
batch.end();
}
Gdx.input
• Ge]ng
input
from
user
is
very
easy
• Touch
– Gdx.input.isTouched()
– Gdx.input.getX()
– Gdx.input.getY()
• Accelerometer
– Gdx.input.getAccelerometerX()
– Gdx.input.getAccelerometerY()
– Gdx.input.getAccelerometerZ()
About
Resolu.on
• Game
can
be
cross-‐plaRorm,
what
is
the
resolu.on?
• We
have
two
resolu.ons
– The
real
resolu.on
– The
world
resolu.on
• Mapping
must
be
done
between
these
two!
Real
resolu.on
0,0
World
resolu.on
0,480
Real
resolu.on
0,480
World
resolu.on
0,0
Window
resolu.on
800
x
480
World
resolu.on
set
to
800
x
480
Real
resolu.on
0,0
World
resolu.on
0,480
Real
resolu.on
0,384
World
resolu.on
0,0
Window
width
640
x
384
World
resolu.on
set
to
800
x
480
Conversion
@Override
public void render() {
if(Gdx.input.isTouched()) {
int realX = Gdx.input.getX();
int realY = Gdx.input.getY();
// Encapsulated 3D Vector, only 2D is used
// Vectors can be used for represent a direction and position
// Bad practice to instantiate every render – call!
Vector3 touchPos = new Vector3(realX, realY, 0);
// Function to translate a point given in screen coordinates to world space.
camera.unproject(touchPos);
Gdx.app.setLogLevel(Logger.DEBUG);
Gdx.app.debug("MyGame", "real X = " + realX);
Gdx.app.debug("MyGame", "real Y = " + realY);
Gdx.app.debug("MyGame", "world X = " + touchPos.x);
Gdx.app.debug("MyGame", "world Y = " + touchPos.y);
}
}
Collision
• Simple
collision
detec.on
is
done
using
overlaps
method
of
Rectangle
• Remember
Texture
Mapping?
– Texture
(image)
– Mesh
(rectangle)
• Create
rectangle
for
each
texture
• if(rect1.overlaps(rect2))
{
..
}
public class SimpleGame extends ApplicationAdapter {
private Texture gorbaImage;
private Rectangle gorbaRectangle;
private Texture phoneImage;
private Rectangle phoneRectangle;
@Override
public void create() {
gorbaImage = new Texture(Gdx.files.internal("littlegorba.png"));
phoneImage = new Texture(Gdx.files.internal("phone.png"));
// new Rectangle (x, y, width, height)
gorbaRectangle = new Rectangle(200,200,24,33);
phoneRectangle = new Rectangle(300,300,17,45);
}
@Override
public void render() {
batch.begin();
batch.draw(gorbaImage, gorbaRectangle.x, gorbaRectangle.y);
batch.draw(phoneImage, phoneRectangle.x, phoneRectangle.x);
batch.end();
if(Gdx.input.isTouched()) {
int realX = Gdx.input.getX();
int realY = Gdx.input.getY();
Vector3 touchPos = new Vector3(realX, realY, 0);
camera.unproject(touchPos);
gorbaRectangle.x = touchPos.x;
gorbaRectangle.y = touchPos.y;
}
if(gorbaRectangle.overlaps(phoneRectangle)) {
Gdx.app.debug("MyGame", "Crash!");
}
}
}
Texture
+
Rectangle
• Texture
(image)
and
Rectangle
(“paper”)
go
hand
in
hand
• It
would
be
great
to
map
these
into
one
class,
for
example
Sprite
– Don’t
implement
one,
libgdx
has
Sprite
J
• hfp://libgdx.badlogicgames.com/nightlies/
docs/api/com/badlogic/gdx/graphics/g2d/
Sprite.html