动画系统模块解析
本文最后更新于33 天前,其中的信息可能已经过时,如有错误请留言

前言

之前是按照各个cs文件和文件夹分类的,但这样分类对于理解代码帮助不大,那只是方便使用和修改代码,所以这次文档说明采用业内通用的方法
按照(Assembly,namespace都唯一故不考虑)类,结构体,枚举类型,接口进行分类

每类又分为:
Constructors 构造方法,Fields 字段(一般为Const / readonly声明的变量),Properties 属性(get / set包装的变量)Methods 方法,operator 运算符(比如隐式类型转换运算符)
implicit operator AnimancerGraph(AnimancerComponent)

implicit operator AnimancerLayer(AnimancerComponent)
当代码需要 AnimancerGraphAnimancerLayer 时,可以直接把一个 AnimancerComponent 当成它来用,编译器会自动替你做转换。

对于函数,我倾向于如果参数名能帮助理解,则保留否则与业内做法一致,只保留参数类型

Class Types

Animacer


AnimationClip是Unity自带的

StringAsset

StringAsset 是把字符串名字做成资源ScriptableObject——名字来自自身的 Object.name,可在 Inspector 中拖拽设置,并在代码里按名字绑定动画参数 / 事件(隐式转换为 StringReferencestring 使用)。用来集中管理动画参数名、事件名、标签等键值,避免硬编码并便于项目内复用、查找和替换。

这里传进去的 playerSO.playerParameterData.speedValueParameterStringAsset/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的对比

对比项ClipTransitionTransitionAsset
形态一个可序列化的对象,通常作为 组件字段内嵌在 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

NameValueSummary
AnimationAtTag(扩展方法) bool判断当前这一层正在播放的 Animator 状态是否带有某个 Tag
Addvoid添加animancerEvent,并更新animancerEventList
Removevoid移除animancerEvent,并更新animancerEventList
RemoveAllvoid销毁所有在animancerEventList的事件,并清空animancerEventList

MonoSingleton<T>

需要创建单例的类应继承该泛型类,并在该单例类的Awake生命周期函数中最先调用base.Awake

properties

NameValueSummery
InstanceT被继承时添加到派生类中,在Awake中初始化

BindableProperty<T>

让一个变量属性的值发生变化时,自动触发 ValueChanged 事件

properties

NameValueSummary
ValueT

Delegates

NameValueSummary
ValueChangedAction<T>当 Value 值发生变化时,会调用所有订阅的方法,并传入新的值

ToolFunction

一组 Unity 静态小工具方法,负责给 Image/RawImage 便捷上色、计算角色与目标的夹角(-180~180°),并按目标高度与重力反推跳跃初速度。

Methods

NameValueSummary
SetImageColorFromVector3
(Image, Vector3, float)
voidcolorVectorRGBalpha 设置 Image.coloralpha 会被 Clamp01)。
SetRawImageColorFromVector3
(RawImage, Vector3, float)
voidcolorVectorRGBalpha 设置 RawImage.coloralpha 会被 Clamp01)。
SetRawImageColorFromVector3
(RawImage, Color, float)
voidcolorVector 直接赋给 RawImage.color当前实现未使用参数 alpha(使用的是 colorVector.a)。
GetDeltaAngle
(Transform , targetAngle)
float计算 player.forward 与“绕 Y 轴 targetAngle 旋转后的方向”的夹角(度),范围 (-180, 180),正负代表左右。
GetDeltaAngle
(Transform , Vector3)
float计算 player.forwardtoDir 的夹角(度),忽略 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 == nullnew InputMap();然后 inputMap.Enable().
  • OnDestroy()
    • inputMap.Disable()

Fields

public InputMap inputMap;
由 Unity 新输入系统生成的输入包装类,绑定所有 Action

Properties

NameTypeSummary
GetMoveHorizontalValueVector2仅保留水平(X)分量的移动输入:在 Android 直接返回摇杆值;在非 Android,将 dir.y=0 并归一化(跑/走共用,是否按下 Shift 只影响分支但当前逻辑两支等价)。如果没有输入则返回0向量
GetMoveVerticalValueVector2仅保留垂直(Y)分量的移动输入:将 dir.x=0 后归一化。
Interactivebool交互键是否按下(ReadValue<float>() != 0)。
Shiftbool是否按下 Shift(跑步开关)。
MoveVector2将原始 Move离散化为 {-1,0,1}(分别处理 x/y)。
ScrollVector2滚轮/滚动轴的当前值直通返回。

EventService

没有用到,解析见阅读优秀代码 – Skyshin34的博客

TimerService

计时任务相比简单计时器外具备计时结束/终止回调函数,记录绝对发生时间和设置循环次数的功能

NameValueSummary
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 注销任务
若提供了 cancelCBTickTimer 的策略被调用

TickTimer(TimerService的核心)

轮询:**轮询(polling)**就是:自己隔一段时间就去“问一次”有没有发生某事,而不是等别人通知你

while (!tokenSource.IsCancellationRequested) {
    UpdateTime();          // 看“有没有定时任务到点”
    Thread.Sleep(interval);
}

它在管什么?

  • 任务本(taskDic):一本字典 tid → TimerTask。每条任务记了:
    • time:计时时长(毫秒)
    • count:还要响几次(<=0 表示无限循环)
    • startTime:开始时刻
    • destTime下一次响铃的绝对时间
    • countIndex:已经响了几次
  • taskCBPackQue,可选:线程安全队列。用来把“要执行的回调”先装袋,留到主线程再执行(避免在子线程里碰 Unity 对象,可以通过锁去避免问题)

谁来驱动它走?

有两种模式——本质都是“定期看表”:

  1. 主线程驱动(默认):在 Update() 里每帧调 UpdateTime();若用了投递箱,还要调 UpdateCBTask() 把回调取出来执行。
  2. 后台线程轮询:构造时传 interval>0 会起一个线程,一直 while(没取消){ UpdateTime(); Sleep(interval); } 自己看表;
    • SetHandle==true:回调丢进投递箱,由主线程 UpdateCBTask() 真执行(安全改 Unity)。
    • SetHandle==false:回调直接在子线程执行(只能做纯计算/日志,不能动 Unity)。

一次完整的生命周期(按时间线)

  1. AddTimer
    • 生成 tid → 记 startTime=now → 设 destTime = startTime + time → 丢进任务本。
    • 返回 tid 以后你可以用它取消。
  2. UpdateTime(看表)
    • 取当前毫秒 now,遍历任务本:
  3. now >= destTime → 到点了:
    • countIndex++(记一次)
    • 如果 count > 0count--
      • count == 0Finish:从任务本里删掉这条,并触发最后一次回调;
      • 否则 → 算下一次 destTime = startTime + (countIndex+1) * time,再触发回调;
    • 如果 count <= 0(无限) → 同样算下一次 destTime,触发回调。
    • 关键点:下一次触发时间用“起点 + 次数 × 周期”,不是“现在 + 周期”,这样即使某一帧卡顿,它也会贴着节拍往前走(不漂移)
  4. CallTaskCB(怎么触发)
    • SetHandle==trueEnqueue 到投递箱,等主线程 UpdateCBTask()Invoke()
    • 否则 → 直接 Invoke()(当前线程)。
  5. UpdateCBTask(主线程消费)
    • 把投递箱里的回调一个个 TryDequeue() 然后 Invoke()——此时就是主线程在执行你的回调
  6. DeleteTimer
    • 从任务本移除;按 SetHandle 决定 cancelCB入队还是立刻调用。
  7. ResetTimer
    • 清空任务;如果开启了轮询线程:Cancel() 发停工信号 → Join() 等线程收尾退出

总结:

它就是一个“闹钟管家”:任务本里记着每个闹钟的下次响铃时间次数,管家定期看表,谁到点就把它的回调(要做的事)叫起来;如果设置了“主线程叫醒”,就先把“叫醒单”塞进投递箱,由主线程统一执行。

AnimacerController


AnimationID

Animator 参数 ID 常量表:把常用参数名用 Animator.StringToHash 预先转成 int,避免字符串查找与拼写错误,在动画控制时直接用哈希值

CharacterBase

一个角色基础控制器:统一管理重力/落地检测/垂直与水平速度根运动(Root Motion)的应用与可选忽略项,并提供斜坡适配调试可视化。依赖 AnimatorCharacterController

Fields

NameTypeSummary
gravityfloat重力加速度(负值向下)。
velocityLimitVector2垂直速度夹取范围 (minY,maxY)
whatIsGroundLayerMask地面层掩码。
groundDetectedOffsetfloat落地检测球的 Y 偏移。
groundRadiusfloat落地检测球半径。
verticalVelocityVector3当前垂直速度向量(内部用)。
horizontalVelocityInAirVector3空中时的水平速度(不含动画位移)。
animationVelocityVector3上一帧应用的动画位移(只读暴露)。
moveDirVector3采样/处理后的根运动位移。

Properties

NameValueSummary
controllerCharacterController角色控制器组件(只读)。
animatorAnimator动画器组件(只读)。
isOnGroundBindableProperty<bool>是否在地面(由球体检测 + verticalSpeed<0 判定)。
verticalSpeedfloat仅 Y 轴的标量速度。
AnimationVelocityVector3对外只读的动画位移速度。
animatorDeltaPositionOffsetVector3额外叠加到 deltaPosition 的偏移。
applyFullRootMotionbooltrue:使用内置 Root Motion;false:自定义采样/处理。
disEnableRootMotionbool禁用根运动(不进入自定义流程)。
ignoreRootMotionYbool忽略动画根运动的 Y 分量,由重力系统接管垂直。
disEnableGravitybool禁用程序重力(例如飞行/特殊状态)。
ignoreRotationRootMotionbool忽略根运动旋转。
moveSpeedMultfloat (0.1~10)自定义根运动位移倍率。

Methods

NameValueSummary
Awake()protected override void缓存 AnimatorCharacterController
Update()protected override void每帧:CheckOnGround()CharacterGravity()CharacterVerticalVelocity()ResetHorizontalVelocity()
CheckOnGround()private bool球体检测(Physics.CheckSphere) + verticalSpeed<0 判落地,写入 isOnGround
CharacterGravity()private void若禁用重力则返回;落地将 verticalSpeed=-2 稳定贴地;空中按 gravity 累加并 ClampvelocityLimit;更新 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=deltaDircontroller.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 == trueanimator.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 + horizontalVelocityInAirdtMove 一次
  • 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

NameConstant ValueSummary
currentRotationTimefloat旋转时长缓存。
standIdleMixerState / crouchIdleMixerStateManualMixerState站立/蹲伏待机混合器。
standIdleList / crouchIdleListList<AnimancerState>待机候选动画池。
currentStandIdleIndex / currentCrouchIdleIndexint当前待机索引。
isLockIdlebool是否锁定待机(不切换)。
ObstructHeightObstructHeight障碍高度枚举(用于攀爬判定)。
ClimbTypeClimbType攀爬方式(翻越/攀爬)。
targetClimbClipClipTransition选中的攀爬动画片段。
drawTargetId / drawCurrentIdint调试用索引。
targetDirVector3目标方向。
targetAngleBindableProperty<float>目标角度(可观察)。
currentStateBindableProperty<string>当前状态名(可观察)。
horizontalSpeedfloat跳跃时的水平速度快照。
currentInertialVelocityVector3跳跃中的惯性速度。
cashIndexint速度缓存下标。
cashSizestatic int = 3缓存上限。
cashVelocityVector3[]最近几帧速度缓存。
originalCCRadiusfloat角色控制器原始半径。
vaultPosVector3翻越目标点。
hitRaycastHit前方/墙面射线命中缓存。
checkWallDistancefloat = 0.6f检墙距离。
isInPlaceJumpbool是否原地跳。
jumpExternalForcefloat = 15向上外力(平台弹跳等)。
currentMidInAirMultiplierfloat = 0.6f半空阶段系数。

Properties

NameValueSummary
standValueParameterSmoothedFloatParameter站↔蹲的混合值平滑器(SmoothDamp)。默认 1。
rotationValueParameterSmoothedFloatParameter旋转混合参数平滑器。
speedValueParameterSmoothedFloatParameter速度混合参数平滑器。
lockValueParameterSmoothedFloatParameter锁定权重平滑器。
lock_X_ValueParameter / lock_Y_ValueParameterSmoothedFloatParameter锁定横/纵向权重平滑器。
lockTargetBindableProperty<Transform>当前锁定目标(可观察)。
inputInterruptionCBAction输入打断回调(设置/触发由外部控制)。

PlayerParameterData

Properties

NameTypeSummary
standValueParameterStringAsset站/蹲混合权值的参数名(传给 SmoothedFloatParameter 控制站↔蹲)。
rotationValueParameterStringAsset转向混合/旋转驱动的参数名。
speedValueParameterStringAsset移动速度(或移动混合树)用的参数名。
LockValueParameterStringAsset锁敌启停或权值的参数名(0/1 或权重)。
Lock_X_ValueParameterStringAsset锁敌时 X 轴(水平)偏移/输入映射的参数名。
Lock_Y_ValueParameterStringAsset锁敌时 Y 轴(垂直)偏移/输入映射的参数名。
moveInterruptEventStringAsset“移动被打断”事件名(用于 Animancer 事件/自定义事件系统)。
cancelClimbEventStringAsset“取消攀爬”事件名(用于动画事件或逻辑订阅)。

PlayerMovementData


PlayerMovementData(包含PlayerXXData很多数据类)

只是存配置把玩家运动相关的各个状态的数据块集中,方便在 Inspector 里拖一份引用给角色

名称类型摘要
PlayerIdleDataPlayerIdleData站立/呼吸等 Idle 的过渡与参数(常见:单剪辑或轻混合 + 事件)。
PlayerMoveStartDataPlayerMoveStartData起步(静止→移动)的过渡配置。
PlayerMoveLoopDataPlayerMoveLoopData移动循环:通常为 1D 混合器(阈值、参数名、是否 Extrapolate Speed、同步子动画等)。
PlayerMoveEndDataPlayerMoveEndData收尾(移动→停)的过渡配置。
PlayerClimbDataPlayerClimbData攀爬:MatchTarget 时间窗、位移/高度偏移、进入/退出动画等。
PlayerHangWallDataPlayerHangWallData贴墙/挂墙相关剪辑与参数(可被运行时替换整块配置——若不需动态替换,建议改为 private set 以防误改)。
PlayerJumpFallAndLandDataPlayerJumpFallAndLandData起跳/下落/落地的过渡与判定门槛(如滞空阈值、落地事件)。

PlayerClimbAnimationSettings

sytax

[System.Serializable]
public class PlayerClimbAnimationSettings

Fields

名称类型摘要
startMatchTimeVector2起步对齐窗口:在该区间内调用 Animator.MatchTarget(如将手/脚向墙面/台阶对齐),通常较早发生,例如 [0.10, 0.30]x<y 且位于 0~1。
targetMatchTimeVector2目标/上沿对齐窗口:在该区间将躯干/髋部对齐到最终攀上去的位置(台面边缘/抓点),例如 [0.45, 0.70]
targetHeightOffSetfloat检测到的攀爬目标点的偏移量
正值向上抬(手更高/落点更高),负值向下
startMatchDistanceOffsetfloat开始爬&翻越的距离的偏移量
在开始对齐前把角色沿前进方向微调前/后。正值更靠近墙体,负值略后退,避免手穿墙或脚悬空
enableCCTimeOffsetfloat进入攀爬状态时会自动禁用,重新启用 CC组件相对TargetMatchTime的偏移量<0 提前启用,>0 延后

PlayerLockMovementData – 锁定模式下用的另一套待机/移动循环/收尾动画


PlayerLockMovementData

锁定(Lock-on/瞄准/侧移)移动形态的一揽子动画配置

Sytax

[System.Serializable]
public class PlayerLockMovementData

是PlayerMovementData成员的子集,可能本来应该有单独的动作,但是现在只是用一套动作但是修改参数

State


PlayerReusableLogic

玩家的通用逻辑模块。封装待机动画初始化与轮播、按键“跳跃→攀爬/翻越”判定、空中抓沿检测、以及攀爬目标位置匹配与动画位移补偿等可复用算法。依赖 PlayerAnimancerPlayerSO 数据

Methods

NameValueSummary
InitIldeState()void进入待机:播放 Idle 树,按是否锁敌选择不同分支;抓取站立/蹲伏 ManualMixerState;把每个子 State 的 OnEnd 绑定到 PlayNextState,并填充 standIdleList / crouchIdleList
PlayNextState()void循环播放待机子动画:根据 standValueParameter.TargetValue(1=站立/0=蹲伏)切换下一个索引,设置权重并 Play/Stop
OnJump()void跳键触发:用 GetWallHight 采样求墙体最高点相对高度法线角度 → 过高/角度不合则jumpState;否则依据高度设置 ObstructHeightVaultOrClimb(决定 ClimbType),最后切到 climbStatejumpState
GetWallHight(dir, startH, maxH, len, ref vaultH, ref h, samples)RaycastHitstartHmaxH 逐步上移采样射线,记录最高命中与命中点法线;计算障碍相对高度 h翻越高度 vaultH;返回最高命中的 RaycastHit(无效则 default)。
VaultOrClimb(vaultStart, wallHit)voidvaultStart墙反方向探测厚度;如被遮挡或落点有地面 → 设为 Climb;否则设为 Vault
InAirMoveCheck(targetDir)void空中检测:在较小高度窗口二次采样;满足角度与高度时,切到 ledgeClimbState 并播放挂墙待机。
ClimbTargetMatch(state, ref info, t0, t1)voidXYZ 位置匹配:在标准化时间区间 [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

NameValueSummary
low0低矮障碍(可轻松越过/翻越)。
lowMedium1低-中等高度障碍。
medium2中等高度障碍。
mediumHight3中-高等高度障碍。
Hight*4很高的障碍。

ClimbType

NameValueSummary
Vault0翻越:跨过去、动作短。
Climb1攀爬:抓握上爬、动作较长。

MatchType

NameValueSummary
Root0目标匹配对齐根节点整体位置(通常 XYZ)。
RootY1只匹配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

“可拖拽、可复用、可比较、可查找创建的字符串标识资源”。用它把易错的硬编码字符串变成类型安全、项目可管理的资产

学习笔记如有侵权,请提醒我,我会马上删除
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇