MonoGame Runtimes

Overview

This document describes how to use the MonoGame runtimes. The language of the runtimes is in C#. 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.

Using Namespaces

Here are the namespaces declared:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using MeshBoneUtil;
using CreatureModule;
using CreatureRenderer;
using System.Collections.Generic;

Loading and Initialization

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

Dictionary<string, object> load_data = 
    CreatureModule.Utils.LoadCreatureJSONData("dragonTest.json");
curCreature = new CreatureModule.Creature(ref load_data);

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:

curManager = new CreatureModule.CreatureManager (curCreature);

curManager.CreateAnimation (ref load_data, "default");
curManager.CreateAnimation (ref load_data, "pose2");

In the example above, the JSON file has 2 animation clips: default and pose2. 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 for playback:

curManager.SetActiveAnimationName ("default");

This sets default as the currently active animation. We will now go ahead and create the objects required to render the character animation:

Texture2D curTexture;
curTexture = Content.Load<Texture2D> ("character-dragon");

curRenderer = new CreatureRenderer.Renderer (graphics.GraphicsDevice, curManager, ref curTexture);
curRenderer.world = Matrix.CreateScale (new Vector3(35.0f, 35.0f, 1.0f));

This creates a creature renderer with our texture atlas image file. Once that is done, we can go ahead and set some playback properties:

curManager.SetIsPlaying (true);
curManager.should_loop = true;

Character Animation and Rendering Updates

Once we have loaded the character, we need to call the corresponding update calls in 2 callbacks to update the animation and render the character. To update the animation with a time delta of say, 0.025, put the following code in the Update() callback:

protected override void Update (GameTime gameTime)
{
        // TODO: Add your update logic here     
        curManager.Update (0.025f);
        ...
}

After that, put the following code to render the character in the Draw() callback:

protected override void Draw (GameTime gameTime)
{
    // Clear the backbuffer
    graphics.GraphicsDevice.Clear (Color.CornflowerBlue);

    //TODO: Add your drawing code here
    base.Draw (gameTime);

    // This renders the character
    curRenderer.DoUpdate (graphics.GraphicsDevice);
}

Complete Code Sample

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

#region Using Statements
using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using MeshBoneUtil;
using CreatureModule;
using CreatureRenderer;
using System.Collections.Generic;


#endregion

namespace Sample
{
    /// <summary>
    /// Default Project Template
    /// </summary>
    public class Game1 : Game
    {

        CreatureModule.Creature curCreature;
        CreatureModule.CreatureManager curManager;
        CreatureRenderer.Renderer curRenderer;
        String curAnimationName;

        #region Fields

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D logoTexture;

        #endregion

        #region Initialization

        public Game1 ()
        {

            graphics = new GraphicsDeviceManager (this);

            Content.RootDirectory = "Assets";

            graphics.IsFullScreen = false;
        }

        /// <summary>
        /// Overridden from the base Game.Initialize. Once the GraphicsDevice is setup,
        /// we'll use the viewport to initialize some values.
        /// </summary>
        protected override void Initialize ()
        {
            base.Initialize ();
        }


        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent ()
        {
            Dictionary<string, object> load_data = CreatureModule.Utils.LoadCreatureJSONData("dragonTest.json");
            curCreature = new CreatureModule.Creature(ref load_data);
            curManager = new CreatureModule.CreatureManager (curCreature);

            curManager.CreateAnimation (ref load_data, "default");
            curManager.CreateAnimation (ref load_data, "pose2");

            curAnimationName = "default";
            curManager.SetActiveAnimationName (curAnimationName);
            curManager.SetIsPlaying (true);
            curManager.should_loop = true;

            Texture2D curTexture;
            curTexture = Content.Load<Texture2D> ("character");

            curRenderer = new CreatureRenderer.Renderer (graphics.GraphicsDevice, curManager, ref curTexture);
            curRenderer.world = Matrix.CreateScale (new Vector3(35.0f, 35.0f, 1.0f));
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update (GameTime gameTime)
        {
            // TODO: Add your update logic here     
            curManager.Update (0.025f);

            base.Update (gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself. 
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw (GameTime gameTime)
        {
            // Clear the backbuffer
            graphics.GraphicsDevice.Clear (Color.CornflowerBlue);

            //TODO: Add your drawing code here
            base.Draw (gameTime);

            curRenderer.DoUpdate (graphics.GraphicsDevice);
        }

        #endregion
    }
}

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:

curManager.use_custom_time_range = true;
curManager.custom_start_time = 10;
curManager.custom_end_time = 30;

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

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. Here is an example that displaces the bones in y by some amount:

// This demonstrates the ability to override/modify bone positions

void UpdateBonesToCustomPositions(Dictionary<string, MeshBoneUtil.MeshBone> bones_map)
{
    foreach(KeyValuePair<string, MeshBoneUtil.MeshBone> entry in bones_map)
    {
        var cur_bone = entry.Value;
        // displace each bone upwards by y as an example
        var cur_world_start_pos = cur_bone.getWorldStartPt();
        var cur_world_end_pos = cur_bone.getWorldEndPt();

        float displace_y = -20.0f;
        cur_world_start_pos.Y += displace_y;
        cur_world_end_pos.Y += displace_y;

        cur_bone.setWorldStartPt(cur_world_start_pos);
        cur_bone.setWorldEndPt(cur_world_end_pos);
    }

}

You will also need to tell the CreatureManager to use your custom bone modify callback like this:

    // The following code sets an optional bone override callback for modifying bone positions
    CreatureManager cur_manager = creature_renderer.creature_manager;
    cur_manager.bones_override_callback = UpdateBonesToCustomPositions;

Character Instancing and Memory

If you need to instance multiple copies of a character(for example 2 dragons), you should create your animations like this instead:

var new_animation_1 = new CreatureModule.CreatureAnimation(ref load_data, "default");
var new_animation_2 = new CreatureModule.CreatureAnimation(ref load_data, "pose2");

You should then proceed to you 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 difference between this example and the previous is that the animations are first created, then added into their respective CreatureManagers. This means 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.