Animation Control

Header: Core/include/Core/Components.h

Animator Component

The Animator component controls skeletal animation playback on entities with skinned models:

FieldTypeDefaultDescription
clipIndexint0Index of the current animation clip
timefloat0.0Current playback time in seconds
speedfloat1.0Playback speed (2.0 = double speed)
playingbooltrueWhether animation is playing
loopbooltrueWhether to loop at the end
boneMatricesvectoremptyOutput matrices (set by the engine)

Switching Animation Clips

Change clipIndex to play a different animation:

void OnUpdate(flecs::entity e, Engine &engine, float dt) override {
  auto *anim = e.get_mut<Animator>();
  if (!anim)
    return;

  // Switch to clip 3
  anim->clipIndex = 3;
  anim->time = 0.0f;     // restart from beginning
  anim->playing = true;
}

Controlling Playback

auto *anim = e.get_mut<Animator>();

anim->playing = false;   // pause
anim->playing = true;    // resume
anim->speed = 0.5f;      // half speed
anim->speed = 2.0f;      // double speed
anim->speed = -1.0f;     // reverse playback
anim->loop = false;      // play once then stop
anim->time = 0.0f;       // jump to start

Example: Idle/Walk Animation

Switch between idle and walk animations based on player movement:

class PlayerBehavior : public Behavior {
public:
  void OnUpdate(flecs::entity e, Engine &engine, float dt) override {
    auto &input = engine.GetInput();
    float vx = 0.0f, vz = 0.0f;
    float speed = 4.0f;

    if (input.IsKeyDown(GLFW_KEY_W)) vz -= speed;
    if (input.IsKeyDown(GLFW_KEY_S)) vz += speed;
    if (input.IsKeyDown(GLFW_KEY_A)) vx -= speed;
    if (input.IsKeyDown(GLFW_KEY_D)) vx += speed;

    bool moving = (vx != 0.0f || vz != 0.0f);

    auto *anim = e.get_mut<Animator>();
    if (anim) {
      int desiredClip = moving ? m_WalkClip : m_IdleClip;
      if (anim->clipIndex != desiredClip) {
        anim->clipIndex = desiredClip;
        anim->time = 0.0f;
        anim->playing = true;
      }
    }

    engine.GetPhysicsWorld().SetHorizontalVelocity(e.id(), vx, vz);
  }

private:
  int m_IdleClip = 0;
  int m_WalkClip = 1;
};
Tip

Animation clip indices correspond to the order animations appear in the glTF/GLB file. Check your model's animation list to find the right index for each action.

Querying Model Animations

If you have access to the entity's model, you can query clip names and counts:

auto *mr = e.get<ModelRenderer>();
if (mr && mr->model) {
  int count = mr->model->GetClipCount();
  for (int i = 0; i < count; i++) {
    std::string name = mr->model->GetClipName(i);
    // name might be "Idle", "Walk", "Run", "Attack", etc.
  }
}