
Godot 2D 角色动画实战3 步搭出骨骼动画 状态机【免费下载链接】godot-demo-projectsDemonstration and Template Projects项目地址: https://gitcode.com/GitHub_Trending/go/godot-demo-projectsgodot-demo-projects 是 Godot 引擎的官方示例合集。其中 2d/skeleton 示例用 Skeleton2D 骨骼动画加 AnimationTree 状态机实现了会走、会跑、会跳的 2D 角色2d/finite_state_machine 示例则额外演示了代码层的分层状态机。沿着输入 → 物理 → 状态判定 → 动画播放 → 骨骼变换这条数据流线把这条角色动画链路逐段拆开看。1. 先理清数据流线谁在驱动谁2D 角色动画翻车多半是链路中某一环断了分工记牢物理系统决定角色现在处于什么状态脚本只负责把状态名写进 AnimationTree 参数状态之间的混合、过渡、回放全部由 AnimationTree 内部完成脚本不手动混两个动画。2. 第 1 步骨骼层20 根骨骼与它们携带的动画轨道2.1 骨骼层级以 Hip 为根示例角色 gBot 挂在CharacterBody2D下player.tscn骨架结构是Skeleton2D是骨骼容器内部是一棵Bone2D层级树根骨骼 Hip其下接 Chest再分 Head/Chin 与左右两条手臂链Arm→Forearm→Hand以及左右两条腿链Leg→LowerLeg→Foot。层级父子关系决定了动画写法动 Hip 带动全身动 Arm 只摆一条手臂关键帧因此可以很少。2.2 动画轨道实际追踪什么看 player.tscn 里的 Animation 轨道可以发现绝大多数轨道是各Bone2D:rotation_degrees只有一条Hip:position。也就是说角色在动靠的是整树旋转加 Hip 的轻微上下起伏AnimationPlayer 播放时把采样到的骨骼变换写回 Skeleton2D蒙皮后的贴图跟随变形。3. 第 2 步AnimationTree 接线5 个循环状态 3 个一次性动画3.1 树结构Transition 管循环OneShot 管事件AnimationTree 的根节点是AnimationNodeBlendTree里面三类节点各司其职5 个循环状态idle / walk / run / fly / fall汇入一个AnimationNodeTransition树内命名 statexfade_time 为 0.1 秒。这是 AnimationTree 过渡配置的核心切状态时自动做交叉淡化。3 个一次性动画jump / land / land_hard各自套AnimationNodeOneShot播放一次后自动回到原循环状态不用写播完切回的逻辑。2 个时标节点walk_timescale 和 run_timescale都是AnimationNodeTimeScale按水平速度实时调节动画播放速率走得快步频就快。3.2 脚本侧只需写 3 种参数$AnimationTree[parameters/state/transition_request] States.WALK $AnimationTree[parameters/run_timescale/scale] abs(velocity.x) / 60 $AnimationTree[parameters/jump/request] AnimationNodeOneShot.ONE_SHOT_REQUEST_FIREtransition_request写一次即生效之后持续保持该状态不必每帧重复赋值也无需碰 blend 系数手动混动画0.1 秒的淡化由 Transition 节点代劳。4. 第 3 步状态判定写进 _physics_process4.1 一段代码解决空中乱跑与落地反馈player.gd 全文约 100 行流程固定读输入 → 叠加重力上限TERMINAL_VELOCITY 400→ 水平方向用move_toward加速 →move_and_slide()→ 依据结果写动画参数if is_on_floor(): if falling_fast: $AnimationTree[parameters/land_hard/request] AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE no_move_horizontal_time 0.4 elif falling_slow: $AnimationTree[parameters/land/request] AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE if abs(velocity.x) 50: $AnimationTree[parameters/state/transition_request] States.RUN $AnimationTree[parameters/run_timescale/scale] abs(velocity.x) / 60 elif velocity.x: $AnimationTree[parameters/state/transition_request] States.WALK $AnimationTree[parameters/walk_timescale/scale] abs(velocity.x) / 12 else: $AnimationTree[parameters/state/transition_request] States.IDLE两个常见坑在这里被一并规避状态判定只发生在is_on_floor()分支内空中只能选 FLYvelocity.y 0或 FALL不存在腾空跑步落地先按下落速度分档接近 400 算硬着陆超过 300 算普通坠落触发对应 one-shot再落回走/跑/站姿判定。4.2 跳跃手感的一行实现if Input.is_action_just_pressed(jump): is_jumping try_jump() elif Input.is_action_just_released(jump) and velocity.y 0.0: velocity.y * 0.6 # 提前松键削减上升动量短按跳不高、长按跳得高控制感来自这行 0.6 的衰减比任何动画调参都直观。5. 动画状态机不够用时纯代码的分层 FSMAnimationTree 只解决播哪段动画。当状态开始带成本攻击起手、受击僵直、死亡后需要回到受击前的状态就把逻辑抬到代码层。2d/finite_state_machine 的做法每个状态是一个继承state.gd的场景实现enter/exit/handle_input/update四个钩子state_machine.gd用states_stack栈管理状态当前状态播完发出finished(next_state)信号状态机收到后执行_change_statenext 取 previous 时弹出栈顶回退这就是分层的含义——stagger受击结束后能自动回到被击打断前的运动状态场景树即文档states 目录按 motionon_ground / in_air、combat、debug 划分不开代码就能看清角色会做什么。选型标准走/跑/跳/落地这类循环状态 瞬时事件交给 AnimationTree状态带进入成本、退出清理、需要回退的放进代码层 FSM由 FSM 继续向 AnimationTree 写参数两层不冲突。6. 交付前的自查清单AnimationTree 的active默认是 falsedemo 在_ready()里开启。漏掉的表现是动画不动也不报错最容易被忽略。脚本里的States字典必须与树内状态名一一对应写错会静默切错状态而不是报错。落地后要重置falling_fast/falling_slow否则下一次起跳必然伴随一次硬着陆。硬着陆的 0.4 秒no_move_horizontal_time水平锁定期别省否则角色在播放落地动画时还能平移物理与动画脱节。换朝向只改sprite.scale.x正负号不要旋转整个 CharacterBody2D避免碰撞与重力方向跟着翻转。想省性能不动的骨骼不加关键帧循环状态多用 TimeScale 变速而非做第二套动画角色贴图多帧合一进图集减少 draw call。7. 进阶路线动手改player.tscn里 Transition 的 xfade_time 和 0.4 秒锁定值对比过渡手感差异照 state_stack 机制给 FSM 示例加一个开枪状态练习 enter/exit 钩子与 finished 信号骨骼动画用到极限后看 3d/ik 示例 了解 IK 反向驱动骨骼的思路2D 的 Skeleton2D 同样支持代码驱动骨骼。git clone https://gitcode.com/GitHub_Trending/go/godot-demo-projects克隆后直接打开2d/skeleton和2d/finite_state_machine两个目录即可对照源码。【免费下载链接】godot-demo-projectsDemonstration and Template Projects项目地址: https://gitcode.com/GitHub_Trending/go/godot-demo-projects创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考