libGDX Runtimes

Overview

This document describes how to use the libGDX runtimes. The language of the runtimes is in Java. We will go through an example of how to load an exported JSON file and play it back in the scene.

Grabbing the runtimes

You can either download the runtimes directly from the Creature Game Runtimes window or grab them from the repository here.

Import Statements

Here are the import statements used:

import MeshBoneUtil.*;
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;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.JsonValue;
import com.badlogic.gdx.graphics.OrthographicCamera;

Loading and Initialization

Let us assume we have an exported dragon animation file called default.json. We also have its corresponding texture atlas called character-dragon.png. We start off by first loading the file assets:

// Load json
JsonValue json_data = CreatureModuleUtils.LoadCreatureJSONData("default.json");

The above will load the JSON data from disk and into memory. Next, let us create the actual objects that can make use of these loaded assets:

// Create creature
Creature new_creature = new Creature(json_data);

// Create animations
CreatureAnimation new_animation1 = new CreatureAnimation(json_data, "default", new_creature);
CreatureAnimation new_animation2 = new CreatureAnimation(json_data, "second", new_creature);

// Create manager and add in animations
CreatureManager new_creature_manager = new CreatureManager(new_creature);
new_creature_manager.AddAnimation(new_animation1);
new_creature_manager.AddAnimation(new_animation2);

In the example above, the JSON file has 2 animation clips: default and second. Hence, we will need to create 2 animations from the creature_manager object to make them available for playback.

Now that we are done loading, we can set the active animation to default for playback, as well as some playback properties:

new_creature_manager.SetActiveAnimationName("default", false);
new_creature_manager.SetIsPlaying(true);
new_creature_manager.SetShouldLoop(true);

We will now go ahead and create the object(s) required to render the character animation:

    // load shaders
    final String VERTEX = Gdx.files.internal("MeshBoneShader.vert").readString();
    final String FRAGMENT = Gdx.files.internal("MeshBoneShader.frag").readString();
    ShaderProgram program = new ShaderProgram(VERTEX, FRAGMENT);

    Texture new_texture = new Texture(Gdx.files.internal("character-dragon.png"));

    // Create the creature render object
    active_creature_render = new CreatureRenderer(new_creature_manager,
            new_texture,
            program,
            camera);

    // Set a transformation matrix for the creature
    Matrix4 xform = new Matrix4();
    xform.scl(1.5f);
    active_creature_render.SetXform(xform);

Character Animation and Rendering Updates

Once we have loaded the character, we need to call the corresponding update calls to update the animation and render the character. This is done in the render() callback:

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

    camera.update();

    // Update the character and render
    active_creature_manager.Update(Gdx.graphics.getDeltaTime());
    active_creature_render.Flush();
}

Complete Code Sample

Here is the complete code layout. Most the the code is generated from the default libGDX project starter template. Pay attention to the method create() which does most of the work:

package com.mygdx.game;

import MeshBoneUtil.*;
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;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.JsonValue;
import com.badlogic.gdx.graphics.OrthographicCamera;


public class MyGdxGame extends ApplicationAdapter {
    OrthographicCamera camera;
    SpriteBatch batch;
    Texture img;
    CreatureManager active_creature_manager;
    CreatureRenderer active_creature_render;

    @Override
    public void create () {
        camera = new OrthographicCamera( (float)Gdx.graphics.getWidth() * 0.05f,
                                            (float)Gdx.graphics.getHeight() * 0.05f);
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");

        System.out.println("Loading json...");
        // Load json
        JsonValue json_data = CreatureModuleUtils.LoadCreatureJSONData("default.json");

        System.out.println("Loading creature...");
        // Create creature
        Creature new_creature = new Creature(json_data);

        System.out.println("Loading animations...");
        // Create animations
        CreatureAnimation new_animation1 = new CreatureAnimation(json_data, "default", new_creature);
        CreatureAnimation new_animation2 = new CreatureAnimation(json_data, "second", new_creature);

        System.out.println("Loading creature manager...");
        // Create manager and add in animations
        CreatureManager new_creature_manager = new CreatureManager(new_creature);
        new_creature_manager.AddAnimation(new_animation1);
        new_creature_manager.AddAnimation(new_animation2);

        new_creature_manager.SetActiveAnimationName("default", false);
        new_creature_manager.SetIsPlaying(true);
        new_creature_manager.SetShouldLoop(true);

        active_creature_manager = new_creature_manager;

        // load shaders
        final String VERTEX = Gdx.files.internal("MeshBoneShader.vert").readString();
        final String FRAGMENT = Gdx.files.internal("MeshBoneShader.frag").readString();
        ShaderProgram program = new ShaderProgram(VERTEX, FRAGMENT);

        Texture new_texture = new Texture(Gdx.files.internal("character-dragon.png"));

        // Create the creature render object
        active_creature_render = new CreatureRenderer(new_creature_manager,
                new_texture,
                program,
                camera);

        // Set a transformation matrix for the creature
        Matrix4 xform = new Matrix4();
        xform.scl(1.5f);
        active_creature_render.SetXform(xform);
    }

    @Override
    public void render () {
        //Gdx.gl20.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());


        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(img, 0, 0);
        batch.end();

        camera.update();
        active_creature_manager.Update(Gdx.graphics.getDeltaTime());

        active_creature_render.Flush();
    }

}

Custom Time/Frame Range

You can set custom time/frame ranges for the currently active animation. Say you wanted to limit the playback to the frame range of 10 to 20, you would do the following:

new_creature_manager.SetUseCustomTimeRane(true);
new_creature_manager.SetCustomTimeRange(10, 20);

Animation Blending

You can blend between 2 animation clips by doing the following:

curManager.SetBlending(true);   
curManager.SetBlendingAnimations("default", "pose2");
curManager.SetBlendingFactor(0.5);   // 0 to 1 blends between the 2 clips

Speeding up Load Times + Reducing Memory Usage with Creature Flat Binary Data

You can speed up load times + reduce memory usage of large character assets by converting your Creature JSON files over into the Creature Flat Binary Data format. If you are running out of heap memory on your device, we recommend using the Flat Binary Data format for loading of Creature character assets.

First, go onto the Creature Tools Github Page:

1) Go into the FlatData directory.

2) You can either compile the CreatureFlatData converter program or just grab the binaries for your system (Mac or Windows) from the Bin directories.

Running the CreatureFlatData Converter

This is a command line program that will take your input exported Creature Character JSON file and convert it into a binary Creature Flat Data file. We recommend you use for the final converted output binary file to have an extension of .bytes so that Unity can recognize it as a binary asset.

To run the CreatureFlatData Converter, load up the terminal/command prompt:

CreatureFlatData <Input JSON File> <Output .bytes File>

Using the Creature Flat Binary in LibGDX

The loading code is very similar to the JSON loading code. Here is a short code snippet to show you how to load a flat data binary file:

String baseResourcePath = "C:\\Mydata\\";
String flatFilename = baseResourcePath + "character_raptor_data.bytes";
String pngFilename = baseResourcePath + "character_raptor_img.png";

// Load flat data
CreatureFlatDataJava.rootData flat_data = CreatureModuleUtils.LoadCreatureFlatData(flatFilename);

// Create creature
Creature new_creature = new Creature(flat_data);

// Create animations
CreatureAnimation new_animation1 = new CreatureAnimation(flat_data.dataAnimation(), "default");

The above code demonstrates the loading of both the creature flat data file and also the creation of a Creature character object and its corresponding animation object. Once those objects have been created, you can proceed as normal.

Overriding/Modifying Bone Positions

Sometimes you need to modify the bone positions of the character directly. For example, you might want the positions of the bones to follow a number of rigid bodies connected with springs/joints for ragdoll physics. In the cases where you need to set bone positions for your own custom requirements, you should do the following. First, write your custom bone override method and then assign it to your CreatureManager object. Here is an example that displaces the bones in y by some amount:

    // This is an example of how to set a custom override callback function
    // to modify the bones during playback. In this example, we are displacing
    // the bones in the character by a fixed amount in y
    active_creature_manager_2.SetBonesOverrideCallback(
            new CreatureManager.BonesCallback() {
                public void run(HashMap<String, MeshBone> bones_map)
                {
                    for (HashMap.Entry<String, MeshBone> entry : bones_map.entrySet()) {
                        MeshBone cur_bone = entry.getValue();
                        Vector3 cur_start_pt = cur_bone.getWorldStartPt();
                        Vector3 cur_end_pt = cur_bone.getWorldEndPt();

                        cur_start_pt.y += 17.5;
                        cur_end_pt.y += 17.5;

                        cur_bone.setWorldStartPt(cur_start_pt);
                        cur_bone.setWorldEndPt(cur_end_pt);
                    }
                }
            }
    );

Character Instancing and Memory

If you need to instance multiple copies of a character(for example 2 dragons), you should create a new Creature object, a new CreatureManager object and a new CreatureRenderer object.

You will add the created animations into your newly created CreatureManager object like this:

new_creature_manager_2.AddAnimation(new_animation_1);
new_creature_manager_2.AddAnimation(new_animation_2);

The memory allocated for the animations(the most expensive) are stored in a standard location. Multiple CreatureManager objects will add animations from a common pool of CreatureAnimation objects.