Drawing animated models
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
- Loading animations
- Adding an animation player
- Playing animations
- Animation events
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);
Congratulations, you have rendered you first 3D animated character in GameMaker using BBMOD!