Speeding up GWT compilation speeds in a LibGDX project

7. October 2013

 

On thing i’ve discovered working with GWT these past few weeks is, it’s slow… very very very slow.  I am developing on a newer laptop running a Haswell processor and SSD and my compilation times look like this:

image

 

254 seconds per compile is simply not tenable, especially during development.  You can avoid a compilation by working in DevMode, but this is exceedingly fragile at times.  As a result, I wanted to look into a way of speeding the process up.  Fortunately it’s a fairly simple process in the end.

 

The first culprit is the “Compiling permutation X” bit.  By default it is going to compile a version for every supported browser.  For release this is obviously advantageous, but during development it is bringing compile times to a crawl.  Fortunately, you only really need to develop for whatever browser you are testing in.  If you are working with a LibGDX project locate the file GwtDefinition.gwt.xml in the –html project.  There is one in the base project too, but that is not the file you are looking for.  It should look like this:

image

 

Edit that file to look like this:

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" 
    "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
    <inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' />
    <inherits name='InputDemo' />
    <entry-point class='input.gamefromscratch.com.client.GwtLauncher' />
    <set-configuration-property name="gdx.assetpath" value="../input-android/assets" />
    <set-property name="user.agent" value="safari"/>
</module>

 

The line highlighted in yellow is the one you are interested in.  Basically you provide an entry for each browser you want GWT to compile for.  In my case I am working in Chrome which (oddly enough) doesn’t have it’s own user agent ( in the form value=”safari,ie9,other_values_here” ).  As Safari and Chrome have a common ancestor in Webkit, this user agent works.  You can also specify values for FireFox ( gecko ) and IE.  By building for just a single browser, we see a massive speedup.  In my after making the above change:

image

 

Down to 53 seconds… much better, but still far to long in my humble opinion.

 

Then one other idea struck me… I’m running a 32bit version of the JDK ( because so many tools still don’t play well with JDK7, FlashDevelop being the biggest ), so after a great deal of effort, I got and configured a 64 bit JDK and version of Eclipse.  Coincidentally, Eclipse really doesn’t seem to like sharing a workspace between 32 and 64bit installs!  Once I eventually got it working ( an hour and a half later… oh Eclipse, I so hate you ), I ran the GWT compiler again:

 

 image

 

31.5 seconds, almost a halving in development time.  So either Java 7, 64bit or possibly both resulted in a large decrease in compile time.

 

There is one final optimization I found, which is ironically to not optimize.  Just like with C++ compilers, you can create and optimized and unoptimized build.  By default GWT performs a great deal of optimization and during development, this is probably a waste.  Fortunately it can easily be disabled.  When you run a GWT compile, in the options window you can pass an additional parameter, –draftCompile.  It is available under the Advanced tab:

image

 

And the result:

image

17 seconds!  Much much much better!  Coincidentally, playing around with the memory amount available made little to no difference.  I actually experienced slightly slower compilation time when I increased it to 2G ( of 8 available on my machine ).  Obviously the less optimized version is going to run slower, but it shouldn’t be by a huge margin.

 

Remember though, when building for release, you want to re-enable all of these settings!  But for day to day development, 17 seconds is a heck of a lot better than 254s!

Programming ,




LibGDX Tutorial 3: Basic graphics

2. October 2013

 

This is the part people always find the most fun, the actual act of putting graphics up on screen.  Let’s start with about the simplest project that we can.

 

We are going to display this sprite (created in this tutorial):

jet

 

On screen.  One important thing to note, the above graphic is 512x256.  OpenGL in general and LibGDX in specific, require your image files to be in power of two dimensions.  This means your width and height are 2,4,8,16,32,64,128,256,512,1024,2048, etc… pixels in size.  Be sure to add this file to the assets\data folder in the android project before continuing.

 

Let’s jump right in with code:

 

package com.gamefromscratch.graphicsdemo;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class GraphicsDemo implements ApplicationListener {
    private SpriteBatch batch;
    private Texture texture;
    private Sprite sprite;
    
    @Override
    public void create() {        
        batch = new SpriteBatch();
        texture = new Texture(Gdx.files.internal("data/jet.png"));
        sprite = new Sprite(texture);
    }

    @Override
    public void dispose() {
        batch.dispose();
        texture.dispose();
    }

    @Override
    public void render() {        
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        sprite.draw(batch);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

And if you run it:

image

 

The image is drawn relative to the origin.  In the case of LibGDX (0,0) is the bottom left corner of the screen.

 

As to the code, there isn’t actually a ton new compared to the Hello World example in the previous tutorial.  The only new concepts are the Texture and the Sprite.  The texture represents the underlying OpenGL texture.  One important thing to keep in mind with Texture ( and other similar classes ) is they implement the Disposable interface.  This means when you are done with it, you have to call the dispose() method, or you will leak memory!  A Sprite holds the geometry and colour data of a texture, this means the positional data ( such as it’s X and Y location ) are stored in the Sprite.  We construct our texture by passing it’s path in, obtained in the same manner we access the font in the prior tutorial.  We then construct the Sprite by passing in our newly created texture.  There are other ways of creating Sprites, that we will see shortly.  Just like in the Hello World sample, we start a SpriteBatch, and draw our sprite to it using the draw() method.

 

Dynamic textures with Pixmap

 

Your Texture’s source doesn’t have to come from a file.  Here we are going to use the Pixmap class to create the texture’s source dynamically.

 

package com.gamefromscratch.graphicsdemo;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class GraphicsDemo implements ApplicationListener {
    private SpriteBatch batch;
    private Pixmap pixmap;
    private Texture texture;
    private Sprite sprite;
    
    @Override
    public void create() {        
        batch = new SpriteBatch();
        
        // A Pixmap is basically a raw image in memory as repesented by pixels
        // We create one 256 wide, 128 height using 8 bytes for Red, Green, Blue and Alpha channels
        pixmap = new Pixmap(256,128, Pixmap.Format.RGBA8888);
        
        //Fill it red
        pixmap.setColor(Color.RED);
        pixmap.fill();
        
        //Draw two lines forming an X
        pixmap.setColor(Color.BLACK);
        pixmap.drawLine(0, 0, pixmap.getWidth()-1, pixmap.getHeight()-1);
        pixmap.drawLine(0, pixmap.getHeight()-1, pixmap.getWidth()-1, 0);
        
        //Draw a circle about the middle
        pixmap.setColor(Color.YELLOW);
        pixmap.drawCircle(pixmap.getWidth()/2, pixmap.getHeight()/2, pixmap.getHeight()/2 - 1);
        
        
        texture = new Texture(pixmap);
        
        //It's the textures responsibility now... get rid of the pixmap
        pixmap.dispose();
        
        sprite = new Sprite(texture);
    }

    @Override
    public void dispose() {
        batch.dispose();
        texture.dispose();
    }

    @Override
    public void render() {        
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        sprite.setPosition(0, 0);        
        sprite.draw(batch);
        sprite.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
        sprite.draw(batch);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

Once again, the code is remarkably similar to our prior example.  The biggest difference is instead of loading the textures image data from file, we create one dynamically using a Pixmap.  At the simplest, a pixmap can be thought of as a grid of pixel data in memory.  It contains a number of graphical functions, many of which we demoed above.  The drawing code is pretty well commented in terms of what it does, so I wont go into details here.  One very important detail though, in the modern GPU driven world, these kinds of per pixel operations are REALLY REALLY SLOW.  Generally you want to avoid them as much as possible. 

 

The only other thing of note in this example is the changes in the render() method.  Notice how the same sprite is drawn twice to the sprite batch?  Well this behaviour is perfectly OK, and has minimal performance overhead in doing so.  Sprite’s setPosition method is used to position a sprite, once again, (0,0) is the lower left hand corner of the screen by default.  The only other new code here is the Gdx.graphics.getWidth() and getHeight() method calls.  These return the window’s ( or Canvas in the case of HTML5 ) dimensions.  Of course in production code you would probably cache them locally instead of retrieving them every pass through the render loop.

 

TextureAtlas

 

Quite often you want to deal with a sprite sheet, which is a number of sprites combined together into a single image.  Such functionality is built into LibGdx.  The first thing you are going to need is a directory of images that are going to be combined into a sprite sheet.  Like this:

image

 

Open a command line or terminal window and run the following command:

java -cp gdx.jar;extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.imagepacker.TexturePacker2 c:\tmp c:\tmp spritesheet
tmp

It looks more unwieldy than it is.  Basically you are running the TexturePacker2 class inside the gdx-tools jar.  The first parameter is the source directory, the second parameter is the destination direction and the final parameter is the filename to use.  It will automatically add the required file extensions.  This process will create two files, a .atlas file and a .png.  The atlas file is a text file describing how the sprites are laid out in the spritesheet image, with the images filename used as the key ( minus extension ), like so:

spritesheet.atlas:

spritesheet.png
format: RGBA8888
filter: Nearest,Nearest
repeat: none
0001
  rotate: false
  xy: 1, 651
  size: 192, 128
  orig: 192, 128
  offset: 0, 0
  index: -1
0002
  rotate: false

 

While the sprite sheet itself looks like this:

spritesheet

 

The spritepacker tool automatically pads the image out to be a power of 2 in size.  I’ve only scratched the very surface of what this tool can do.  You can set it to run as part of your build process, run if from code or within Eclipse or even run it at program run time. There are a wealth of options you can configure.  You can read much more about it right here.

 

So how do you actually use a texture atlas then?  It’s very simple, first copy the generated png and atlas file to your assets.  The following code shows how to use a TextureAtlas:

 

package com.gamefromscratch.graphicsdemo;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.Timer.Task;

public class GraphicsDemo implements ApplicationListener {
    private SpriteBatch batch;
    private TextureAtlas textureAtlas;
    private Sprite sprite;
    private int currentFrame = 1;
    private String currentAtlasKey = new String("0001");
    
    @Override
    public void create() {        
        batch = new SpriteBatch();
        textureAtlas = new TextureAtlas(Gdx.files.internal("data/spritesheet.atlas"));
        AtlasRegion region = textureAtlas.findRegion("0001");
        sprite = new Sprite(region);
        sprite.setPosition(120, 100);
        sprite.scale(2.5f);
        Timer.schedule(new Task(){
                @Override
                public void run() {
                    currentFrame++;
                    if(currentFrame > 20)
                        currentFrame = 1;
                    
                    // ATTENTION! String.format() doesnt work under GWT for god knows why...
                    currentAtlasKey = String.format("%04d", currentFrame);
                    sprite.setRegion(textureAtlas.findRegion(currentAtlasKey));
                }
            }
            ,0,1/30.0f);
    }

    @Override
    public void dispose() {
        batch.dispose();
        textureAtlas.dispose();
    }

    @Override
    public void render() {        
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        sprite.draw(batch);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

Here is the HTML5 version of the above code:

 

 

As you can see, it’s remarkably consistent.  The majority of the code above is actually part of the demo related, as opposed to being part of using a TextureAtlas.  Instead the only import new code is:

batch = new SpriteBatch();
textureAtlas = new TextureAtlas(Gdx.files.internal("data/spritesheet.atlas"));
AtlasRegion region = textureAtlas.findRegion("0001");
sprite = new Sprite(region);

Just like working with a texture, but instead you load a TextureAtlas.  Then instead of assign the texture to the sprite, you use an AtlasRegion, which describes the coordinates of the individual sprite within the spritesheet.  You get the region by name by calling the findRegion() method and passing the key.  Remember this value is set by the file names of the source images.  The TextureAtlas needs to be dispose()’d or you will leak memory.

As you can see by the call:

sprite.setRegion(textureAtlas.findRegion(currentAtlasKey));

You can change the region within the sprite sheet that the sprite will refer to by calling setRegion().

 

The rest of the code simply positions and scales the sprite up 2.5x times.  We then schedule a Task using Timer.schedule().  This task will be called ever 30th of a second.  It simply changes the key we will use within the TextureAtlas.   In this case the files were named 0001.png, 0002.png, etc…  so we want a value between 0001 and 0020.  We then use this value to update the region the sprite refers to.  As a result every 30th of a second, the sprite moves on to the next frame of animation, rolling over when it gets to the end.

 

EDIT: I should state for the record, this is NOT how you would use a TextureAtlas to perform animation, this code was simply for demonstration purposes.  There are dedicated animation classes and we will cover them later on.

 

Be warned though, if you try to run this under GWT, you will see:

image

 

This is because the GWT compiler ( this has nothing to do with LibGDX ) doesn’t support String.format() for some reason.  If you want to run this example in a browser you can simply replace

currentAtlasKey = String.format("%04d", currentFrame);

With:

String base = new String();
        
        if(currentFrame >= 10)
            base = "00";
        else
            base = "000";
        
currentAtlasKey = base + currentFrame;

 

Now the HTML target should run just fine.

 

In the next part we will take a look at controlling input in LibGDX.

 

Configuring LibGDX to use GL 2

 

It was brought to my attention by Mario Zechner that LibGDX is not limited to power of 2 texture sizes.  That instead is an artefact of OpenGL ES 1.  If you run using OpenGL ES2 it will work fine.  That said, OpenGL and the underlying hardware still perform better if you stick to power of two.  If you want to use GL2, you set it during as part of the configuration process, we discussed briefly in the Hello World tutorial.  Simply set the useGL20 value to true in the configuration you pass in to your application listener.  Here for example is Main from the desktop project configured to use GL 2.

 

public class Main {
    public static void main(String[] args) {
        LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
        cfg.title = "graphicsdemo";
        cfg.useGL20 = true;
        cfg.width = 480;
        cfg.height = 320;
        
        new LwjglApplication(new GraphicsDemo(), cfg);
    }
}

 

Remember of course to configure this for all targets you are supporting.

 

EDIT:

12/18/2013 – It was pointed out to me that I didn’t include the atlas files, making this tutorial hard to follow along with.  I have included an archive of the data folder used for this example, you can download it here.

Programming ,




SpellJS a JavaScript based cross platform component based game engine with an IDE

1. October 2013

 

This game engine came to my attention yesterday on reddit so I took a bit of time to check it out and it has potential.

 

First off, it also has a few problems.  The installer has absolutely no feedback to say that it installed, no UI, nothing.  It left me scratching my head about what was going wrong and in the end everything was working fine behind the scenes.  It all ended up being moot though, as I never got the evaluation key I applied for anyway, so I was never able to run the local executables anyway.  This is all those teething growing pain issues and no doubt will be resolved in time.  My money says my email provider simply rejected their email… it happens.  Fortunately we can still get a pretty good look as the IDE runs in the browser as well and their is a demo on their site.

 

Speaking of which, here it is:

image

 

You can run the editor in demo mode by clicking here.  Unfortunately you can’t actually create projects this way, but it will give you an idea what SpellJS can do.  Otherwise you need a key.  There are a couple options here, free, not free and slightly more expensive.  Or more specifically:

 

image

 

 

So basically its free for non-commercial use, or 99 euro per developer if you want to make money selling your game directly.  If on the other hand you want to make money via advertising and/or make use of the analytic or cloud features it’s 239 euro per developer.  All told, fairly reasonable pricing in my opinion, but they will face the same trouble all other engine companies face…  a lot of their competition is free.

 

Then there is the matter of what platforms are supported:

image

 

That’s most of the major platforms covered with Flash support as a fallback for the non-compliant browsers out there.  The HTML5 layer is built over WebGL with fallback to Canvas/CSS3 rendering for non-compliant browsers.  The Android and iOS publishing is as native applications, not as web apps by the way, which is good as the iOS browser performance is often abysmal while Android is a mixed bag.

 

Ok, back to SpellJS…  the layout is pretty straight forward.

 

Games are laid out in terms of Scenes.  On the left hand side you’ve got the scene graph:

image

 

Right click on a scene and select Render Scene and it appears in the Scene view:

image

 

Here you can this scene in your game.  There are buttons across the top for pausing the scene and switching in and out of development mode.  Unfortunately they didn’t seem to work for me, I am not sure if this is a side effect of the editor.  SpellJS is supposed to support live editing, allowing you to change your game as you play it.

 

Across the right hand side is a context sensitive area depending on what you have otherwise selected.  This for example is what happens if you select the physics component in Update:

image

 

While if you have an entity selected, such as the HighScore, you will see:

image

 

This is where you would configure your various entities by setting the properties of attached components, or by adding new components.  Much like Unity, you can attach a series of components to your entities and multiple entities to your scene.

 

So, where the heck does code go?  That is the realm of scripts.  On the left hand panel, select Library:

image

 

And you will see the various assets that make up your game, such as graphics sounds and… scripts.

image

 

Here for example is the script showFinish showing in the in IDE editor:

image

 

The editor supports code folding, syntax highlighting but unfortunately doesn't seem to support code completion.

 

Scripts arent your only option, if you look the various systems that compose the update group, if you right click demo_asteroids.system.shoot and select show for example, the code that composes the system will be shown in the editor.

image

 

image

 

On other big question is… how is the documentation?  Quite good actually.  There is a Getting Started guide, a half a dozen tutorials and a fairly comprehensive, if a little sparse, reference guide.  One annoyance is, each click opens in a new tab, leading to tons of tabs to be closed.

 

image

 

All told, this looks like a very polished product and if you like working in JavaScript is certainly worth checking out.  Should my product key ever arrive and my calendar opens up a bit, I will take a closer look.  You can check them out at SpellJs.com.

Programming , ,




New CocosStudio, Cocos2d-html5 and Cocos2d-x releases today

28. September 2013

image

There are a new set of coordinated releases to the Cocos2d-x family of game development libraries and tools.  The changes include:

 

CocosStudio

  • UI editor for UI graphic artists
  • Animation editor for graphic artists
  • Data editor for game data designers
  • Scene editor for game designers

 

 

Cocos2d-html5

  • Improved Sprite, Node, LabelTTF class, now it is clean and clear
  • Added a new sample game Fruit Attack which works great on PC browsers, mobile browsers, and can even be run natively as an android and iOS app with JSB
  • Replaced cc.Sprite and its subclasses's texture from DOM element to cc.Texture2D on Canvas mode,
  • Improved cc.Texture2d. Now you don't need to wait for loading resources when creating a new scene or layers. Textures will pop up when they are loaded
  • Improved the update function of Actions. Now Action objects use less temporary objects, making it better for GC performance.
  • Improved LabelTTF rendering pipeline. Now it caches the result which is 100% faster on mobile browser
  • Fixed API compatibility between Cocos2d-html5 and JSB: cc.ParticleSystemQuad has merged intocc.ParticleSystem. For more info, please read Upgrade guide v2.1.5 to v2.2
  • Added Auto Hiding url address bar for mobile browsers. Please refer to the template and the Hello World for examples
  • Added frame event, collider and blend type supporting for Armature. Now Armature supports 2 tools: 1.CocoStudio, 2.DragonBones
  • Set auto render mode $Default value$ to canvas for mobile browsers and WebGL for desktop browsers

 

Cocos2d-x

  • Initial version of Windows8 and WinPhone8 port
  • Supported the first stable version of CocoStudio v1.0.0.0
  • Added CocoStudio GUI
  • Almost no differnce between JSB and cocos2d-html5 v2.2
  • Lua binding supports CCTableView and CCScrollView

 

 

The Cocos2d-html5 project also released a new sample game, Fruit Attack:

FruitAttackGame

 

You can play it in your browser here.

 

You can read the official announcement here.  Or head on over here to download.

News ,




LibGDX Tutorial 2: Hello World

26. September 2013

 

There is an old law, possibly predating the age of man, that all tutorials must start with Hello World.  I am nothing if not law abiding, so therefore let’s create a Hello World app.  Hello World is generally one of the simplest programs you can create, you simply display the words Hello World on screen.  Of course, there are always complications in life… that’s what makes it interesting!

 

To get started I created a simple project using the Project Setup tool we discussed in the prior tutorial.

 

We are going to jump in with the code in a second, but first let’s take a quick look at the code created by the project tool, gdx-setup-ui.  Your project should look like this:

image

 

Obviously your file names will vary depending on what you used during the project setup tool.  The key thing to note is the basics of how code is laid out.  The non-suffixed folder ( hello-world ) is where the shared code goes.  The –android, –desktop and –html folders are where platform specific code goes and hopefully you will have minimal need to use these.  I will look at them a bit closer in a few minutes, but for now it’s the file HelloWorld.java that we are interested in.  This is where a very important class called an ApplicationListener is implemented.  Here is the code I used:

 

package com.gamefromscratch.helloworld;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class HelloWorld implements ApplicationListener {
    private SpriteBatch batch;
    private BitmapFont font;
    
    @Override
    public void create() {        
        batch = new SpriteBatch();    
        font = new BitmapFont();
        font.setColor(Color.RED);
    }

    @Override
    public void dispose() {
        batch.dispose();
        font.dispose();
    }

    @Override
    public void render() {        
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        font.draw(batch, "Hello World", 200, 200);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

The first thing you may notice is… there’s no Main!  Well there is one and we will take a look at it in a second.  At the end of the day though, LibGDX is an event driven engine.  You implement an ApplicationListener and GDX calls a number of functions that you can respond to.  The render() method will be called each from, so if you want to, you can think of that as your event loop.  Otherwise there are functions that are called in response to various events, these include create, resize, pause and resume.  I imagine you can guess what event each one is in response to!

 

The bulk of our code is in create() and render().  In create() we allocate a new SpriteBatch, BitmapFont and set the font to the colour red.  SpriteBatch’ing is a common activity in 2D game engines built over 3D libraries, if you’ve used XNA you are used to it.  Basically behind the scenes, LibGDX is using OpenGL ( or WebGL depending on platform ) to do the rendering.  In OpenGL there is a fair bit of overhead in drawing … well, anything.  A spritebatch combines them all into a single operation to reduce the amount of overhead.  In a nutshell, it makes 2D rendering a great deal faster.  A BitmapFont is exactly what it sounds like, a 2D bitmap containing all the characters.  If you don’t specify a Font in the constructor, you will get the default font Arial-15 included with LibGDX.  The font file looks like this:

 

image

 

In the render() method we clear the screen to white by making the OpenGL function call glClear() and glClearColor().  The parameters to glClearColor are the red, green, blue and alpha ( transparency ) values to clear the screen with.  The function glClear actually clears the screen.  As you can see, the underlying OpenGL functionality is exposed in Gdx.gl, although generally you wont work at that level very often.

 

Next we start our sprite batch by calling begin(), then render our text to the batch using the font.draw method.  The parameters to draw() are the batch to draw to, the text to draw and the x and y coordinates to draw the text at.  If you run this code ( right click hello-world-desktop and select Run As->Java Application ) you will see:

 

image

 

Voila!  It’s Hello World.

 

One important thing to be aware of is the project hello-world is not an application that you can run, its a library used by the other projects.  I’ll show you what I mean, take a look at code in hello-world-desktop for example:

image

 

Hey look, it’s Main!  Let’s check out the code:

 

package com.gamefromscratch.helloworld;

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;

public class Main {
    public static void main(String[] args) {
        LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
        cfg.title = "hello-world";
        cfg.useGL20 = false;
        cfg.width = 480;
        cfg.height = 320;
        
        new LwjglApplication(new HelloWorld(), cfg);
    }
}

 

This is the actual entry point for your application, or at least it is for the desktop target.  This is where the Desktop specific configuration happens.  You then start your game off by creating a LwjglApplication object, passing in an instance of your ApplicationListener as well as the Lwjgl specific configuration settings.  If Lwjgl is new to you, it’s a Java based game wrapper over top of OpenGL and is what LibGDX uses for desktop rendering.  Beyond configuring it here, you will have no other interactions with it, LibGDX takes care of all of that for you.

 

To really understand how cross platform magic works in LibGDX, let’s also take a look at the Main for the –html project.  In this case it’s not actually called Main, but instead GwtLauncher.java.

 

image

 

Gwt stands for Google Web Toolkit, and it’s a technology Google provides for compiling Java into JavaScript for use in a browser.  It’s the secret sauce that LibGDX uses to make your game run in HTML.  It’s also horrifically annoying at times, you have been warned!  That said, if you dont care about HTML, you can remove this project completely and save yourself a number of headaches. 

 

Let’s take a look at GwtLauncher.java:

 

package com.gamefromscratch.helloworld.client;

import com.gamefromscratch.helloworld.HelloWorld;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.backends.gwt.GwtApplication;
import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration;

public class GwtLauncher extends GwtApplication {
    @Override
    public GwtApplicationConfiguration getConfig () {
        GwtApplicationConfiguration cfg = new GwtApplicationConfiguration(480, 320);
        return cfg;
    }

    @Override
    public ApplicationListener getApplicationListener () {
        return new HelloWorld();
    }
}

Look’s a lot like the –desktop project main doesn’t it?  The basic concept is exactly the same, you create the platform specific configuration bits, and create an instance of your ApplicationListener.  The GwtApplication class is callback based however, so it looks a bit different.  Once again, you should rarely be working at this level.  One important thing to note though is the values being passed to GwtApplicationConfiguration… this represents the size of the HTML canvas being created.  So if you want your HTML app to be more than a small square in the middle of the screen, this is where you change it.

 

So basically LibGDX works by having you create a single common library that implements your game in a cross platform way in the form of an ApplicationListener.  To support multiple platforms, you have a project for each platform where you create a platform specific application ( an instance of GwtApplication in the case of HTML targets, LwjglApplication for desktop targets, AndroidApplication for Android targets, Application for iOS targets… not shown because I am working on Windows currently ) , configure it and pass in the ApplicationListener.  It is this application class that will be calling back to your ApplicationListener each frame.  The nice news is, most of the time, you wont care about any of this… but it’s handy to understand what’s happening behind the curtains.

 

 

Oh yeah… about GWT

 

Remember I said it was a bit of a pain?  Well let’s take a look at what happens when you run the hello-world-html application ( right click hello-world-html->Run As->Web Application):

 

image

 

 

Ugh…  so basically our code is trying to do something GWT does not permit.  If we flip back to Eclipse in the Console panel we can get a bit more insight into the nature of the exception.

image

 

It’s line 17 in HelloWorld.Java that is causing the exception:

        font = new BitmapFont();

So, what exactly is going on here?  Well, remember earlier when I told you that BitmapFont’s default constructor would use the built-in arial-15 font.  Well, when I said built in, that file actually resides in gdx.jar which is included in your project.  A jar file is actually just a zip, so if you extract the file you can see all the code and assets that make up the gdx library itself.  Of particular interest to us is the folder \gdx\com\badlogic\gdx\utils, this is where the font file resides among other files:

 

image

 

Basically the GwtApplication is trying to access this file and doesn’t have permission to do so.  What’s the moral to the story?  Cross platform is awesome… but not always free!  Unless you need to support HTML, I would suggest not creating an HTML project, as it is by far the most fragile part of LibGDX and working with GWT causes all kinds of heartache and complication.  Your mileage may vary!

 

That said, there is a very simple fix to this, and it nicely illustrates how you deal with files between your projects… a process that may not be particularly intuitive.  The simple solution is to add the files arial-15.fnt and  arial-15 to the project and change the line:

font = new BitmapFont();

to

 

font = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"),false);

 

This version of BitmapFont’s constructor takes a file handle of the font file you want the BitmapFont to use.  Gdx.files is used for file manipulation, internal returns a file handle to a file that is included within the project.  The false parameter is specifying that the font’s graphic isn't flipped upside down.

 

So, how do you actually add the file to the project?  You add them to the assets\data folder of the hello-world-android project:

image

 

You can add the files by simply dragging/dropping from Finder or Explorer to the data folder in the Package Explorer.

 

Now that the font file has been added, we can now run the HTML target:

image

 

So that’s Hello World in LibGDX.  Next up we look at something more advanced than Hello World.

Programming ,