Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

23. October 2015

 

In a past life in which I sat in a cubicle and someone actually gave me a pay check every week I was a huge fan of Xamarin products.  They do very a good job of enabling .NET developers to leverage their skill across many platforms.  In fact, they are the technology that Unity is built on top off.  That said, I became increasingly less of a fan when the checks stopped and expenses came out of my own pocket!

 

There are many people out there that view making money from software as somehow evil.  I am certainly not one of those people.  In that corporate environment, where developers are paid salaries, rent is paid for office space, taxes are paid, etc…  the price of a software tool like Xamarin is trivial to justify.  In the world of indie game development though, this is often simply not the case.

 

Thing is, Xamarin has become a necessary evil for so many C# based game engines ( MonoGame, WaveEngine, Duality, Paradox, etc ) if you want to port to iOS or Android.  Many of these developers will never see a dime from their efforts, while a select few will become massively rich and a certain middle ground will eek out a living doing what they love.  It’s the later two groups that keep companies like Unity and Unreal afloat, and those two groups don’t come into being without the former group.

 

The challenge with Xamarin has always been their license structure has always been pretty awful for amateur developers.  How many people have chosenn not to work in C# simply because their is a price tag attached?  After years of awaiting a newer friendlier license structure (or Microsoft buyout), hope is on the horizon.

 

Today, in response to Xamarin’s recent acquisition of RoboVM, I ended up in this Twitter conversation with Nat Friedman, CEO of Xamarin:

 

First, in regard to the acquisition of RoboVM and how long the free for LibGDX developers offer will be extended:

image

 

Then more on the indie friendly nature of Xamarin, or lack thereof:

image

(Portion excerpted, Twitter message threading is bizarre)

image

image

 

This is news I am certain many C# game developers and tool providers are going to be delighted to hear.  Hopefully something happens fairly soon, as I’ve been waiting about 6 years and counting at this point! ;)

Programming, News , ,

31. August 2015

 

In this Closer Look At we look at take a look at the jMonkeyEngine.  The Closer Look At game engine series is a cross between an overview, a review and a getting started tutorial to help you decide if a game engine is the right fit for you.  The jMonkeyEngine engine is a Java based, open sourced, cross platform 3djMonkeyCloserLook_450px game engine that runs on most Java supported platforms and can target Windows, Linux, Mac and Android, with iOS and Oculus VR support currently being tested.  jMonkeyEngine is available as both a game library, or as a set of tools built on top of the NetBeans IDE.  For this closer look, we will focus on the full SDK experience.

 

 

This closer look is also available in HD video format here.

 

 

Although we are going to focus on the complete set of tools including in the jMonkeyEngine SDK, keep in mind it can be used in library form if you prefer working in Eclipse or IntelliJ.  You will however lose access to some very convenient tools.

 

 

Meet jMonkeyEngine

 

As I mentioned earlier, jMonkeyEngine ships in two forms, as a set of libraries, or as a complete SDK build on top of the Netbeans IDE.  You can download load the SDK for Windows, Mac or Linux right here.  As of writing, 3.0 is the current released version, while 3.1 is available in development on Github.  This version marks the first public release using the Github platform.  jMonkeyEngine has a few prerequisites before installing, but they basically boil down to having an OpenGL 2 compatible video card and JDK 6 or higher installed.

 

Once downloaded and installed simply run the jMonkeyEngine SDK application.   This is jMonkeyEngine:

image

 

As mentioned earlier, this is actually a preconfigured version of the Netbeans IDE with a set of plugins and extensions to support jMonkeyEngine development.  This means in addition to the various jME tools you get a complete modern Java development environment, meaning code completion, project management, refactoring tools, debugging and more.  I won’t be specifically covering Netbeans functionality in this guide.  If you’ve got prior experience in Eclipse or IntelliJ, you should feel right at home.  Personally I rate the Netbeans experience somewhere between the two, with IntelliJ being quite a bit better, while Eclipse is many many many times worse.  That all said, that is purely opinion, each platform has it’s strength and weakness, it’s fans and haters.  If you prefer to use Eclipse or IntelliJ you can.

 

Hello jMonkeyEngine

 

It is often easiest to start with a simple project, so let’s do exactly that.  Select File->New Project

image

 

A New Project wizard will appear.  All of the standard project types supported by Netbeans are available, but also the new jMonkeyEngine templates are available too.  Select BasicGame and click Next.

image

 

Pick a name and location and click Finish.

image

 

Your project will now be created.  You can have several projects open in the IDE at the same time, just be sure to select the right one in the Projects panel:

image

 

The wizard will have automatically created a project hierarchy for you:

image

 

It’s optional to use this layout, but you are making life more difficult for yourself if you do not.  File paths for textures in imported models are absolute, forcing your hand somewhat in how you import your data.  Again, you can code around this design, but you are making your life more complicated.  For the most part I found the layout fairly logical, but the suggestion to import your models into the Textures folder then relocating them to Models ( well discuss this more later ), well that simply a gross kludge.

 

The New Project wizard also generated a default source file for us, Main.java, with the following contents:

 

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

/**
 * test
 * @author normenhansen
 */
public class Main extends SimpleApplication {

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);
    }

    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

The code is all pretty straight forward.  You game code extends the class SimpleApplication, which in turn implements Application plus implements some “out of the box” behaviour like key mappings for exiting the application and implementing a camera.  These default behaviours can easily be overridden as we will see shortly.  SimpleApplication exposes three critical methods as part of your games life cycle, simpleInitApp(), called when your app is created, then simpleUpdate() and simpleRender() called over and over by the game event loop.  Basically stick your setup code in the init() method, your update code in the update() method and drawing code in the render() method.  If these methods start getting overly complex, you can refactor your design to use States, something we will cover later on.

 

You can run or debug your project using the toolbar:

image

 

Or via the Run menu:

image

 

Once launched you will see a configuration Window.

image

 

Select your preferred configuration and click Continue.  You may be asking, can I get rid of this damned window?  The answer is yes you can, but you have to use code to do it.  I can’t really fathom why there isn’t a “Remember my settings” check box.  Once you click Continue, your first app will run.

FirstApp

 

As you move the mouse cursor around, the camera implemented in SimpleApplication is moving the camera position around.  You may also notice the debug details and of course that startup window.  As said earlier, this can all be override, let’s look at how.

First we can get rid of the configuration window ( which I admit, gets old very quickly ) and set a default resolution using the following code:

    public static void main(String[] args) {
        Main app = new Main();
        
        // Dont show window
        app.showSettings = false;
        
        // Create a new app settings loaded with defaults
        AppSettings appSettings = new AppSettings(true);
        
        // Override resolution
        appSettings.put("Width",720);
        appSettings.put("Height",480);
        
        // Add a title, just because
        appSettings.put("Title", "Super Awesome Megagame 9000!");
        
        app.setSettings(appSettings);
        app.start();
    }

 

Next in our init we add the following logic to disable the camera and debug info. These need to be called after app.start(), thus why they are in init.

    @Override
    public void simpleInitApp() {
                
        // Disable fly cam
        this.flyCam.setEnabled(false);
        
        // Turn off debug info and FPS window
        this.setDisplayFps(false);
        this.setDisplayStatView(false);
        
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);
    }

 

Now when you run your game, you should no longer see the config window, nor display stats when running.  Instead you should see:

image

 

Importing a 3D Model

 

One of the first things I do when testing a new engine is check to see how hard it is to get a 3D model imported.  In jMonkeyEngine you have a couple of options, you can import to their native format, use a Blender plugin, support an OBJ file, or import files converted using the Ogre XML toolchain, which is also available as a Blender plugin as well as several other packages.

 

I will use the native format (j3o) later, for now, let’s look at the process of importing a Blender model, since jMonkeyEngine has solid Blender integration built in.  In fact, jMonkeyEngine actually ships with a copy of Blender as part of the SDK install, currently version 2.69 (as of writing, 2.75 is the most current version).  When you run Blender from within jMonkeyEngine, this included version is the one that is run.  (Note, for performance, you should always prefer using the native binary format unless you have a very good reason not to).

 

You can add a new textured Blender cube (you don’t have to by the way), right click the desired location and select File->New->Other…

image

 

Then select Blender->Box prepared for UV texturing.

image

 

Name it and confirm the location, then click Finish.

image

 

This will run a copy of Blender and set up a cube with textures defined for you.

image

 

What’s extremely odd here is the configured cube isn’t actually ready to go.  You still need to UV unwrap the cube, attach a texture and set the UVmap.   You can see the entire process in the video if you need more details.

 

You can confirm that the blend file works fine, right click the blend and select View Model.

image

 

This will open the Viewer.

image

Be sure to click the light icon (top left) to enable lighting in the viewer.  Now that we know the Blender file works, let’s move over to the code to load a Blender file.  there is a bit of a challenge first, Blender support is actually added as a plugin, we need to add it in first.

 

Right click Libraries and select Add Library…

image

 

Select jme3-libraries-blender then click Add Library.

image

 

We need to add a light to the scene or the model isn’t going to show up.  Simply drag and drop SunLight from to the drop of the simpleInitApp() code and it will drop all the code we need.

image

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Spatial;

public class Main extends SimpleApplication {

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        /** A white, directional light source */ 
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
        sun.setColor(ColorRGBA.White);
        rootNode.addLight(sun); 
        Spatial blenderModel = assetManager.loadModel("Models/demoBox.blend");
        rootNode.attachChild(blenderModel);
    }

    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

And run it:

image

 

So other than Blender configuration, getting a model into a jMonkeyEngine app is fairly straight forward.

 

Tools in jMonkeyEngine

 

Code Palette

We briefly saw the Palette in action in the previous example.

image

This is a selection of code snippets you can drag and drop into the editor.  One major gotcha however, many of these samples depend on a library, jme3-test-data, that isn’t included by default oddly enough.  We saw earlier when we set up the Blender plugin the process of adding a library.

 

3D File Importer

While jMonkeyEngine supports the Ogre XML format and Blend files, working with a game oriented file format is almost always the best performing option.  Fortunately jMonkeyEngine provides just such a format, j3o.  These files can be created easily using the menu File->Import Model menu:

image

 

Then select the model

image

 

Material/Shader Editor

You can easily create shaders right clicking an Asset folder such as Materials, New->Other…

image

 

Then Material->Empty Material file

image

 

You can then define a shader using a UI tool.  You can also set a template that other materials inherit from.

image

 

3D Scene Composer

image

 

The Scene Composer can be use to assemble and create 3D scenes.  There is also a corresponding scene graph:

image

 

A variety of game nodes can be created here:

image

 

Terrain Editor

In addition to the Scene Composer, there is also a 3d terrain tool:

image

You can create terrain visually.  Easily pull and push terrain into shape, paint with multiple textures.  The generated terrain can be used in the scene composer.

terrain

 

Engine Capabilities

 

We only briefly touched upon the code capabilities of the jMonkeyEngine due to time and space restraints.  jMonkeyEngine is a full functioning engine with the following functionality, excerpted from their website.

image

 

Documentation and Community

jMonkeyEngine is well documented, with a comprehensive collection of tutorials and guides available on the wiki.  I encountered a few entries that were out of date or invalid, but for the most part the document was solid and easy to follow.  There is also a good reference in the form of the JavaDoc.  I may not always be the biggest Java fan, but I almost always love JavaDoc generated references!

Until recently the forums for jMonkeyEngine were pretty terrible, but thankfully they’ve recently transitioned to an improved forum.  There is an active community and questions rarely go unanswered.  They have also recently transitioned the source code to Github.

 

Books

 

There are two books available for jMonkeyEngine.

jm1jm2

 

 

The Video

 

Programming , , ,

21. August 2015

Today marks the official release of jMonkeyEngine 3.1 alpha. Generally I wouldn't make a news post over a minor alpha release but a) jme has been pretty quite lately b) I'm currently looking at this engine right now c) it's a pretty massive release.

In addition to underlying changes like a move to github, transition from ant to gradle build systems and implementation of a commenting system that isnt from the 90s, there are some pretty huge new features, such as iOS support, FBX importing, VR support, render optimizations and much more.

 

The full release notes follow:

 

At long last, we have our first alpha release for the jMonkeyEngine 3.1 SDK.

Go get it on GitHub and start breaking things.

Not only does this release mark the introduction of some absolutely game-changing features (or shall we say, abbreviations: iOS, FBX, VR!); it also marks a significant step forward in jME’s underlying infrastructure. In the following weeks, we will explain each and every one of these changes in depth.

All the same bits, structured differently

  • First, we switched from using Google Code (SVN) to GitHub (Git) for
    our source code repository.
  • And then, as if that wasn’t enough, we went from using ANT
    for our build system to using Gradle.
  • We also migrated our forum to the ever more awesome Discourse, which was followed by a series of website updates, with more to come.

These structural changes will allow us to do our work more effectively, and with the combined power of GitHub and Discourse, we’re already seeing a big uptake in contributions and overall user participation.

Unified Renderer Architecture

Previously, there would be a Renderer implementation for each platform that jME3 supported, but all of these platforms supported OpenGL, so in the end, this led to a lot of code duplication. Each time we wanted to add a new renderer feature, all existing renderer implementations had to be modified in the same way.

The new unified renderer architecture means there’s only 1 Renderer implementation, “GLRenderer”, which then calls into GL interfaces implemented by each back-end – this is much easier to maintain. It means easier modification of renderer internals, including performance improvements, as well as the ability to add really advanced features to the renderer that wasn’t possible before. As a consequence, the OpenGL 1 renderer is now out, nobody will ever miss it and (probably) nobody used it for anything. There were some other changes around the rendering pipeline, reduce useless work and improve performance.

OpenGL 3 Core Profile Support

This is a significant improvement especially on Mac OS X and Linux where using the Core Profile actually allows more features to be used than otherwise. Do note that many jME3 shaders don’t support GLSL 1.5 which is required on some platforms when using OpenGL Core Profile – this is being worked on …

Geometry / Tesselation Shader Support

Added support for specifying geometry and tessellation shaders in the material definition. Note that this requires hardware capable of running such shaders. This feature is not used in the engine itself for any capability.

Scene Graph Optimizations

Previously, the engine would need to recurse into the scene graph 3 times every frame, even if nothing was changed! This has been improved so only the branches of the scene graph that require updating or rendering are actually walked into. This equals big performance boost for mostly static and large scenes. The only kind of scenes that don’t benefit from this are scenes where all objects and lights are constantly moving and the entire scene is visible in the camera the whole time. Those kinds of scenes are very rare!

In addition, hardware skinning is now enabled by default, which means a big speed boost when there are many animated models on screen.

Lighting Boost

Remy “nehon” already made a post about this which you can read here. With both single pass lighting and light culling you can now expect big performance improvements in large scenes with many lights. – When rendering shadows for lights, only casters that are inside the light’s area of influence are rendered.

FBX Importer (Beta!)

There’s a beta quality FBX importer currently in development. Unfortunately skeletal animation is not supported yet, but once it is finished, it should replace the semi-functional OgreXML support and hopefully be on par with the .blend importer.

Geometry Instancing

If you want to render a certain (complex) model many times in different places. E.g. a forest or asteroid field, you can use InstancedNode (requires OpenGL3 and higher support!)

Rewritten Audio Streaming

If you were using audio streams before, you might have noticed that they have quite a lot of limitations. They cannot be looped, reset, or stopped without the audio stream becoming useless. The new changes mean you can now stop, loop, or reset audio streams with ease. Also, updates about audio finishing playing now occur every frame instead of every 50 milliseconds (e.g. if you were relying on it for any events & such)

Further, there’s a new capability to determine current playback position of an audio source. Can be used to synchronize events or video to an audio stream.

Networking Improvements

HostedServices: Essentially like AppStates, but independent of jME3 Application infrastructure.

Gamma-correct lighting and high dynamic range rendering

Gamma-correct lighting – basically means lighting looks better or more realistic, or both. Oh, and if you’re planning on using this, you better make sure its always on because your scene will look different depending on if its on or off. While at it, you can also use the new tonemap filter for HDR rendering. The tonemap algorithm is based on a filmic curve from Uncharted 2.

Profiling Frame Times

With the app profiler state, you can see how long each part of a frame takes, e.g. rendering or updates, thus allowing you to detect stuttering parts in the game and optimize them.

iOS Improvements

  • Now iOS support is mostly stable (but still behind Android support). More testing is needed.
  • Texture loading issue fixed.
  • Audio support now enabled.

Android Bugfixes & Improvements

  • Texture decoding is now handled by C++ code so loading time is now much shorter. This also means the terrain alphamap issue is fixed. Previously you had to flip the alpha channel to use terrain on Android, this is no longer required.
  • OGG/Vorbis audio decoding is now handled by C++ code. This allows using the native OpenAL Soft audio library to handle audio instead of the Android built-in MediaPlayer, hence 3D audio, doppler effects, and reverb is now supported.
  • Support for Android Fragments (on Android 4.0+)
  • Added support for joysticks. For example, you can connect your Xbox 360 controller to your Android tablet and it will show up as an actual joystick in jME.

Blender Importer

  • Improved support for models animated with IK (inverse kinematics)
  • Support for loading linked .blend files

SDK Editor Improvements

dark_monkey

  • Enhanced shader node editor with many issues fixed.
  • 3D Scale / Rotate Tool.
  • New “DarkMonkey” theme which matches the forum theme (you have to enable it manually under the Look and Feel settings)

Bullet Physics

  • Added capability to change number of solver iterations – aka “physics accuracy”.
  • Added support native sweep test (previously was unimplemented)
  • Fixes to native ray test (previously was broken / crashing)
  • Allow 3D vector linear and angular factor instead of just a scalar factor

Misc Engine

  • Print out current build branch / tag / revision / hash in log

Misc Bugfixes

  • Fix inconsistent mouse coordinate origin on AWT panels
  • Fix translucent bucket on AWT panels
  • Fix using texture arrays with GPU compressed textures
  • Fix building engine on JDK8 and latest Android NDK
  • Fix point sprites on Android
  • Fix post-processing / FBO on Android
  • Fix running jME3 in the Android emulator
  • Fix shadow effect Z fade feature
  • Fix compilation issues on Java 1.8
  • Fix broken Material.preload() method
  • Fix water filter not working on GPUs without OpenGL 3 support
  • Fix crashing filter multisample support on OpenGL 3.2 contexts
  • Fix bounding volume not updated when geometry inside BatchNode is modified
  • Fix incorrect flipping of 2×2 DXT5 images
  • Fix audio source reverb being enabled by default
  • Fix batching with vertex colored meshes
  • And a trillion other bug fixes I forgot to mention, so you better start using jME 3.1 today!

 

News ,

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 , ,

Month List

Popular Comments