Tag Archives: PlayCanvas

Even more animation with PlayCanvas

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“).

“Thomas Was Alone” uses simple shapes to reduce animation

Collision fun

The project can be found here.

So, another week, another problem to solve.

After working through the wrinkles of importing FBX files (with moderate success), my attention turned to animation and moving my avatar (Pearl) around a scene.

Quite quickly it be apparent that there was one section of the map where she fell straight through apparently solid ground. Oh joy! Time for another fluffing diversion!

Oh noes! And you don’t get the full flicker effect here!

My first impulse was to just plug the gap with some box colliders, but that was the too fiddly and inaccurate, and not a scalable solution.

After some experimentation, the faces of making up the gap seemed to be inverted – if turned over through 180° the collider worked. Perhaps the normals were inverted or the winding order of some of the faces were wrong. After further experimentation, this proved to be no practical use and didn’t lead to any practical solution.

Will Eastcott of PlayCanvas suggested subdivision. Clara.io doesn’t do subdivision automatically, but manually subdividing the faces fixed the problem. Again, manual subdivision is not a practical solution and is only of value in small, limited situations.

A search to do automatically subdivide lead to Blender.

The new model looked like pants as parts were too dark.

Original

Looking shady.

The exported subdivided mesh seemed to work fine when tested, but not when added back into the original model as a collider. It turned out that the subdivided mesh was scaled and translated.

Back to our scheduled programme

I simplified the collision by using only the base mesh and using cylinders for trees. This also stops Pearl from bouncing off leaves, and allows her to paddle through water.

I added an animated pulsing effect to random shapes for some visual interest.

Summary

If a collision mesh isn’t working properly:

  1. Subdivide in Blender (Clara.io won’t do it automatically, Maya and Max cost money).
  2. Test that the subdivided mesh actually works.
  3. If it looks good use it.
  4. If it looks like pants, add it to the original as a collision mesh but watch out for changes is scale and position.

Comments

There was a proliferation of PlayCanvas projects to preserve existing work and separate oh, so very many new experiments to test out ideas and such.

I’m having to pick up more than a passing acquaintance with a varied group of tools whether I want to or not. I’m not a fan of Blender, but it looks like the best option in many cases. I’d much prefer Clara.io, but it just doesn’t have all the features I need.