Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
26. May 2015

 

As part of GameFromScratch’s ongoing A Closer look at game engine series, today we are going to be taking a look at LibGDX, a Java based cross platform game engine(sorta).  The “Closer Look” series is intended to be a cross between a tutorial, review and overview of a game engine, aimed at helping those evaluating which game engine is right for them.  We are going to go into a bit less technical detail with LibGDX, as this site already has a massive text based and video based tutorial series covering LibGDX in depth.

 

There is an HD video version of this post available as well, also embedded below.

 

Introduction to LibGDX

 

Let’s start with their own description:

Libgdx is a Java game development framework that provides a unified API that works across all supported platforms.

The framework provides an environment for rapid prototyping and fast iterations. Instead of deploying to Android/iOS/Javascript after each code change, you can run and debug your game on the desktop, natively. Desktop JVM features like code hotswapping reduce your iteration times considerably.

Libgdx tries not be the "end all, be all" solution. It does not force a specific design on you.

You can get a complete feature list here.

 

So basically LibGDX is a cross platform, JVM based 2D/3D game engine(sorta) capable of targeting desktops, iOS, Android and HTML.  It is free and completely open source.  When I say JVM based, LibGDX is written primarily in Java but your own applications code could theoretically be written in any JVM based language, such as Kotlin or Scala.  LibGDX is able to compile to HTML using the GWT compiler, while iOS support is provided using RoboVM.  For the most part, 99% of the time, the platform specific portions are pretty well hidden from you the developer.

 

So why do I keep throwing a (sorta) disclaimer every time I use the word “Game Engine”?  Well that’s technically because LibGDX isn’t a game engine, it’s more of a framework, similar in scope to SFML, MonoGame/XNA or SDL.  It provides the underlying “guts” required to make game a game, things like graphics, audio and input.  It however doesn’t provide a scenegraph, essentially the “heart” of a game.  However it does provide a simple 2D scene graph/ UI / Widget library named Scene2D, which is built over top of LibGDX.  The use of Scene2D is completely optional.

 

Getting Started

 

Getting started with LibGDX is incredibly simple.  If you want to use it as just another library that is of course your option.  If you are for example making a desktop only project, you can download and build LibGDX from it’s Github repository.  If you want to create a cross platform game, or like me, want to avoid Java build systems like the plague there is a handy project creation tool available right here.  Simply download and execute the linked Jar file.  It will automatically download all of the required dependencies, although you will have to have a Java Development Kit and the Android SDK pre-installed.  For more detailed installation instructions watch this.  Assuming you have a properly configured Java dev environment, you should see the following:

image

 

This will automatically generate a project for you.  Clicking Advanced allows you to have LibGDX generate IntelliJ IDEA or Eclipse projects for you.  You can also select which platforms you want to support and which extensions to you want enabled.  Once you click Generate, Maven will automatically create a project for you and download all the dependencies.  If you want the tools such as a font generator, particle tool or sprite packer, be sure to select Tools under extensions.

 

If you are looking for more details on working with your specific IDE, check the tutorials for more details.  There are IntelliJ and Eclipse configuration tutorial available.

 

A Simple Project

 

Let’s take a quick look at the project it generated.

 

The heart of your game is the platform agnostic ApplicationAdapter located in the core project.  ( More on this shortly ).  Here is the code:

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class MyGame extends ApplicationAdapter {
   SpriteBatch batch;
   Texture img;
   
   @Override
   public void create () {
      batch = new SpriteBatch();
      img = new Texture("badlogic.jpg");
   }

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

 

If you’ve previously worked in XNA, the overarching structure should be immediately familiar to you, XNA and LibGDX feel incredibly similar to me, and this is a good thing.

 

The nutshell version of what’s happening here is our game extends the ApplicationAdapter class… we will see why shortly.  In it’s create() method we create a SpriteBatch and a Texture object, the texture “badlogic.jpg” is loaded from the assets folder ( by default in the Android project, unless you didn’t create an Android project, in which case it will be in Core ).  The assets folder is basically the root where all of your game’s non-code content is located.  In render() method we clear the background color, start our sprite batch, draw the texture to it, then finish the batch, which results in it’s contents being drawn to the screen.

 

There are a few things to be immediately aware of.  LibGDX provides a fairly shallow abstraction over top of OpenGL ( or WebGL/OpenGL ES, depending on platform ), which can be access with Gdx.gl. calls.  Most of the GL functions are accessible this way, but in a cross platform friendly manner.  The other thing to be aware of is the coordinate system by default follows the OpenGL convention of having the origin (0,0) be the bottom left corner of the screen.

 

When you run the generated code, you should see:

image

 

That’s about as detailed as I am going to get with the code, if you want more details, simply go through the tutorial series for dozens of them.

 

Now the neat part about this whole process is, using the exact same code you could switch your run target to iOS, Android or HTML and it should just work.  Let’s look at exactly how that works.  If you look at the project, your folders should be structured like so:

image

 

Basically you have a project/module for each targeted platform, then core where the cross platform ( majority ) of your code exists.  Let’s take a quick look at the desktop project for a look at exactly how this works. Expanded, the desktop project should look something like this.

image

 

It’s the DesktopLauncher class that is of the most interest.  For desktop projects, this is your application entry point.  Let’s take a quick look inside:

package com.gamefromscratch.desktop;

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

public class DesktopLauncher {
   public static void main (String[] arg) {
      LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
      new LwjglApplication(new MyGame(), config);
   }
}

 

This is where you would put the platform specific code related to desktop platforms.  You can see the traditional program main() is here, inside of which we create a simple configuration object and pass it to our LwjglApplication.  LWJGL stands for Light Weight Java Game Library, and it’s the OpenGL layer that LibGDX desktop implementation is based on.  There is a similar entry point created for the Android application, the iOS application and the HTML5 application.  Each and every one creates a new instance of your game class and passes in the platform specific configurations.  Ideally, this is the extent of your platform specific code, but quite often you have to implement some details on a platform by platform basis.

 

If you look at the various config objects being created, you will notice each is full of properties that are specific to that particular platform, like so:

image

 

Splitting your project up into this format makes platform independence mostly an after thought for most developers.

 

I wont be going into depth of the functionality that LibGDX provides, it’s covered in detail elsewhere.  That said, if functionality is required by a game, but isn’t game specific, chances are its in LibGDX.  This includes graphics, audio, input, motion, asset management and much more.

 

LibGDX Tools

 

Not being strictly a game engine, the tooling support in LibGDX is minimal, but there are some tools included, many of which are command-line based.  There is no world editor, animation tools, etc…  The tools are bundled in the project if you included the Tools extension.  The tools include:

image

 

Most of the tools are Java callable and can be invoked from the command line/terminal.  This means integrating them into your build process is trivial.  The primary tools above are for font and sprite sheet creation.  Only hiero and particleeditor are GUI based:

 

Hiero is a tool for creating bitmap fonts from system/ttf fonts:

image

 

The Particle Editor is a GUI tool for creating particle systems:

image

 

Another critical tool, not included by default, is the fbx-conv project, which is used for importing 3D assets into LibGDX.

 

Built on LibGDX

 

Although not directly part of LibGDX, there are some tools build over top of LibGDX and provide some of the functionality typically ascribed to a full game engine.  They include:

 

Overlap2D  A 2D level and UI editor for LibGDX games built over LibGDX

 

GDX-Proto A 3D game engine built over LibGDX

 

BDX Another 3D engine built over LibGDX, this one built over top of Blender as the world editor.

 

Spine A commercial 2D IK animation tool built using LibGDX by the author of Scene2D.

 

 

Documentation and Tutorials

 

Of course, there is the GameFromScratch.com tutorial series, which I happen to think are pretty good, but I’m biased.  On top of that, there is the Wiki, which is pretty comprehensive.  There is also a generated from code complete reference guide, that while a little shallow in spots, is generally quite useful.

 

There are a couple recently published LibGDX books available as well, one which I somewhat recently reviewed.  I am not sure the other books are really needed between the Wiki and tutorials available on this site.  If you want however, there are some beginner oriented books available as well.

 

For support, there is a quite active forum available.  Well worded questions are generally answered quite quickly.  Stackoverflow also sees a fair number of LibGDX questions.  All told, it’s got a very large community, making community based support pretty solid.

 

Conclusion

 

Personally I am a big fan of LibGDX, even though I am not the biggest Java cheerleader you will find.  If you are looking to create complex 3D games, or want extensive editor support, LibGDX is probably not the engine for you.  If you want a code focused, open source, free, accessible cross platform game engine capable of doing 2D or 3D, you really should check out LibGDX.

 

 

The Video

 

Programming


7. April 2015

 

In this video tutorial we continue to look at 3D programming in LibGDX.  First we look at how to convert a 3D model to work with LibGDX using fbx-conv.  We then write the code to display that model and look at displaying animations.  The fbx-conv application can be downloaded here.

 

The data file used in this example can be downloaded here (zip format).  If you are interested in learning more about the process of creating the model click here.

 

The video is available in HD here.

 

The source code, and an embedded copy of the video, are available below.

 

 

Source Code

 

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.loader.G3dModelLoader;
import com.badlogic.gdx.graphics.g3d.utils.AnimationController;
import com.badlogic.gdx.utils.UBJsonReader;

public class ModelTest extends ApplicationAdapter {
    private PerspectiveCamera camera;
    private ModelBatch modelBatch;
    private Model model;
    private ModelInstance modelInstance;
    private Environment environment;
    private AnimationController controller;

    @Override
    public void create() {
        camera = new PerspectiveCamera(75,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());

        camera.position.set(0f,100f,100f);
        camera.lookAt(0f,100f,0f);

        camera.near = 0.1f;
        camera.far = 300.0f;

        modelBatch = new ModelBatch();

        UBJsonReader jsonReader = new UBJsonReader();

        G3dModelLoader modelLoader = new G3dModelLoader(jsonReader);
        model = modelLoader.loadModel(Gdx.files.getFileHandle("model.g3db", Files.FileType.Internal));
        modelInstance = new ModelInstance(model);

        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight,0.8f,0.8f,0.8f,1.0f));

        controller = new AnimationController(modelInstance);
        controller.setAnimation("Mixamo.com", -1, new AnimationController.AnimationListener() {
            @Override
            public void onEnd(AnimationController.AnimationDesc animation) {
            }

            @Override
            public void onLoop(AnimationController.AnimationDesc animation) {
                Gdx.app.log("INFO","Animation Ended");
            }
        });
    }

    @Override
    public void dispose() {
        modelBatch.dispose();
        model.dispose();
    }

    @Override
    public void render() {
        Gdx.gl.glViewport(0,0,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
        Gdx.gl.glClearColor(1,1,1,1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);

        camera.update();
        controller.update(Gdx.graphics.getDeltaTime());

        modelBatch.begin(camera);
        modelBatch.render(modelInstance);
        modelBatch.end();
    }
}

 

Video

 

Programming


24. March 2015

 

In this tutorial we start looking at 3D game development using LibGDX.  We explore creating a Camera, Model, ModelInstance and look at the basics of working in 3D using LibGDX.

 

You can watch the tutorial in HD here or embedded below.  The following is the source used in this example.

 

The Source


package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g3d.*;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;

public class Demo3D extends ApplicationAdapter implements InputProcessor {
    private PerspectiveCamera camera;
    private ModelBatch modelBatch;
    private ModelBuilder modelBuilder;
    private Model box;
    private ModelInstance modelInstance;
    private Environment environment;
   
   @Override
   public void create () {
        camera = new PerspectiveCamera(75,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
        camera.position.set(0f, 0f, 3f);
        camera.lookAt(0f,0f,0f);
        camera.near =0.1f;
        camera.far = 300f;

        modelBatch = new ModelBatch();
        modelBuilder = new ModelBuilder();
        box = modelBuilder.createBox(2f,2f,2f,
                new Material(ColorAttribute.createDiffuse(Color.BLUE)),
                VertexAttributes.Usage.Position|VertexAttributes.Usage.Normal);
        modelInstance = new ModelInstance(box,0,0,0);
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight,0.8f,0.8f,0.8f,1f));

        Gdx.input.setInputProcessor(this);
   }

   @Override
   public void render () {
      Gdx.gl.glClearColor(0, 0, 0, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);

        camera.update();
        modelBatch.begin(camera);
        modelBatch.render(modelInstance,environment);
        modelBatch.end();
   }

    @Override
    public boolean keyDown(int keycode) {
        // In the real world, do not create NEW variables over and over, create
        // a temporary static member instead
        if(keycode == Input.Keys.LEFT)
            camera.rotateAround(new Vector3(0f, 0f, 0f), new Vector3(0f, 1f, 0f), 1f);
        if(keycode == Input.Keys.RIGHT)
            camera.rotateAround(new Vector3(0f,0f,0f),new Vector3(0f,1f,0f), -1f);
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

 

The Video


Programming


16. March 2015

 

This post popped up on reddit a few days back and didn’t really get a ton of interest.  I almost missed it myself, but I am glad I didn’t.  Off and on the last couple days, I’ve been playing around with BDX and I have to say, there is the kernel of something really cool here!

 

First off, let me say BDX is really young and it shows some times.  You do some things wrong and you are left with either a crashing game or a cryptic Python error message.  Armature support is currently missing as are a few other features I looked for.  The community is currently small and we are talking a 0.10 release here…  I had to work around a couple bugs, the Android SDK path was getting an extra “ added and I simply can’t get gradle import to work with IntelliJ without hacking out the Android project.  So expect some warts and experimentation.  It’s worth it though, this is pretty cool stuff, as you will now see.

 

Oh yeah, there is also a video version of this post.  It’s also embedded below if you scroll down.  It covers basically the same topics as this tutorial.

 

What is BDX?

 

So, what exactly is BDX?  Well basically it’s a Java library built over top of LibGDX adding 3D support.  Essentially I suppose you can think of it as a 3D scene graph.  Then the cool part… it’s also a plugin to Blender that turns Blender into your 3D world editor.  Basically you create your assets and world in Blender, apply properties using the BGE and Physics portions of Blender, then export and run.  To a much lesser degree, it is also a code generator… sort of.  Let’s take a look at how it works now…

 

Prerequisites

 

First off, you need to have a Java JDK installed, personally I am using JDK 1.7.  If you are going to be building BDX from sources ( we wont here ) you also need Ant installed.  If you have trouble, watch this video on configuring a Java/LibGDX development environment.  It’s more than what you need, but will certainly get you running.

 

Next head on over to the BDX download page and download the BDX zip file.  If you happen to be running on Mac, turn off that infernal “automatically run trusted downloads” setting, as you want the file to remain zipped.

 

image

 

Of course, you will also need Blender installed.  You can download it here.  For the record I, at the time of writing this, am using 2.73a and as you can see from the screenshot above, 0.1.1 of BDX.

 

Please note, I WILL NOT be covering how to use Blender in this post, except for the configuration bit below.  Fortunately I’ve got that down already, so if you are brand new to Blender run through this tutorial series.  It will cover everything you need to get started (and more).

 

Installing BDX

 

At this point I assume you have Blender installed and BDX downloaded.  Now we need to set it up in Blender.  Don’t worry, it’s pretty simple.

 

Load Blender up.

In the menu, select File->User Preferences…

image

 

Select the Add-ons tab, then Install From Disk:

image

 

Now navigate to and select Bdx.zip then click “Install from File…”

image

 

Now we need to enable the plugin.  Back in the Add-ons tab, on the left hand side toggle the option Testing.  Import-Export: BDX should now appear as an option.  Click the Checkbox beside the dynamite icon.

image

 

BDX should now be ready to use!

 

Creating Your First Project

 

BDX does an impressive job of wrapping the project generator for you.  Coincidentally if you see the LibGDX project wizard you’ve made a mistake!

 

In Blender, make sure you are in Default view to start:

image

 

Now, assuming you are running factory settings, look for the Properties window on the right hand side, and scroll down to locate the BDX settings:

image

 

Fill in the settings like so:

image

 

Click Create BDX project.  For Java Package, make sure to give the entire name, not just the url qualifier.   Base Path is the directory the project will be created in, while Directory is the folder within that directory that will be created.  So using the above settings, you will get the directory c:\temp\bdxdemo.

 

Once you click the Create BDX project, the magic begins!

 

It will churn away for a few seconds, and assuming no errors occurred, it should create a new scene for you like so:

image

 

A complete but very simple “game” created for you.  A couple things to notice.  First your Blender now has a new display mode “BDX” available:

image

 

This enables you to switch in and out of the BDX view you see in the screenshot above.  Also, the controls in the BDX scene are now completely different:

image

 

Go ahead and click Export and Run.   This will package your Blender scene, generate some Java code for you, call the Java compiler and assuming no errors, run your game.

 

image

 

Cool stuff!

 

So basically you can now create and edit a world in Blender and code it using LibGDX.  Let’s take a look at the code portion now…  actually, lets look at the project this created.  Go to the directory you specified earlier.

 

The Project Hierarchy… how it works

 

So, here’s the directory structure that is created, with the critical directories expanded:

image

 

If you’ve done any LibGDX development, most of the structure should be immediately obvious.  You get one directory for each project ( android, desktop, html, ios ), then all of the common code goes in to core.  All of the assets ( graphics, scenes, data files, etc… ) that make up your game are put in the assets folder of the android folder.

 

The other folder of note is the Blender folder.  This is where your Blender .blend files are generated/stored.  In many ways, when using BDX, this becomes the heart of your project.  You re-open the .blend file in Blender to reload your project.

 

What about the code?

 

So far we’ve just used Blender… how exactly do we work in Java? 

 

Well the code is located in core/src/com/yourdomain/yourproject.

There are a pair of files generated by default here.  First is BdxApp.java

This is your main application class implementing ApplicationListener.  Here is the code below:

 

package com.gamefromscratch.bdxdemo;

import java.util.HashMap;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.ModelBatch;

import com.nilunder.bdx.Bdx;
import com.nilunder.bdx.GameObject;
import com.nilunder.bdx.Scene;
import com.nilunder.bdx.Instantiator;
import com.nilunder.bdx.utils.*;
import com.nilunder.bdx.inputs.*;

public class BdxApp implements ApplicationListener {

   public PerspectiveCamera cam;
   public ModelBatch modelBatch;

   @Override
   public void create() {
      modelBatch = new ModelBatch();
      
      Bdx.init();
      Gdx.input.setInputProcessor(new GdxProcessor(Bdx.keyboard, Bdx.mouse, Bdx.allocatedFingers));

      Scene.instantiators = new HashMap<String, Instantiator>();
      Scene.instantiators.put("Scene", new com.gamefromscratch.bdxdemo.inst.iScene());

      Bdx.scenes.add(new Scene("Scene"));
   }

   @Override
   public void dispose() {
      modelBatch.dispose();
   }

   @Override
   public void render() {
      Bdx.profiler.start("__graphics");
      Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      Bdx.profiler.stop("__graphics");

      Bdx.updateInput();
      Bdx.profiler.stop("__input");

      for (Scene s : (ArrayListNamed<Scene>)Bdx.scenes.clone()){
         s.update();
         Bdx.profiler.start("__render");
         renderScene(s);
         Bdx.profiler.stop("__render");
      }
      Bdx.profiler.update();
   }
   
   
   public void renderScene(Scene scene){
      Gdx.gl.glClear(GL20.GL_DEPTH_BUFFER_BIT);
      modelBatch.begin(scene.cam);
      for (GameObject g : scene.objects){
         if (g.visible()){
            modelBatch.render(g.modelInstance);
         }
      }
      modelBatch.end();
   }

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

   @Override
   public void pause() {
   }

   @Override
   public void resume() {
   }
}

 

If you’ve worked in LibGDX before, this should all look pretty straight forward.  Basically it’s setting up the BDX classes and a regular LibGDX render loop.

 

However, the part that is critical to understand is this little line…  it goes a long way towards figuring out how BDX actually works:

 

      Scene.instantiators = new HashMap<String, Instantiator>();
      Scene.instantiators.put("Scene", new com.gamefromscratch.bdxdemo.inst.iScene());

 

This is the special sauce that links Blender and LibGDX together.  If you look in sub directory inst, you will see a class named iScene.java:

package com.gamefromscratch.bdxdemo.inst;

import com.badlogic.gdx.utils.JsonValue;
import com.nilunder.bdx.Instantiator;
import com.nilunder.bdx.GameObject;
import com.gamefromscratch.bdxdemo.*;
public class iScene extends Instantiator {

   public GameObject newObject(JsonValue gobj){
      String name = gobj.name;

      if (name.equals("Sacky"))
         return new com.gamefromscratch.bdxdemo.Sacky();

      return super.newObject(gobj);
   }
   
}

This is actually an area I struggled with at first because I kept editing it by hand, then when I would run the game my changes were being overwritten!  GRRRRRR…  Then it dawned on me, BDX is also a code generator.  This file is being created automatically when you click the “Export and Run” button.

 

So what exactly is it doing?  Well basically it loops through each object in the Blender scene by name and creates the cooresponding Java class in our scene.   For example, when it finds an object named “Sacky” in the Blender scene, it then creates a new com.gamefromscratch.bdxdemo.Sacky instance in our java code.  Essentially this is the link between Blender and Java.

 

Wait, you might ask… what the heck is a Sacky?

 

Great question!

 

First, lets take a look at our Blender scene graph:

image

 

Ahhh… so that’s a “Sacky”.  It’s basically a texture mesh in Blender that’s been named Sacky.  So… where exactly is the class Sacky.java?  If you look in the code directory:

image

 

No Sacky.java. 

 

This is because by default the code is actually “embedded” in the blend file.  In the BDX control buttons, there is a button “Make internal java files external”.  Click it:

image

 

Now in your src folder you should see:

image

 

Ahhh, much better.  At this point you can actually import the gradle project into your favorite IDE and work normally.  You only need to return to Blender and click Export and Run when you make changes to the Blender scene.

 

NOTE: I am using IntelliJ and had a problem with the gradle import.  It really doesn’t like the android gradle version created by default, but updating the version number caused other dependencies to break… oh the joy of Java build systems.  I personally just hacked out everything but desktop and core from the gradle build.  Leave a comment if you want more details how to do this… if you run into the same problem that is.

 

Meet the GameObject

 

The heart of the BDX scenegraph is GameObject.  It’s basically a thing in the world, often called an entity or node in other engines.  Here for example is Sacky.java:

package com.gamefromscratch.bdxdemo;

import com.nilunder.bdx.*;

public class Sacky extends GameObject{

    public void main(){
        if (Bdx.keyboard.keyHit("space"))
            applyForce(0, 0, 300);
    }
    
}

GameObjects have a couple key methods.  main() you see above is what you traditionally think of as update or tick.  It is called each frame, so this is where you update your objects logic.  There is also init() called on creation and onEnd() called when removed.   In the above example you simply poll to see if the user hits space, and if they do apply 300 “force” along the Z axis.  BDX makes use of the physics properties of Blender, as we will see shortly.

 

In a nutshell, the things that make up your game are GameObjects.  Under the curtain, GameObjects are still LibGDX classes we know and love, let’s take a quick look behind the curtain with a debugger and inspect what makes up Sacky here…

image

Essentially GameObject is a fairly light wrapper over the LibGDX ModelInstance class, which is what you ultimately get when you import a 3D model into LibGDX.  It holds all the nodes, animations, geometry and bones that make up an object.  Unfortunately bone animation isn’t currently supported by BDX.  You may also notice that each GameObject holds a reference to the Scene that contains it.

 

Scene itself is essentially the scene graph.  That is, the container that holds the contents of your game ( the GameObjects, Cameras, etc ):

image

 

All told, pretty straight forward stuff and a good reminder that below it all, LibGDX is still right there, just slightly wrapped.

 

Creating a new GameObject

 

Now let’s actually look at creating your own GameObject.  This is basically what the majority of your game development workflow will look like in BDX.  It’s a multistep process, but isn’t difficult.

 

First, in Blender, simply add a new object.  I am going to add a new Mesh->Cube:

image

 

Now in the scene graph select your newly created Cube, rename it to MyCube:

image

 

Now if you select Export and Run, you will now see your Cube:

image

 

Now let’s wire some code to it.

 

In the same directory as your App and the existing Sacky.java file, create a new Java class named MyCube.java, with the following contents:

package com.gamefromscratch.bdxdemo;

import com.nilunder.bdx.*;

public class MyCube extends GameObject{

    public void main(){
        if (Bdx.keyboard.keyHit("space"))
            visible(!visible());
    }

}

Next in Blender click the Export and Run button. Now when you press the spacebar, the visibility of the newly created cube will now toggle.

 

You will notice something… now that we have an object named MyCube in Blender and a class named MyCube.java, when we click the Export button, the iScene.java class is being auto generated each time:

package com.gamefromscratch.bdxdemo.inst;

import com.badlogic.gdx.utils.JsonValue;
import com.nilunder.bdx.Instantiator;import com.nilunder.bdx.GameObject;
import com.gamefromscratch.bdxdemo.*;
public class iScene extends Instantiator {

   public GameObject newObject(JsonValue gobj){
      String name = gobj.name;

      if (name.equals("MyCube"))
         return new com.gamefromscratch.bdxdemo.MyCube();
      if (name.equals("Sacky"))
         return new com.gamefromscratch.bdxdemo.Sacky();

      return super.newObject(gobj);
   }
   
}

Again, this is basically the glue that ties Java and Blender together

 

Texturing our Cube

 

An un-textured cube isn’t exactly exciting, so let’s quickly texture our cube.  To do so, switch to edit mode in Blender, select all vertices and unwrap.  Then create a new material, then a new texture.  Watch the attached video for more details of this process.

 

There is one critical part you need to be aware of, thus why I am bothering to mention it at all.  When generating your texture map, you need to put it in your assets folder!  So when saving it, save it to the correct folder, like so:

image

 

To the following location:

 

image

 

If you don’t implicitly save it to this folder, or a sub-directory, your code will die on execution.  Oh, another top tip… DO NOT RUN YOUR GAME WHILE IN EDIT MODE!  Yeah, it doesn’t work.  I’m guessing it’s a bug, but always switch back to object mode before running.

 

Now that we’ve got our cube textured, let’s run it:

image

 

Very cool.

 

Adding Physics

 

You can also make objects physics objects using Blender.  With your object selected selected the Physics tab in Blender:

image

 

You can now set the object to static ( unmoving ), dynamic ( affected by physics but not moving on its own ) or rigid body ( fully simulated physics ):

image

All other options are ignored, so stick to those three or No Collision.

 

For a Rigid Body there are a number of properties you can select.  You can also determine the bounding type.  Your choices are limited to Box (uses a bounding box to determine boundaries), Sphere (uses a sphere instead) and Mesh (uses the mesh itself. More accurate but much more CPU intensive):

image

As you can see, you can also configure Mass, velocity, etc.

 

Setting Properties

 

Another cool feature is you can actually set properties using Blender and access them in your code.  Therefore you can use Blender as a proper game editor, setting properties such as HP.

 

To do this, open the Logic Editor in Blender, and click Add Property.

image

 

Now name and type your property and set a default value, like so:

image

 

Then in code you can easily access these values:

public class MyCube extends GameObject{
    public void main(){
        if (Bdx.keyboard.keyHit("space")) {
            int hp = this.props.get("hitPoints").asInt();
            Gdx.app.log("Current HP",String.valueOf(hp));
            visible(!visible());
        }
    }
}

Very cool stuff

 

The Video

 

 

Conclusion

 

BDX is certainly a project to watch if you are working in 3D with LibGDX, especially if you use Blender as part of your workflow.  It does over all make for a pretty seamless pipeline and makes world authoring a breeze.

Programming


27. February 2015

 

In this tutorial, we look at animating sprites using the Animation class.  We look at loading sprites two different ways.  First creates them by splitting up a Texture loaded into memory.  The second example uses a texture atlas.  As always the code is provide below.

 

You can watch the video in HD here.

 

 

The Source

 

Example 1:

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class AnimationDemo extends ApplicationAdapter {
   SpriteBatch batch;
   Texture img;
   TextureRegion[] animationFrames;
   Animation animation;
   float elapsedTime;
   
   @Override
   public void create () {
      batch = new SpriteBatch();
      img = new Texture("walkcycle.png");

      TextureRegion[][] tmpFrames = TextureRegion.split(img,256,256);

      animationFrames = new TextureRegion[4];
      int index = 0;

      for (int i = 0; i < 2; i++){
         for(int j = 0; j < 2; j++) {
            animationFrames[index++] = tmpFrames[j][i];
         }
      }

      animation = new Animation(1f/4f,animationFrames);
   }

   @Override
   public void render () {
      elapsedTime += Gdx.graphics.getDeltaTime();
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      batch.begin();
      batch.draw(animation.getKeyFrame(elapsedTime,true),0,0);
      batch.end();
   }
}

 

Example 2:

package com.gamefromscratch.com;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;

public class TextureAtlasAnimationDemo extends ApplicationAdapter {
   SpriteBatch batch;
   private TextureAtlas textureAtlas;
   private Animation animation;
   private float elapsedTime = 0f;
   
   @Override
   public void create () {
      batch = new SpriteBatch();
      textureAtlas = new TextureAtlas(Gdx.files.internal("spritesheets/myspritesheet.atlas"));
      animation = new Animation(1f/15f, textureAtlas.getRegions());
   }

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

   @Override
   public void render () {
      elapsedTime += Gdx.graphics.getDeltaTime();
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      batch.begin();
      batch.draw(animation.getKeyFrame(elapsedTime,true),0,0);
      batch.end();
   }
}

Programming


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List