PixiJS Runtimes
Monday, September 18, 2017 3:27 AMOverview
This document describes how to use the PixiJS runtimes. The language of the runtimes is in JavaScript. 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.
Picking a File Format and Runtime type
There are 2 types of runtimes you can choose: JSON/Creature FlatData or CreaturePack Web Format.
-
JSON/Creature FlatData : Gives you the full bone structure, is more feature complete but larger in size and more expensive to evaluate if you are not using point caching.
-
CreaturePack Web Format. : Only gives you the deformed points, uvs and colours. You do not get the skeletal structure of the character. However, it can be a lot smaller and is very cheap to evaluate, making playback very fast.
JSON/Creature FlatData
Included Scripts
Here are the scripts that need to be included:
<script src="pixi.js"></script>
<script src="https://raw.githubusercontent.com/toji/gl-matrix/master/dist/gl-matrix.js"></script>
<script src="CreatureMeshBone.js"></script>
<script src="CreaturePixiJSRefRenderer.js"></script>
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:
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'default.json', true); // Load the JSON file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
var response = xobj.responseText;
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
...
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:
var new_creature = new Creature(actual_JSON, false);
var new_animation_1 = new CreatureAnimation(actual_JSON, "default", false);
var new_animation_2 = new CreatureAnimation(actual_JSON, "second", false);
var new_manager = new CreatureManager(new_creature);
new_manager.AddAnimation(new_animation_1);
new_manager.AddAnimation(new_animation_2);
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_manager.SetActiveAnimationName("default", false);
new_manager.SetShouldLoop(true);
new_manager.SetIsPlaying(true);
new_manager.RunAtTime(0);
We will now go ahead and create the object(s) required to render the character animation:
// create a texture from an image path
var texture = PIXI.Texture.fromImage("character-dragon.png");
var creatureContainer = new PIXI.DisplayObjectContainer();
creatureContainer.position.x = window.innerWidth/2;
creatureContainer.position.y = window.innerHeight/2;
creatureContainer.scale.set(35.0);
stage.addChild(creatureContainer);
var new_creature_renderer = new CreatureRenderer(new_manager, texture);
creatureContainer.addChild(new_creature_renderer);
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 animate() callback:
function animate() {
requestAnimationFrame( animate );
new_manager.Update(0.05);
new_creature_renderer.refresh();
// render the stage
renderer.render(stage);
}
Complete Code Sample
Here is the complete code layout. Most the the code is generated from the default PixiJS project starter template:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>PixiJs - Basic scene</title>
<style>
canvas {
border: 1px dashed gray;
}
html, body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<h1>My First Web Page</h1>
<p>My first paragraph.</p>
<script src="pixi.dev.js"></script>
<script src="https://raw.githubusercontent.com/toji/gl-matrix/master/dist/gl-matrix.js"></script>
<script src="CreatureMeshBone.js"></script>
<script src="CreaturePixiJSRefRenderer.js"></script>
<script>
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'dragonTest.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
var response = xobj.responseText;
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
new_creature = new Creature(actual_JSON, false);
new_animation_1 = new CreatureAnimation(actual_JSON, "default", false);
new_animation_2 = new CreatureAnimation(actual_JSON, "pose2", false);
var new_manager = new CreatureManager(new_creature);
new_manager.AddAnimation(new_animation_1);
new_manager.AddAnimation(new_animation_2);
new_manager.SetActiveAnimationName("pose2", false);
new_manager.SetShouldLoop(true);
new_manager.SetIsPlaying(true);
new_manager.RunAtTime(0);
// create an new instance of a pixi stage
var stage = new PIXI.Stage(0x000000);
// create a renderer instance.
var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight);
if (renderer.type == PIXI.WEBGL_RENDERER) {
console.log('Using WebGL');
} else {
console.log('Using Canvas');
};
// add the renderer view element to the DOM
document.body.appendChild(renderer.view);
// create a texture from an image path
var texture = PIXI.Texture.fromImage("character-dragon.png");
var creatureContainer = new PIXI.DisplayObjectContainer();
creatureContainer.position.x = window.innerWidth/2;
creatureContainer.position.y = window.innerHeight/2;
creatureContainer.scale.set(35.0);
stage.addChild(creatureContainer);
var new_creature_renderer = new CreatureRenderer(new_manager, texture);
creatureContainer.addChild(new_creature_renderer);
creatureContainer.scale.x = -creatureContainer.scale.x;
function animate() {
requestAnimationFrame( animate );
new_manager.Update(0.05);
new_creature_renderer.refresh();
// render the stage
renderer.render(stage);
}
animate();
}
};
xobj.send(null);
</script>
</body>
</html>
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
Skin Swap
You can swap in/out items/clothing/weapons etc. if you setup Skin Swap groups in the Creature Editor. The Skin Swap information is exported out as a MetaData JSON in the export folder ( it has the .mdata extension ).
First, make sure you load the MetaData JSON into a JSON object in Javascript. Then, you should proceed to create the CreatureMetaData object:
// Create Meta Data object
var meta_data = CreatureModuleUtils.BuildCreatureMetaData(meta_json);
// Assign Meta Data object to your Creature object
new_creature.SetMetaData(meta_data);
To enabled Skin Swapping, call EnableSkinSwap on the CreatureRenderer object:
// This swaps to the new Skin. In this case, we swap into "cape" and enable it to true
new_creature_renderer.EnableSkinSwap("cape", true);
Similarly, to disable skin swap call:
new_creature_renderer.DisableSkinSwap();
Using the Creature Flat Binary
The Creature Flat Data is a binary version of your exported Creature Animated Asset. Binary data in general is more compact and loads much faster than the regular JSON format. For web deployment, the recommended file format is to use the binary FLat Data format.
First, retrieve the binary file as you would in your current framework. Then, do the following:
var actual_data = CreatureModuleUtils.LoadCreatureFlatData(game.cache.getBinary('myFlatDataBinary.bin'));
new_creature = new Creature(actual_data, true);
new_animation_1 = new CreatureAnimation(actual_data, "idle", true);
As you can see, all you are doing is to grab a reference to the flat data object. Then set the last parameter in the Creature and CreatureAnimation creation to true. This triggers a binary flat data load.
CreaturePack Web Format
CreaturePack is a compact, high performance version of your character asset. It lacks certain features ( bones, skin swapping etc. ) compared to the fully featured JSON/FlatBuffers file formats. However, it makes up for that in terms of performance and file size. CreaturePack when tuned correctly is extremely compact and very performant. It is suitable for animating large numbers of crowd characters on screen or on mobile devices where performance is critical.
Tuning the CreaturePack Web Format
In the Game Engine Export Window of Creature, you have the following options:
-
Gap Step : This decides how much approximation is done on export. The higher the number, the smaller the file size but lower the quality. A value of 1 means no approximation. Try anything from 1 to 6.
-
UV Swaps : Check this on or off to decide whether to export UV swapping. If you are using image swaps, you should check this option to ON.
-
Color Changes :Check this on or off to decide whether to export any opacity changes. If you are fading regions, check this option to ON.
File sizes can be reduced quite a bit by increasing the Gap Step at the expense of some quality loss.
JS vs WebAssembly
There are 2 versions of the CreaturePack runtimes: JS and WebAssembly. JS is implemented in regular Javascript and provides very good performance for large numbers of characters. However, you can take advantage of the new WebAssembly standard available in modern browsers for even more impressive playback performance. For the best playback performance, we recommend using the WebAssembly backend for CreaturePack.
Using the CreaturePack JS Runtime
Included Scripts
You will need the following:
<script src="msgpack.js"></script>
<script src="CreaturePackModule.js"></script>
<script src="CreaturePixiPackJSRenderer.js"></script>
Loading and Initialization
Grab the binary buffer of your file and pass it into the CreaturePackLoader:
creature_pack = new CreaturePackLoader(game.cache.getBinary('raptorPack').buffer);
Rendering
Have a look at the file: CreaturePixiJSRenderer.js Also check the Phaser Documentation for more information since it the concepts are very similar.
Using the CreaturePack WebAssembly Runtime
You will need the following:
<script src="../pixi.js"></script>
<script src="CreaturePackWASMPixiJSRenderer.js"></script>
<script src="creaturepack-wasm.js"></script>
Make sure you have the required compiled WebAssembly files contained in this directory. Crucially, you will need the files/libraries with js and wasm extensions.
Loading and Initialization
Grab the binary buffer from your file and call addPackLoader() on your newly created PackManager:
var pack_manager = new Module.PackManager();
var byte_array = new Uint8Array(response);
var load_bytes = CreatureASMUtils.heapBytes(byte_array);
var pack_loader = pack_manager.addPackLoader("Raptor", load_bytes.byteOffset, byte_array.byteLength);
var texture = PIXI.Texture.fromImage("../raptor_img.png");
Create Rendering Objects
Here is how to create the objects for rendering:
// Add CreaturePack objects
var creatureContainer = new PIXI.DisplayObjectContainer();
creatureContainer.position.x = window.innerWidth/2;
creatureContainer.position.y = window.innerHeight/2;
creatureContainer.scale.set(15.0);
stage.addChild(creatureContainer);
var raptor_renderer = new CreaturePackRenderer(pack_manager ,"Raptor", texture);
// Set/Change animation clip
raptor_renderer.packManager.setPlayerActiveAnimation(raptor_renderer.playerId, "clip1");
creatureContainer.addChild(raptor_renderer);
creatureContainer.scale.x = creatureContainer.scale.x;
Updating and displaying Rendering Objects
Here is how you will setup your rendering loop:
function animate() {
requestAnimationFrame( animate );
raptor_renderer.packManager.stepPlayer(raptor_renderer.playerId, 1.0);
raptor_renderer.refresh();
// render the stage
renderer.render(stage);
}
animate();
});
For more information, check out the sample to render a single character here.