AmbientRun / Ambient

The multiplayer game engine
https://ambient.run
Apache License 2.0
3.79k stars 122 forks source link

Explore better APIs to mix and manage more than two animations #609

Open chaosprint opened 1 year ago

chaosprint commented 1 year ago

The current API only supports a blend of two animations.

But it's very common to have more than 2 animations blending together, e.g. walk fd + walk rt + idle transition.

The current API will make the complexity of animation management increase exponentially: https://github.com/AmbientRun/afps/blob/main/src/fpsanim/anim.rs

chaosprint commented 1 year ago

@FredrikNoren Perhaps don't need a specific state machine.

Instead, we can query all the information we need. The developer just needs to: write a function to convert the query result to the blend state at each frame, say:

{
  walk_forward: 0.1,
  walk_left: 0.1,
  jump: 0.6,
  idle: 0.0,
  fire: 0.0,
 ...
}

A more challenging question is: how can we set the blend?

 spawn_query((player(), components::player_model_ref())).bind(move |v| {
        for (id, (_, model)) in v {
            let walk_fd = PlayClipFromUrlNode::new(
                asset::url("assets/anim/Walk Forward.fbx/animations/mixamo.com.anim").unwrap(),
            );
            let jump = PlayClipFromUrlNode::new(
                asset::url("assets/anim/Rifle Jump.fbx/animations/mixamo.com.anim").unwrap(),
            );
            let idle = PlayClipFromUrlNode::new(
                asset::url("assets/anim/Rifle Aiming Idle.fbx/animations/mixamo.com.anim").unwrap(),
            );

            let walk_fd_jump = BlendNode::new(&walk_fd, &jump, 0.5); // hard to determine the weight here
            let walk_fd_jump_idle = BlendNode::new(&walk_fd_jump, &idle, 0.5); // hard to determine the weight here

            let anim_player = AnimationPlayer::new(&walk_fd_jump_idle);
            entity::add_component(model, apply_animation_player(), anim_player.0);
            entity::add_component(id, components::player_jumping(), false);
        }
    });

With the current API, I need to blend all the clips two by two from left to right. And every time we need to update the weight, we need to set the corresponding weight, which can be hard to calculate.

FredrikNoren commented 1 year ago

@chaosprint Well that will only almost work; you'll still need to keep some kind of state for animations that should only start playing at a transition (going from walking to jumping; the jump animation should start playing when is_jumping goes from false to true).

For setting the blend, there's a function on the BlendNode