mcpField
B
bevy-animation

bevy-animation

github.com/chrisgliddon开发2682 次安装9 周前更新
代码仓库

关于 bevy-animation

面向 Bevy 0.19 开发者的动画实现参考技能,涵盖动画片段、图、事件和程序化运动。提供经过验证的模式,并介绍混合、glTF 导入、性能及动画十二原则的应用。

主要功能

  1. 01构建混合与叠加动画图
  2. 02播放并交叉淡入动画片段
  3. 03触发片段时间线事件
  4. 04创建程序化缓动与曲线
  5. 05提供 glTF 导入和性能指导

适用场景

  1. 01混合待机、行走和奔跑动画
  2. 02根据动画片段触发脚步或特效
  3. 03不使用 AnimationClip 对变换进行补间
  4. 04排查 Blender 到 glTF 的骨骼动画问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chrisgliddon/bevy-skills --skill bevy-animation

安装后在 Claude Code 中输入/bevy-animation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
animation-events.md
animation-graph.md
curves-and-tweening.md
gltf-import.md
performance.md
principles-authoring.md
principles-easing-and-timing.md
principles-graph-layering.md
principles-transform-keyframes.md
procedural-animation.md
state-machines.md

详细介绍

Bevy 0.19 — 动画(图、混合、事件、12 项原则)

适用场景

  • 加载 glTF 动画片段并在角色上播放:AnimationPlayer + AnimationGraphHandle。
  • 通过 AnimationTransitions::play(player, node, Duration) 在待机 / 行走 / 奔跑动画之间交叉淡入淡出。
  • 在代码中构建 AnimationGraph:混合节点、加法节点、权重、AnimationMask。
  • 从动画片段时间线上触发游戏事件(脚步声、碰撞箱激活、VFX 提示):使用 #[derive(AnimationEvent)] + clip.add_event_to_target(...) + On<MyEvent> 观察器。
  • 在没有 AnimationClip 的情况下进行程序化补间——每帧通过 EasingCurve + EaseFunction 或 CubicSegment::new_bezier_easing 对 Curve 采样。
  • 将动画 12 项基本原则(Thomas & Johnston,1981)应用于 Bevy 角色。
  • 导入 Blender 骨架,发现骨骼没有动画——通常是因为 AnimationTargetId::from_name 需要 Name。

端到端标准模式

已通过 bevy = "0.19" 验证——bevy-skills-tester/skill-snippets/examples/bevy_animation.rs 中的 cargo check 检查通过。

use bevy::{
    animation::{
        animated_field,
        animation_curves::{AnimatableCurve, AnimatableKeyframeCurve},
        AnimationEvent, AnimationTargetId,
    },
    prelude::*,
};
use core::time::Duration;

#[derive(AnimationEvent, Clone)]
struct FootstepEvent { foot: u8 }

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut clips: ResMut<Assets<AnimationClip>>,
    mut graphs: ResMut<Assets<AnimationGraph>>,
) {
    // 1. Load a glTF clip
    let walk: Handle<AnimationClip> =
        asset_server.load("models/character.glb#Animation0");

    // 2. Build a tiny procedural clip with a sample curve + an event
    let bone = AnimationTargetId::from_name(&Name::new("Hips"));
    let tween = AnimatableKeyframeCurve::new([
        (0.0_f32, Vec3::ZERO),
        (0.5,     Vec3::new(0.0, 1.0, 0.0)),
        (1.0,     Vec3::ZERO),
    ]).expect("strictly-increasing times");
    let curve = AnimatableCurve::new(animated_field!(Transform::translation), tween);
    let mut proc = AnimationClip::default();
    proc.add_curve_to_target(bone, curve);
    proc.add_event(0.5, FootstepEvent { foot: 0 });
    let proc = clips.add(proc);

    // 3. Compose a graph: root → walk + additive(proc, mask=group 0 excluded)
    const MASK_GROUP_0_BIT: u64 = 1 << 0;
    let mut graph = AnimationGraph::new();
    let root = graph.root;
    let _walk_node = graph.add_clip(walk, 1.0, root);
    let additive = graph.add_additive_blend(0.5, root);
    let _proc_node = graph.add_clip_with_mask(proc, MASK_GROUP_0_BIT, 1.0, additive);

    // 4. Spawn the player entity (bones come from the loaded glTF scene)
    commands.spawn((
        Name::new("AnimationRoot"),
        AnimationPlayer::default(),
        AnimationGraphHandle(graphs.add(graph)),
        AnimationTransitions::new(),
    ));
}

fn start(mut q: Query<(&mut AnimationTransitions, &mut AnimationPlayer), Added<AnimationPlayer>>) {
    use bevy::animation::{graph::AnimationNodeIndex, RepeatAnimation};
    for (mut tx, mut player) in &mut q {
        tx.play(&mut player, AnimationNodeIndex::new(1), Duration::from_millis(250))
            .set_repeat(RepeatAnimation::Forever);
    }
}

fn on_footstep(trigger: On<FootstepEvent>) {
    let foot = trigger.foot;                        // On<E> derefs to &E
    let _entity = trigger.trigger().target;          // AnimationEventTrigger::target
    let _ = foot;
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)                 // gltf_animation is a default feature
        .add_systems(Startup, setup)
        .add_systems(Update, start)
        .add_observer(on_footstep)
        .run();
}

主题

主题参考资料
构建混合 / 加法图、AnimationMask、热切换references/animation-graph.md
Blender → glTF → Bevy 导入:Name、坐标轴、多动画片段、不支持的扩展references/gltf-import.md
Update 与 FixedUpdate 中的程序化动画、根运动提取references/procedural-animation.md
待机 / 行走 / 奔跑混合;AnimationTransitions::play 与 Bevy States 集成references/state-machines.md
#[derive(AnimationEvent)]、add_event_to_target、On<E> 观察器连接references/animation-events.md
AnimatableCurve、EasingCurve、EaseFunction、三次贝塞尔、UnevenSampleAutoCurvereferences/curves-and-tweening.md
AnimationPlayer 开销、蒙皮缓冲区、图复杂度、运行时图切换references/performance.md
原则 — 缓入 / 缓出、节奏、预备动作 → 缓动 + 时长references/principles-easing-and-timing.md
原则 — 挤压与拉伸、弧线、夸张 → Transform 关键帧references/principles-transform-keyframes.md
原则 — 构图、跟随动作、次要动作 → 图分层 + 遮罩references/principles-graph-layering.md
原则 — 直线动画与姿势动画、立体绘制、吸引力 → 上游创作references/principles-authoring.md

动画 12 项基本原则

四份 principles-*.md 参考资料按照 Bevy 实际运用的基本构件,对 Thomas & Johnston 提出的 12 项原则进行归类。快速概览:

  • 缓动与节奏 — 缓入 / 缓出、节奏、预备动作对应 EaseFunction / EasingCurve / CubicSegment::new_bezier_easing,以及动画片段时长和 ActiveAnimation::set_speed。
  • Transform 关键帧 — 挤压与拉伸、弧线、夸张通过 animated_field!,对 Transform::scale / ::translation 使用 AnimatableKeyframeCurve。
  • 图分层 — 构图、跟随动作与重叠动作、次要动作对应 AnimationGraph::add_additive_blend + AnimationMask 分组隔离。
  • 创作 — 直线动画与姿势动画、立体绘制、吸引力属于 DCC 工具(Blender、Maya)的范畴。Bevy 会播放你创作的内容。

易错点

  • 目标组件已拆分。 AnimationTarget { id, player } 已不复存在。 骨骼实体使用 AnimationTargetId(Uuid) 加上 AnimatedBy(Entity);glTF 加载器会同时提供这两个组件。
  • 重新生成持久化的目标 ID。 Bevy 0.19 更改了 AnimationTargetId 的计算算法。必须根据层级/名称路径重新计算从 0.18 序列化的目标 ID。
  • gltf_animation 默认启用。 它已包含在 bevy = "0.19" 的默认功能中——除非你使用了 default-features = false,否则无需选择启用。
  • AnimationTransitions::play_with_transition 并不存在。 实际上唯一的方法是 play(&mut self, player, node, Duration) -> &mut ActiveAnimation。在返回值上链式调用 .set_repeat(RepeatAnimation::Forever)/.set_speed(f32)。
  • animated_field! 和 AnimatableCurve 不在 prelude 中。 请从 bevy::animation::{animated_field, animation_curves::{AnimatableCurve, AnimatableKeyframeCurve}} 显式导入。
  • On<AnimationEvent> 不是 EntityEvent 观察器。 On<E> 解引用为 &E(可直接访问事件字段)。触发实体位于 trigger.trigger().target(AnimationEventTrigger::target 字段在 0.18 中由 animation_player 重命名而来)。不能使用 .target()——该方法用于 EntityEvent。
  • 骨骼实体必须包含 Name,这样 AnimationTargetId::from_name(&Name) 才能解析。glTF 加载器会设置此组件;手动构建的骨架也必须设置。
  • AnimationMask 的位极性。 节点的 u64 掩码中某个位被置位,意味着该节点不会为该组中的目标设置动画。通过 graph.add_target_to_mask_group(target_id, group_u32) 将骨骼注册到一个组。若要将节点限制在单个组中,应设置除该组以外的所有位。
  • 调度。 Bevy 的动画系统在 PostUpdate 中运行,并通过 .before(TransformSystems::Propagate) 链接。也会写入 Transform 的过程式系统应在 Update 中运行,或明确指定其相对于 PostUpdate 中 AnimationSystems 的顺序。
  • 核心动画不涵盖的内容。 不内置 IK,粒子/特效系统是独立的,且 glTF 加载器未实现 KHR_animation_pointer——参见 references/gltf-import.md。

另请参阅

  • bevy-cameras — 摄像机动画(平移、推拉、跟随焦点)与此技能有所重叠;使用相同的 EaseFunction/EasingCurve 工具集。
  • bevy-core-concepts — 过程式动画中 Update 与 FixedUpdate 的选择很重要;参见 procedural-animation.md。
  • bevy-ecs-systems — 用于 AnimationEvent 的观察器连接模式(On<E>、add_observer)。
  • bevy-pbr-materials — 通过 AnimatableCurve 为 StandardMaterial 字段设置材质参数动画(自发光闪烁、Alpha 淡变)。
  • bevy-custom-assets — 如果你将 AnimationGraph 序列化为 RON(.animgraph.ron)并作为资源加载,可参考其中的 AssetLoader 模式。
  • bevy-migration-0-18-to-0-19 — 持久化目标 ID 和变形目标资源的变更。

评论

支持 Markdown