前言
之前是按照各个cs文件和文件夹分类的,但这样分类对于理解代码帮助不大,那只是方便使用和修改代码,所以这次文档说明采用业内通用的方法
按照(Assembly,namespace都唯一故不考虑)类,结构体,枚举类型,接口进行分类
每类又分为:
Constructors 构造方法,Fields 字段(一般为Const / readonly声明的变量),Properties 属性(get / set包装的变量)Methods 方法,operator 运算符(比如隐式类型转换运算符)implicit operator AnimancerGraph(AnimancerComponent)
implicit operator AnimancerLayer(AnimancerComponent)
当代码需要 AnimancerGraph 或 AnimancerLayer 时,可以直接把一个 AnimancerComponent 当成它来用,编译器会自动替你做转换。
对于函数,我倾向于如果参数名能帮助理解,则保留否则与业内做法一致,只保留参数类型
Class Types
Animacer
AnimationClip是Unity自带的
StringAsset
StringAsset 是把字符串名字做成资源的 ScriptableObject——名字来自自身的 Object.name,可在 Inspector 中拖拽设置,并在代码里按名字绑定动画参数 / 事件(隐式转换为 StringReference 或 string 使用)。用来集中管理动画参数名、事件名、标签等键值,避免硬编码并便于项目内复用、查找和替换。
这里传进去的 playerSO.playerParameterData.speedValueParameter(StringAsset/StringReference)只是参数名,作用像 Animator.SetFloat("Speed", v) 里的 "Speed"——用来在动画系统里定位一个参数槽。这些字段只是键(名字):用于在 Animancer/Animator 中按名获取并驱动参数,而不是读取某个 C# 变量的值
TransitionAsset
TransitionAsset 的作用(把“过渡/播放方案”做成可复用的资源)
本质:ScriptableObject,继承 TransitionAsset<ITransitionDetailed>,把任意过渡对象(如 ClipTransition、MixerTransition…)存成资源,便于跨 Prefab/角色统一引用与替换。

- Fade Duration(秒):切进这个混合器时,和上一个正在播的状态之间做跨帧淡入/淡出需要的时间”。也就是 前一个状态 ↔ 这个混合器本身 的交叉淡化时长(0 表示瞬切)
- Speed:该混合器整体的播放速度倍率(会乘到所有子状态的速度上)。
- Events:这条过渡自带的 Animancer 事件序列(按归一化时间触发)
- Normalized Time / Callback / Name 共同描述“同一个 Animancer 事件”。简明解释如下(括号里是调用时机):
- Normalized Times
事件触发的时间点,使用归一化时间(0–1 表示当前循环的进度;循环动画每过一圈会再次触发)。若一帧跨过多个循环,会按顺序触发多次;比如0.1就是当前这段动画(或当前这一圈循环)总时长的 10% 位置触发 - Callbacks
真正要调用的函数(非循环:到达该时刻触发一次;循环:每圈到达该时刻都会触发一次)。这些回调既可在 Inspector 里用 UnityEvent/UltEvent 配,也可在代码里绑定(官方更推荐“时间在 Inspector 配,回调在代码里绑”的混合方式)。 - Names
给事件起的“字符串引用”(StringAsset/StringReference)。名字用于在代码里查找并绑定回调,或把同名事件集中路由(Central Event Dictionary)。这样美术/设计可在面板调时间,你在代码里按名字注册处理函数,重命名也更安全。- 另外别混淆与“End Event(结束事件)”:它是每个状态自带的单独事件,默认在正播到 1、倒播到 0 时触发,且在到达后每帧都会再触发(通常用来切下一个动画;若需要才在 Inspector/代码里单独设置它的时间/回调)。
- Animations:子过渡列表。可以是
ClipTransition、其他 Mixer 的 Transition Asset 等,支持嵌套。 - Speeds:可选的“每个子动画的额外速度倍率”。为空就按 1.0 处理(只用上面的整体 Speed)。该数组对应
ManualMixerTransition.Speeds。 - Synchronize Children:为每个子动画勾选“是否参与同步”。同步开启时,混合器会让被勾选的那些子动画在时间相位上对齐(比如走和跑的落脚相位一致),避免混合时脚步错位;常见做法是同步 Walk/Run,但不要同步 Idle。
- Thresholds:每个子动画的阈值(升序且唯一),根据“参数值”自动算权重。混合器会拿你运行时设置的浮点参数,在这些阈值之间做线性插值来给子动画分配权重。
合器内部根据参数给各个子动画分配权重”的规则(线性插值)。它只决定 混合器里面 的子动画比例,不负责与“上一个状态”的过渡,与Fade duration区分。 - Default Parameter:该混合器首次创建时使用的初始参数值(也影响过渡预览)。之后运行时会被你代码里设置的参数覆盖。
- Extrapolate Speed:当“参数值超过最高阈值”时,不再继续权重外推,而是按超出的比例提高混合器速度。下面看一个例子:
| 参数 p | 关掉 Extrapolate | 开启 Extrapolate |
|---|---|---|
| 0.6 | 走:跑 = 40%:60%,速度×1 | 同左(范围内不加速) |
| 1.0 | 只播“跑”,速度×1 | 同左 |
| 1.2 | 只播“跑”,速度×1(还是普通跑) | 只播“跑”,速度×1.2(相当于冲刺) |
- Parameter Name:这个混合器绑定的浮点参数名(用
String Asset存名字,便于重命名和复用)。游戏里你只需改这个参数的值,混合器就会按Thresholds自动给子动画分配权重。
ClipTransition
ClipTransition 的作用(如何播放一个 AnimationClip 的“方案”)
本质:一个可序列化的“过渡/播放配置”,包住一个 AnimationClip,并附带“怎么播”的参数(如淡入、速度、起始时间、事件等,来自 Transition<T> 基类)。

Normalized Start Time:指定从剪辑的哪个“归一化时间”开始播放(0~1)。
NaN(默认):不强制改动起始时间。- 第一次播放这条状态:自然从 0 开始;
- 如果这条状态之前就存在并停在 0.7,再次 Play 且仍为 NaN,就会从 0.7 继续。
- 写
0:每次 Play 都从头开始;写0.5:从一半处开始,依此类推。
ClipTransition和 TransitionAsset的对比
| 对比项 | ClipTransition | TransitionAsset |
|---|---|---|
| 形态 | 一个可序列化的对象,通常作为 组件字段内嵌在 Prefab/场景里 | 一个 ScriptableObject 资产文件,像材质那样单独存在、可被多处引用 |
| 适用场景 | 该对象专属的一小段动画配置(例如“这个怪独有的击飞”) | 多人/多处复用的通用配置(例如“全角色通用的 Run 过渡”或各类混合器) |
| 维护成本 | 每个用到的地方各自保存一份;改动只影响这个对象 | 改一次资产,所有引用处都跟着更新(适合团队协作与调参) |
| 用法代码 | animancer.Play(clipTransition); | animancer.Play(transitionAsset); |
| 内容 | 通常只封装一个剪辑(也有“Clip 只给某处/某个字段配置一个剪辑的播放细节 | 可以是 Clip、也可以是 Mixer(1D/2D/自定义)等复杂过渡,Inspector 里会显示对应的子列表、阈值、参数名等 |
ManualMixerState
一个可手动控制权重的混合器状态:把多个子动画接到一个 Mixer 上,由你在代码里直接设置各子动画的 Weight 来决定最终的混合结果(类似 Mecanim 的 Direct Blend Tree)。
Tool
ExpandClass
Method
| Name | Value | Summary |
| AnimationAtTag(扩展方法) | bool | 判断当前这一层正在播放的 Animator 状态是否带有某个 Tag |
| Add | void | 添加animancerEvent,并更新animancerEventList |
| Remove | void | 移除animancerEvent,并更新animancerEventList |
| RemoveAll | void | 销毁所有在animancerEventList的事件,并清空animancerEventList |
MonoSingleton<T>
需要创建单例的类应继承该泛型类,并在该单例类的Awake生命周期函数中最先调用base.Awake
properties
| Name | Value | Summery |
| Instance | T | 被继承时添加到派生类中,在Awake中初始化 |
BindableProperty<T>
让一个变量属性的值发生变化时,自动触发 ValueChanged 事件
properties
| Name | Value | Summary |
| Value | T |
Delegates
| Name | Value | Summary |
| ValueChanged | Action<T> | 当 Value 值发生变化时,会调用所有订阅的方法,并传入新的值 |
ToolFunction
一组 Unity 静态小工具方法,负责给 Image/RawImage 便捷上色、计算角色与目标的夹角(-180~180°),并按目标高度与重力反推跳跃初速度。
Methods
| Name | Value | Summary |
|---|---|---|
SetImageColorFromVector3(Image, Vector3, float) | void | 用 colorVector 的 RGB 与 alpha 设置 Image.color(alpha 会被 Clamp01)。 |
SetRawImageColorFromVector3(RawImage, Vector3, float) | void | 用 colorVector 的 RGB 与 alpha 设置 RawImage.color(alpha 会被 Clamp01)。 |
SetRawImageColorFromVector3(RawImage, Color, float) | void | 将 colorVector 直接赋给 RawImage.color。当前实现未使用参数 alpha(使用的是 colorVector.a)。 |
GetDeltaAngle(Transform , targetAngle) | float | 计算 player.forward 与“绕 Y 轴 targetAngle 旋转后的方向”的夹角(度),范围 (-180, 180),正负代表左右。 |
GetDeltaAngle(Transform , Vector3) | float | 计算 player.forward 与 toDir 的夹角(度),忽略 Y 分量,范围 (-180, 180)。 |
GetDeltaAngle(Vector3 , Vector3) | float | 计算两个方向向量(忽略 Y)的夹角(度),使用 Atan2 + Mathf.DeltaAngle,范围 (-180, 180)。 |
GetJumpInitVelocity(float jumpMaxHeight, float Gravity) | float | 返回达到高度 h 的初速度:v0 = sqrt(-2 * Gravity * h)(要求重力为负值,结果为速度标量)。 |
Service
InputService
一个基于 MonoSingleton<InputService> 的全局输入服务:在 Awake 中创建并启用 InputMap(新输入系统),在销毁时禁用;对外提供若干只读属性,把底层输入转成更易用的方向量/按钮状态,并对 PC 与 Android 做了区分
public class InputService : MonoSingleton
Constructors
- Awake()(override)
- 先执行基类以建立单例;若
inputMap == null则new InputMap();然后inputMap.Enable().
- 先执行基类以建立单例;若
- OnDestroy()
inputMap.Disable()。
Fields
public InputMap inputMap;
由 Unity 新输入系统生成的输入包装类,绑定所有 Action
Properties
| Name | Type | Summary |
|---|---|---|
GetMoveHorizontalValue | Vector2 | 仅保留水平(X)分量的移动输入:在 Android 直接返回摇杆值;在非 Android,将 dir.y=0 并归一化(跑/走共用,是否按下 Shift 只影响分支但当前逻辑两支等价)。如果没有输入则返回0向量 |
GetMoveVerticalValue | Vector2 | 仅保留垂直(Y)分量的移动输入:将 dir.x=0 后归一化。 |
Interactive | bool | 交互键是否按下(ReadValue<float>() != 0)。 |
Shift | bool | 是否按下 Shift(跑步开关)。 |
Move | Vector2 | 将原始 Move 轴离散化为 {-1,0,1}(分别处理 x/y)。 |
Scroll | Vector2 | 滚轮/滚动轴的当前值直通返回。 |
EventService
没有用到,解析见阅读优秀代码 – Skyshin34的博客
TimerService
计时任务相比简单计时器外具备计时结束/终止回调函数,记录绝对发生时间和设置循环次数的功能
| Name | Value | Summary |
|---|---|---|
AddTimer(int time, Action taskCB, Action cancelCB = null, int count = 1) | public int | 注册一个任务:time计时时长taskCB为计时结束后的回调(FinishTimer -> CallTaskCB), cancelCB是计时任务删除是的回调(DeleteTimer) count计时次数 <=0 表示无限循环返回计时任务 tid |
RemoveTimer(int tid) | public void | 通过 tid 注销任务若提供了 cancelCB 按TickTimer 的策略被调用 |
TickTimer(TimerService的核心)
轮询:**轮询(polling)**就是:自己隔一段时间就去“问一次”有没有发生某事,而不是等别人通知你
while (!tokenSource.IsCancellationRequested) {
UpdateTime(); // 看“有没有定时任务到点”
Thread.Sleep(interval);
}
它在管什么?
- 任务本(taskDic):一本字典
tid → TimerTask。每条任务记了:time:计时时长(毫秒)count:还要响几次(<=0表示无限循环)startTime:开始时刻destTime:下一次响铃的绝对时间countIndex:已经响了几次
- taskCBPackQue,可选:线程安全队列。用来把“要执行的回调”先装袋,留到主线程再执行(避免在子线程里碰 Unity 对象,可以通过锁去避免问题)
谁来驱动它走?
有两种模式——本质都是“定期看表”:
- 主线程驱动(默认):在
Update()里每帧调UpdateTime();若用了投递箱,还要调UpdateCBTask()把回调取出来执行。 - 后台线程轮询:构造时传
interval>0会起一个线程,一直while(没取消){ UpdateTime(); Sleep(interval); }自己看表;- 若
SetHandle==true:回调丢进投递箱,由主线程UpdateCBTask()真执行(安全改 Unity)。 - 若
SetHandle==false:回调直接在子线程执行(只能做纯计算/日志,不能动 Unity)。
- 若
一次完整的生命周期(按时间线)
- AddTimer
- 生成
tid→ 记startTime=now→ 设destTime = startTime + time→ 丢进任务本。 - 返回
tid以后你可以用它取消。
- 生成
- UpdateTime(看表)
- 取当前毫秒
now,遍历任务本:
- 取当前毫秒
now >= destTime→ 到点了:countIndex++(记一次)- 如果
count > 0:count--;- 若
count == 0→ Finish:从任务本里删掉这条,并触发最后一次回调; - 否则 → 算下一次
destTime = startTime + (countIndex+1) * time,再触发回调;
- 若
- 如果
count <= 0(无限) → 同样算下一次destTime,触发回调。 - ✅ 关键点:下一次触发时间用“起点 + 次数 × 周期”,不是“现在 + 周期”,这样即使某一帧卡顿,它也会贴着节拍往前走(不漂移)。
- CallTaskCB(怎么触发)
SetHandle==true→Enqueue到投递箱,等主线程UpdateCBTask()才Invoke()。- 否则 → 直接
Invoke()(当前线程)。
- UpdateCBTask(主线程消费)
- 把投递箱里的回调一个个
TryDequeue()然后Invoke()——此时就是主线程在执行你的回调。
- 把投递箱里的回调一个个
- DeleteTimer
- 从任务本移除;按
SetHandle决定cancelCB是入队还是立刻调用。
- 从任务本移除;按
- ResetTimer
- 清空任务;如果开启了轮询线程:
Cancel()发停工信号 →Join()等线程收尾退出
- 清空任务;如果开启了轮询线程:
总结:
它就是一个“闹钟管家”:任务本里记着每个闹钟的下次响铃时间和次数,管家定期看表,谁到点就把它的回调(要做的事)叫起来;如果设置了“主线程叫醒”,就先把“叫醒单”塞进投递箱,由主线程统一执行。
AnimacerController
AnimationID
Animator 参数 ID 常量表:把常用参数名用 Animator.StringToHash 预先转成 int,避免字符串查找与拼写错误,在动画控制时直接用哈希值
CharacterBase
一个角色基础控制器:统一管理重力/落地检测/垂直与水平速度、根运动(Root Motion)的应用与可选忽略项,并提供斜坡适配与调试可视化。依赖 Animator 与 CharacterController
Fields
| Name | Type | Summary |
|---|---|---|
gravity | float | 重力加速度(负值向下)。 |
velocityLimit | Vector2 | 垂直速度夹取范围 (minY,maxY)。 |
whatIsGround | LayerMask | 地面层掩码。 |
groundDetectedOffset | float | 落地检测球的 Y 偏移。 |
groundRadius | float | 落地检测球半径。 |
verticalVelocity | Vector3 | 当前垂直速度向量(内部用)。 |
horizontalVelocityInAir | Vector3 | 空中时的水平速度(不含动画位移)。 |
animationVelocity | Vector3 | 上一帧应用的动画位移(只读暴露)。 |
moveDir | Vector3 | 采样/处理后的根运动位移。 |
Properties
| Name | Value | Summary |
|---|---|---|
controller | CharacterController | 角色控制器组件(只读)。 |
animator | Animator | 动画器组件(只读)。 |
isOnGround | BindableProperty<bool> | 是否在地面(由球体检测 + verticalSpeed<0 判定)。 |
verticalSpeed | float | 仅 Y 轴的标量速度。 |
AnimationVelocity | Vector3 | 对外只读的动画位移速度。 |
animatorDeltaPositionOffset | Vector3 | 额外叠加到 deltaPosition 的偏移。 |
applyFullRootMotion | bool | true:使用内置 Root Motion;false:自定义采样/处理。 |
disEnableRootMotion | bool | 禁用根运动(不进入自定义流程)。 |
ignoreRootMotionY | bool | 忽略动画根运动的 Y 分量,由重力系统接管垂直。 |
disEnableGravity | bool | 禁用程序重力(例如飞行/特殊状态)。 |
ignoreRotationRootMotion | bool | 忽略根运动旋转。 |
moveSpeedMult | float (0.1~10) | 自定义根运动位移倍率。 |
Methods
| Name | Value | Summary |
|---|---|---|
Awake() | protected override void | 缓存 Animator 与 CharacterController。 |
Update() | protected override void | 每帧:CheckOnGround() → CharacterGravity() → CharacterVerticalVelocity() → ResetHorizontalVelocity()。 |
CheckOnGround() | private bool | 以球体检测(Physics.CheckSphere) + verticalSpeed<0 判落地,写入 isOnGround。 |
CharacterGravity() | private void | 若禁用重力则返回;落地将 verticalSpeed=-2 稳定贴地;空中按 gravity 累加并 Clamp 到 velocityLimit;更新 verticalVelocity。 |
ResetHorizontalVelocity() | private void | 落地时将空中水平速度清零,避免落地后“漂移”。 |
CharacterVerticalVelocity() | private void | 组合 垂直速度 与 空中水平速度 后 controller.Move(… * deltaTime)。 |
OnAnimatorMove() | protected virtual void | 根运动钩子:禁用则返回;applyFullRootMotion 时调用 animator.ApplyBuiltinRootMotion(),否则自定义:deltaPosition + offset → 可选忽略 Y → 斜坡投影 → 速度倍率 → UpdateCharacterMove(dir, deltaRotation)。 |
UpdateCharacterMove(Vector3, Quaternion) | public void | 可选应用根运动旋转;animationVelocity=deltaDir;controller.Move(deltaDir)(与上一处 Move 累加)。 |
ChangeVerticalSpeed(float) | public float | 外部修改垂直速度(返回新值)。 |
AddHorizontalVelocityInAir(Vector3) | public void | 设定空中水平速度(清除 Y)。 |
ClearHorizontalVelocity() | public void | 清空空中水平速度。 |
SetDirOnSlop(Vector3) | private Vector3 | 将移动向量投影到命中表面(Raycast 一米向下),使位移贴合斜坡。 |
OnDrawGizmos() | private void | 在 Scene 视图绘制落地检测球(落地绿/空中红)。 |
角色每帧的位移由哪些“来源”组成?
最终这一帧移动量,可以理解为几块的合成:
总位移 D =(程序速度位移)+(动画根运动位移)+(其他外力)
- 程序速度位移(velocity)
- 垂直:
verticalSpeed按重力积分 →verticalVelocity = (0, verticalSpeed, 0) - 空中水平:
horizontalVelocityInAir(跳起后在空中留下的水平速度) - 在
CharacterVerticalVelocity()中一次性调用:controller.Move( (verticalVelocity + horizontalVelocityInAir) * Time.deltaTime )
- 垂直:
- 动画根运动位移(root motion)
OnAnimatorMove()里拿animator.deltaPosition / deltaRotation- 两种模式:
applyFullRootMotion == true→animator.ApplyBuiltinRootMotion()(Unity内置直接用)- 否则自定义:
deltaPosition + offset→ 可选忽略Y → 斜坡投影 → 乘moveSpeedMult→UpdateCharacterMove(moveDir, deltaRotation)→controller.Move(moveDir)
- 其他外力/冲量(可选)
- 例如受击、风场、Dash 等,可叠加到“程序速度位移”那一块里
同一帧会调用两次 CharacterController.Move:一次“程序速度位移”(重力/空中速度)+ 一次“根运动位移”。二者会累加
Update()的完整逻辑
CheckOnGround():球体检测 +verticalSpeed<0判落地CharacterGravity():计算VerticalSpeed- 落地:
verticalSpeed = -2(贴地技巧) - 空中:
verticalSpeed += gravity * dt并限制在velocityLimit之间,赋值给(0,VerticalSpeed,0)得到VerticalVelocity
- 落地:
CharacterVerticalVelocity():把verticalVelocity + horizontalVelocityInAir乘dt后Move 一次ResetHorizontalVelocity():若已落地,把horizontalVelocityInAir清零(防止“落地漂移”)OnAnimatorMove()(动画帧回调)- 若
disEnableRootMotion:直接返回 - 若
applyFullRootMotion:内置根运动(位置/旋转) - 否则自定义:
- moveDir = SetDirOnSlop(animation.deltaPosition + animatorDeltaPositionOffset)* moveSpeedMult 把动画的位移向量投影到斜坡表面,并手动加上一个偏移,再乘以一个速度倍率
- UpdateCharacterMove(moveDir , animator.deltaRotation
):- 可选应用
deltaRotation(除非ignoreRotationRootMotion) - Move 第二次:
controller.Move(moveDir)
- 可选应用
- 若
PlatformerUp
PlayerReusableData
PlayerReusableData 是玩家角色的可变数据缓存:把跨状态会读写的数值集中到一处,包含 Animancer 混合参数的平滑器、锁敌信息、待机混合器/随机池、攀爬/跳跃/挂墙相关的临时值与回调等,供各个状态机状态复用
Fields
| Name | Constant Value | Summary |
|---|---|---|
currentRotationTime | float | 旋转时长缓存。 |
standIdleMixerState / crouchIdleMixerState | ManualMixerState | 站立/蹲伏待机混合器。 |
standIdleList / crouchIdleList | List<AnimancerState> | 待机候选动画池。 |
currentStandIdleIndex / currentCrouchIdleIndex | int | 当前待机索引。 |
isLockIdle | bool | 是否锁定待机(不切换)。 |
ObstructHeight | ObstructHeight | 障碍高度枚举(用于攀爬判定)。 |
ClimbType | ClimbType | 攀爬方式(翻越/攀爬)。 |
targetClimbClip | ClipTransition | 选中的攀爬动画片段。 |
drawTargetId / drawCurrentId | int | 调试用索引。 |
targetDir | Vector3 | 目标方向。 |
targetAngle | BindableProperty<float> | 目标角度(可观察)。 |
currentState | BindableProperty<string> | 当前状态名(可观察)。 |
horizontalSpeed | float | 跳跃时的水平速度快照。 |
currentInertialVelocity | Vector3 | 跳跃中的惯性速度。 |
cashIndex | int | 速度缓存下标。 |
cashSize | static int = 3 | 缓存上限。 |
cashVelocity | Vector3[] | 最近几帧速度缓存。 |
originalCCRadius | float | 角色控制器原始半径。 |
vaultPos | Vector3 | 翻越目标点。 |
hit | RaycastHit | 前方/墙面射线命中缓存。 |
checkWallDistance | float = 0.6f | 检墙距离。 |
isInPlaceJump | bool | 是否原地跳。 |
jumpExternalForce | float = 15 | 向上外力(平台弹跳等)。 |
currentMidInAirMultiplier | float = 0.6f | 半空阶段系数。 |
Properties
| Name | Value | Summary |
|---|---|---|
standValueParameter | SmoothedFloatParameter | 站↔蹲的混合值平滑器(SmoothDamp)。默认 1。 |
rotationValueParameter | SmoothedFloatParameter | 旋转混合参数平滑器。 |
speedValueParameter | SmoothedFloatParameter | 速度混合参数平滑器。 |
lockValueParameter | SmoothedFloatParameter | 锁定权重平滑器。 |
lock_X_ValueParameter / lock_Y_ValueParameter | SmoothedFloatParameter | 锁定横/纵向权重平滑器。 |
lockTarget | BindableProperty<Transform> | 当前锁定目标(可观察)。 |
inputInterruptionCB | Action | 输入打断回调(设置/触发由外部控制)。 |
PlayerParameterData
Properties
| Name | Type | Summary |
|---|---|---|
standValueParameter | StringAsset | 站/蹲混合权值的参数名(传给 SmoothedFloatParameter 控制站↔蹲)。 |
rotationValueParameter | StringAsset | 转向混合/旋转驱动的参数名。 |
speedValueParameter | StringAsset | 移动速度(或移动混合树)用的参数名。 |
LockValueParameter | StringAsset | 锁敌启停或权值的参数名(0/1 或权重)。 |
Lock_X_ValueParameter | StringAsset | 锁敌时 X 轴(水平)偏移/输入映射的参数名。 |
Lock_Y_ValueParameter | StringAsset | 锁敌时 Y 轴(垂直)偏移/输入映射的参数名。 |
moveInterruptEvent | StringAsset | “移动被打断”事件名(用于 Animancer 事件/自定义事件系统)。 |
cancelClimbEvent | StringAsset | “取消攀爬”事件名(用于动画事件或逻辑订阅)。 |
PlayerMovementData
PlayerMovementData(包含PlayerXXData很多数据类)
只是存配置,把玩家运动相关的各个状态的数据块集中,方便在 Inspector 里拖一份引用给角色
| 名称 | 类型 | 摘要 |
|---|---|---|
PlayerIdleData | PlayerIdleData | 站立/呼吸等 Idle 的过渡与参数(常见:单剪辑或轻混合 + 事件)。 |
PlayerMoveStartData | PlayerMoveStartData | 起步(静止→移动)的过渡配置。 |
PlayerMoveLoopData | PlayerMoveLoopData | 移动循环:通常为 1D 混合器(阈值、参数名、是否 Extrapolate Speed、同步子动画等)。 |
PlayerMoveEndData | PlayerMoveEndData | 收尾(移动→停)的过渡配置。 |
PlayerClimbData | PlayerClimbData | 攀爬:MatchTarget 时间窗、位移/高度偏移、进入/退出动画等。 |
PlayerHangWallData | PlayerHangWallData | 贴墙/挂墙相关剪辑与参数(可被运行时替换整块配置——若不需动态替换,建议改为 private set 以防误改)。 |
PlayerJumpFallAndLandData | PlayerJumpFallAndLandData | 起跳/下落/落地的过渡与判定门槛(如滞空阈值、落地事件)。 |
PlayerClimbAnimationSettings
sytax
[System.Serializable]
public class PlayerClimbAnimationSettings
Fields
| 名称 | 类型 | 摘要 |
|---|---|---|
startMatchTime | Vector2 | 起步对齐窗口:在该区间内调用 Animator.MatchTarget(如将手/脚向墙面/台阶对齐),通常较早发生,例如 [0.10, 0.30]。x<y 且位于 0~1。 |
targetMatchTime | Vector2 | 目标/上沿对齐窗口:在该区间将躯干/髋部对齐到最终攀上去的位置(台面边缘/抓点),例如 [0.45, 0.70]。 |
targetHeightOffSet | float | 对检测到的攀爬目标点的偏移量 正值向上抬(手更高/落点更高),负值向下 |
startMatchDistanceOffset | float | 开始爬&翻越的距离的偏移量 在开始对齐前把角色沿前进方向微调前/后。正值更靠近墙体,负值略后退,避免手穿墙或脚悬空 |
enableCCTimeOffset | float | 进入攀爬状态时会自动禁用,重新启用 CC组件相对TargetMatchTime的偏移量:<0 提前启用,>0 延后 |
PlayerLockMovementData – 锁定模式下用的另一套待机/移动循环/收尾动画
PlayerLockMovementData
锁定(Lock-on/瞄准/侧移)移动形态的一揽子动画配置
Sytax
[System.Serializable]
public class PlayerLockMovementData
是PlayerMovementData成员的子集,可能本来应该有单独的动作,但是现在只是用一套动作但是修改参数
State
PlayerReusableLogic
玩家的通用逻辑模块。封装待机动画初始化与轮播、按键“跳跃→攀爬/翻越”判定、空中抓沿检测、以及攀爬目标位置匹配与动画位移补偿等可复用算法。依赖 Player、Animancer 与 PlayerSO 数据
Methods
| Name | Value | Summary |
|---|---|---|
InitIldeState() | void | 进入待机:播放 Idle 树,按是否锁敌选择不同分支;抓取站立/蹲伏 ManualMixerState;把每个子 State 的 OnEnd 绑定到 PlayNextState,并填充 standIdleList / crouchIdleList。 |
PlayNextState() | void | 循环播放待机子动画:根据 standValueParameter.TargetValue(1=站立/0=蹲伏)切换下一个索引,设置权重并 Play/Stop。 |
OnJump() | void | 跳键触发:用 GetWallHight 采样求墙体最高点与相对高度与法线角度 → 过高/角度不合则jumpState;否则依据高度设置 ObstructHeight 并 VaultOrClimb(决定 ClimbType),最后切到 climbState 或 jumpState。 |
GetWallHight(dir, startH, maxH, len, ref vaultH, ref h, samples) | RaycastHit | 从 startH 到 maxH 逐步上移采样射线,记录最高命中与命中点法线;计算障碍相对高度 h 与翻越高度 vaultH;返回最高命中的 RaycastHit(无效则 default)。 |
VaultOrClimb(vaultStart, wallHit) | void | 从 vaultStart 向墙反方向探测厚度;如被遮挡或落点有地面 → 设为 Climb;否则设为 Vault。 |
InAirMoveCheck(targetDir) | void | 空中检测:在较小高度窗口二次采样;满足角度与高度时,切到 ledgeClimbState 并播放挂墙待机。 |
ClimbTargetMatch(state, ref info, t0, t1) | void | XYZ 位置匹配:在标准化时间区间 [t0,t1] 内将 transform.position 从记录的 InitPos 插值到 TargetPos;首次越过 t0 时记录 InitPos。 |
ClimbTargetMatch_Y(state, ref info, t0, t1) | void | 仅 Y 轴匹配:同上,但只插值高度。 |
SetClimbTarget_Y_Task(state, ref info, t0, t1) | void | 把“Y 轴匹配”封装为 animationTask(用局部副本避免 ref 捕获问题)。 |
RemoveClimbTarget_Y_Task() | void | 清除对应任务。 |
SetAnimationMotionCompensationTask(comp, target, t0=0, t1=1) | void | 设定动画位移补偿任务:当 target 正在 [t0,t1] 区间播放时,每帧把 comp * (dt / (secs(t1)-secs(t0))) 写入 player.animatorDeltaPositionOffset,以抵消或叠加位移。区间外置零。 |
RemoveAnimationMotionCompensationTask() | void | 归零 animatorDeltaPositionOffset 并清空任务。 |
IState
状态机里每个“状态”的统一接口。定义进入、逐帧更新、动画驱动更新、退出、以及“动画播放结束”五个生命周期钩子
| 名称 | 调用时机(频率) | 典型职责 |
|---|---|---|
OnEnter() | 切换为当前状态当帧调用一次 | 状态被激活或进入时调用,初始化状态相关的数据、播放动画、重置参数等。 |
OnUpdate() | 每帧(Update 节点) | 采样输入;执行状态内逻辑(移动、检测条件);决定是否切换到其他状态 |
OnAnimationUpdate() | 每个动画步(随 Animator / Playable Graph 更新) | 处理动画驱动逻辑:根运动同步、MatchTarget、命中判定、按“归一化时间”触发事件 |
OnExit() | 离开当前状态当帧调用一次 | 停止/淡出动画;清理订阅与协程;恢复 CharacterController/碰撞/输入等 |
OnAnimationEnd() | 当当前主动画播放结束时(一次或按循环策略) | 常用于自动切换到下一个状态(如 Attack→Idle),或触发收尾效果/音效/镜头 |
StateBase
PlayerMovementState
StateMachine
Struct Types
Enum Types
这些枚举类型不属于任何类
ObstructHeight
| Name | Value | Summary |
|---|---|---|
low | 0 | 低矮障碍(可轻松越过/翻越)。 |
lowMedium | 1 | 低-中等高度障碍。 |
medium | 2 | 中等高度障碍。 |
mediumHight | 3 | 中-高等高度障碍。 |
Hight* | 4 | 很高的障碍。 |
ClimbType
| Name | Value | Summary |
|---|---|---|
Vault | 0 | 翻越:跨过去、动作短。 |
Climb | 1 | 攀爬:抓握上爬、动作较长。 |
MatchType
| Name | Value | Summary |
|---|---|---|
Root | 0 | 目标匹配对齐根节点整体位置(通常 XYZ)。 |
RootY | 1 | 只匹配Y 高度(垂直方向对齐)。 |
Interface Types
这样,角色控制器、相机控制器等代码不用关心 Input Actions 的读值细节,也不用关心平台差异(键鼠/手柄/触屏),直接消费这些属性即可
:这个类确保界面永远有焦点,并用 Tab 在控件间跳转、用 Enter 执行“提交/点击”,让纯键盘(或手柄)操作 UI 顺畅可用。
AnimacerController
为什么要分离State Machinebase和Statemachine,如果有多角色,之间的state一定有区别,但是底层是不变的,所以将来如果有其他角色可以创建更多派生自tate Machinebase的XXStateMachine
Animacer
TransitionAsset
Animacer可以创建这几种资源



TransitionAsset 就是一张“动作播放卡片”(.asset 文件)。
这张卡片里写着:播哪个动作 + 怎么播(淡入多久、要不要循环、速度多少、结束回调…)。
把卡片做成独立资源后,你就能在项目里到处拖、复用、统一改(淡入从 0.1 改到 0.2?改卡片一次,全项目生效)
AnimationClip
ManualMixerState
手动权重混合器”——你往里放多个子动画(Clip/State),自己控制每个子动画的权重,由它把结果混成一个输出给当前 Layer。
SmoothedFloatParameter
用来平滑地把一个浮点参数从当前值推向目标值,内部用 Mathf.SmoothDamp 维护 Current/Target/Velocity 等状态;这个参数再去驱动 Animancer 的混合器(Mixer)或其它动画/逻辑数值,避免“跳变、抖动、卡顿”
比如声明了一个standValueParameter变量,把“是否站立”做成 0~1 的连续浮点(通常 1=站立、0=蹲伏)standValueParameter.Parameter.Value = 1; → 默认站立。
为什么做成“可复用数据”
多处共享:不仅能驱动动画权重,还可以同时插值角色控制器高度 / 摄像机高度 / 移动速度上限等,让整体“站↔蹲”统一协调。
跨状态保留惯性:切到别的状态再回来不会“跳回 0 或 1”,而是延续当前的平滑进度与 velocity,观感更自然。
AnimationClip:只有“原始关键帧数据”。
ClipTransition:配方(包含 Clip + 播放参数 + 事件)。
StringAsset
“可拖拽、可复用、可比较、可查找创建的字符串标识资源”。用它把易错的硬编码字符串变成类型安全、项目可管理的资产






