Drawing animated models

Beginner Getting started

In tutorial Drawing your first 3D model you have learnt how to draw static models. This time we are going to have a look at how to draw animated characters.

We will be using a survivor character by Kenney.nl. The original package comes with animations in separate files, but when converting animated models to BBMOD, you must have the model and its animations in a single file! To make things a little easier for you, we have already joined the files into a single FBX and you can download it from here.

Note: We have used command BBMOD.exe .\Character.fbx -iw=true -lh=false to convert the FBX to BBMOD.

Contents

Animated materials

In Drawing your first 3D model we have created our own material by creating a copy of BBMOD_MATERIAL_DEFAULT. While this works for static models, animated models contain extra data that the shader used in this material does not account for. To fix this, we simply use BBMOD_MATERIAL_DEFAULT_ANIMATED instead:

var _matCharacter = BBMOD_MATERIAL_DEFAULT_ANIMATED.clone(); // <- Instead of BBMOD_MATERIAL_DEFAULT
_matCharacter.BaseOpacity = sprite_get_texture(SprCharacter, 0);
global.resources.Materials.Character = _matCharacter;

You can download sprite SprCharacter from here. Do not forget to check the "Separate Texture Page" option after you add it into your project.

Loading animations

When we convert a model that has animations, they are stored as separate *.bbanim files. Same as with *.bbmod, we have to put them first into the Included Files to be able to load them. Loading animations is straight forward just like loading models, we only have to use struct BBMOD_Animation instead of BBMOD_Model:

global.resources = {
    Animations: {}, // <- Add Animations struct here
    Materials: {},
    Models: {},
};

// Load model:
global.resources.Models.Character = new BBMOD_Model("Data/Character.bbmod")
    .set_material("skin", _matCharacter)
    .freeze();

// Load animations:
global.resources.Animations.Idle = new BBMOD_Animation("Data/Character_Root_Idle.bbanim");
global.resources.Animations.Run = new BBMOD_Animation("Data/Character_Root_Run.bbanim");
global.resources.Animations.Jump = new BBMOD_Animation("Data/Character_Root_Jump.bbanim");

Adding an animation player

BBMOD offers multiple ways of playing animations, the simplest one being using the BBMOD_AnimationPlayer struct. We will want to create one for every instance that plays animations, which we can do in the Create event of our character object:

model = global.resources.Models.Character;
// Create an animation player for the model:
animationPlayer = new BBMOD_AnimationPlayer(model);

An animation player needs to be updated every frame. This is done using the update method, so we will put it into the Step event of our character object:

animationPlayer.update(delta_time);

In the Draw event we want to use the submit method of the animation player instead of the model's submit:

bbmod_material_reset();
new BBMOD_Matrix()
    .RotateZ(-90)
    .RotateX(90)
    .Scale(100, 100, 100)
    .Translate(x, y, 0)
    .ApplyWorld();
animationPlayer.submit(); // <- Use animationPlayer instead of model here
new BBMOD_Matrix().ApplyWorld();
bbmod_material_reset();

Playing animations

Our character object is now fully prepared for playing animations. This can be done using the animation player's method change in the Step event:

// This is just to shorted the code a bit:
var _animations = global.resources.Animations;
// This will be the animation we want to change to if it is not the current one
// (or none is being played). We will make it default to the Idle animation:
var _animationNew = _animations.Idle;
// Play Run animation when we hold the W key:
if (keyboard_check(ord("W")))
{
    _animationNew = _animations.Run;
}
// Change to the new animation (true to loop):
animationPlayer.change(_animationNew, true);
// Update the animation player:
animationPlayer.update(delta_time);

Animation events

You may have noticed that we have not used our jumping animation yet. That is because we need to handle its playback a bit differently - we want to press a key only once and keep playing the animation until it finishes. For this we can use the animation player's method on_event to add a listener that is executed when an animation event BBMOD_EV_ANIMATION_END is triggered, which happens at the end of every animation we play. Lets begin by adding following code to the Create event of our character:

animationPlayer.on_event(BBMOD_EV_ANIMATION_END, method(self, function (_animation) {
    // When the Jump animation ends, change back to Idle animation:
    if (_animation == global.resources.Animations.Jump)
    {
        animationPlayer.change(global.resources.Animations.Idle);
    }
}));

Now we can slightly modify the Step event to play the jumping animation when we press space and then not call the change method while we are playing it, which we can tell from the read-only Animation property of the animation player:

var _animations = global.resources.Animations;
if (animationPlayer.Animation != _animations.Jump)
{
    var _animationNew = _animations.Idle;
    var _animationLoop = true;
    if (keyboard_check(ord("W")))
    {
        _animationNew = _animations.Run;
    }
    if (keyboard_check_pressed(vk_space))
    {
        _animationNew = _animations.Jump;
        _animationLoop = false;
    }
    animationPlayer.change(_animationNew, _animationLoop);
}
animationPlayer.update(delta_time);

Animations

Congratulations, you have rendered you first 3D animated character in GameMaker using BBMOD!

Could not find what you were looking for?

We are still working on more tutorials. If you need additional help with BBMOD, please have a look at the documentation or join our Discord community. Thank you for your patience.