This dev blog is proving to be far more time consuming than I expected. And I don’t even get paid to write it. 🙁
Avatar movement broadly breaks into three parts:
1. Motion (forward, back, turn, fast slow, etc.)
2. Animations (walk, run, turn, etc.)
3. Collision
At first glance, this looks ripe for a separation of concerns. Indeed, initial experimentation was promising. Movement and an appropriate animation were displayed on key press events/triggers in completely separate sections of code, while collision response was handled independently by the physics engine. However, with more motions and animations (e.g. jumping) it becomes necessary for the different parts of the system to interact. For instance, while the avatar is jumping all key presses are ignored, so the movement code needs to know when the jump animation has stopped.
Animation Control
It turns out that Finite State Machines aren’t suitable for animation control. I tried state-machine.js, which is a fine tool, but FSMs only work when there only a few animations to wrangle. Even with only four or five animations, I faced a combinatorial explosion, plus much repetition and fiddly edge cases.
I’d prefer to use an existing, built-in animation manager (such as Unity’s) but PlayCanvas doesn’t provide one, yet. Although, Mike Talbot has done some work on Root Motion and Animation Blend Trees.
For now, I’m using a “tabular” method, it’s wasteful, but fairly easy to understand and maintain, It’s not the best method by any means but it’ll have to do for now.
AnimationBlending.animations = {
stand: { default: 'idle.json', forward: 'idle.json', left: 'idle_left.json', right: 'idle_right.json', back: 'idle.json', jump: 'jump.json', },
walk: { default: 'walk_back.json', forward: 'walk_back.json', left: 'walk_back.json', right: 'walk_back.json', back: 'walk_back.json', jump: 'jump.json', },
run: { default: 'run_forward.json', forward: 'run_forward.json', left: 'run_forward.json', right: 'run_forward.json', back: 'run_forward.json', jump: 'running_jump.json', },
};
Extending animations/behaviour is difficult. Adding a relatively simple jump action was awkward, requiring an additional pause, to accommodate a squat down before the jump proper.
I’m now at bit of a loss as to where to go from here. I can have broken animation or incomplete movement (i.e. no jumping) or spaghetti code to paper over the cracks. Back to the drawing board?
Summary
Animation is easy. Animation management is hard
Animations are specific to a given model and can’t be shared/re-used, and it can be a pain to find the animation that does just what you want.
PlayCanvas’s animation system lacks maturity. In particular
● there are no animation related events
(e.g. to alert when an animation has ended)
● there is no mechanism for mixing animations
(using parts from different animations, rather than just blending between whole animations)
Consequently, in PlayCanvas, animations need to be kept simple or even avoided all together, say, by writing an FPS and having static characters (as in “Thomas Was Alone“).