架构与定位
Architecture & Positioning第三人称生存游戏的玩家运动系统。一句话:用传统分层动画(state machine + BlendSpace)——一个基础动画蓝图搭一次,每把武器挂一个可换的持械层;火器的低位持枪(枪放胸口)和举枪瞄准是层内两套姿势、一个布尔切。一切服务器权威 · server-authoritative,客户端只发输入 + 演表现。
设计决定 Decision
放弃 Motion Matching(2026-06-16 拍板),玩家 locomotion 完全重写为传统分层。理由:手上的动捕(Military_Pistol / Rifle)本就是为传统 locomotion 做的(自带 Relaxed + Aim 完整方向集、全是去根变体);MM 的姿态库 Pose Search 数据库 · PSD 脚本建不了、且只有空手 AimOffset、无举枪源。旧混合方案(空手 MM + 持枪状态机、运行时换整个动画蓝图)已弃。
核心模型 Mental Model
腿只有一个来源 = 基础蓝图;持械差异只活在上半身/姿态层 = 每武器一个 链接动画层 · Linked Anim Layer。换武器 = LinkAnimClassLayers 换一层,不再换整个动画蓝图。加一把枪 = 复制一个层模板 + 填一张数据表,基础图零改动。
两条姿态轴 Two Axes
每个移动状态都被两条正交轴调制:站立 ⇄ 下蹲(Stance)、低位 ⇄ 瞄准(Aim,仅火器)。姿势 = 状态 × Stance × Aim。低位/瞄准不是两个状态,是同一层里两张 BlendSpace 按 bIsAiming 混合。
终结"乱"的两件事 Goals
① 干掉两套并行系统(不再运行时 SetAnimInstanceClass 换整个蓝图);② 干掉魔法速度常量(×600/306、×300/148)——BlendSpace 速度轴按动捕真实根速度建,不再反向缩放骗采样。
✅ 武器层动作资产已就位(Pistol/Rifle/Knife 已重定向) 🔶 基础蓝图 + 链接层 待搭(编辑器手工) ⬜ 空手层资产偏薄、待补
Source/CoopSurvival/Character 与 Content/Animation/Weapons/*,单元状态以 DevelopmentUnits.md 为准。控制状态与数据流
Control State & Authority Dataflow玩家按键 → 意图(本地)→ 服务器权威结算 → 复制态 → 动画蓝图只读。动画从不自己挪角色、从不在动画线程查世界。这条链是联机一致与"不滑步/不抖"的根。
bWantsToSprint 等,条件恢复ServerSetAiming / ServerSetSprintingbIsAiming / bIsSprinting / bIsCrouched / 瞄准点UCSPlayerAnimInstance 线程安全读控制状态规格 Control States
移动 Move(速度档 Gait)
行走 / 慢跑 / 冲刺(WalkSpeed / SprintSpeed)。冲刺是意图(bWantsToSprint 本地,不复制):被体力耗尽/下蹲/超重打断后,键还按着、条件一恢复就在 Tick 自动续,不用松开重按。瞄准时移速 ×AimingMoveSpeedMultiplier(0.5)。
瞄准 Aim(低位 ⇄ ADS)
右键按住进瞄。bIsAiming 复制。进瞄=朝向锁定 · strafe(身体转向准星、左右变横移,bUseControllerRotationYaw=true)+ 镜头越肩拉近 + FOV 收窄。火器命门:低位↔瞄准的全身切换。
下蹲 Crouch(Stance)
bIsCrouched(引擎内建、复制)。切胶囊高度(镜头反补偿消除硬跳)、降移速、降噪音足迹。每个移动状态都有蹲姿变体(取 Crouch BlendSpace)。
空中 Airborne
IsFalling() 驱动跳跃子状态机。空中锁转向(非瞄准时 bOrientRotationToMovement=!IsFalling());落地按下落速度播一次下沉镜头。
GetCachedMuzzleAimOffset)。动画工作线程碰 UWorld 会概率性崩。输入仍是 legacy BindAxis/BindAction(EnhancedInput 已链接未用,迁移留独立单元)。分层动画架构
Layered AnimBP — Base + Linked Weapon Layers一个基础动画蓝图ABP_Player(搭一次、永不动)+ 每武器一个链接动画层。基础图负责"调用当前武器的腿 + 瞄准偏移 + 动作槽 + 脚/手 IK";武器层只负责"用这把武器的 clip 出 locomotion"。
LinkAnimClassLayers(武器层类) · 换武器只换这一层(替掉运行时 SetAnimInstanceClass)为什么是"链接层"而非"再加状态机分支"
旧法每加一把枪 = 克隆一整套整身状态机 + 一条流水线(线性堆)。链接层把它收敛成一个层资产:基础图的状态机/AO/IK/槽全程不动、不断,换武器只替换层的 class。加武器 = 填表 · data-driven(UCSEquipmentAnimProfile.LocomotionLayerClass)。
各层方向粒度不同,层各自吸收
手枪 4 向(F/B/L/R,对角靠相邻混合)、步枪 8 向(含对角 + 后撤步)、近战 8 向(角度命名 45/90/135,需重映射)、空手 8 向(Manny)。链接层让每层用自己的命名/粒度,不强求统一——这正是分层的好处。
线程 THREAD线程安全更新 Thread-safe Update
动画属性(速度/方向/bIsAiming/bIsCrouching/bIsFalling/瞄准偏移)在 UCSPlayerAnimInstance::NativeUpdateAnimation 算好;动画线程不发射线、不访问 UWorld。新设计删掉旧的 bUsePistolFullBodyAnimSet 等一串互斥布尔与 EquipmentMoveSpeed 魔法缩放——速度直接喂、轴按真实根速度建。
🔶 链接层接口 + 基础图 待编辑器手工搭(Linked Layer / BlendSpace / AimOffset 节点 Python 建不了)
Locomotion 状态机
Locomotion State Machine — States & Transitions每个武器层内部的地面移动状态机。下图是状态 + 连线(转移条件)的模拟;两条正交轴(站/蹲、低位/瞄准)叠加在每个状态之上。开火/换弹等动作不在状态机里,走动作槽叠在上面(见 §04)。
读法:站定 = 站立待机,给速度 → 移动(混合空间按速度×方向取样),松手急停回待机;站定大幅转视角 → 原地转身;跳跃输入进空中子机(起跳→滞空→落地→回地面)。整张图再被"站/蹲""低位/瞄准"两条轴各乘一遍——所以一个"移动"状态实际覆盖 走/跑/冲 × 8 向 × 站/蹲 × 低位/瞄准。
状态规格 State Specs
站立待机 Idle
速度≈0。播 idle(低位 Stand_Relaxed_Idle / 瞄准 Stand_Aim_Idle 由 bIsAiming 选)。转出:速度↑→移动;静止且 |Δyaw| 大→原地转身;跳跃输入→起跳。
移动 Locomotion
速度>阈值。混合空间按速度(Walk/Jog/Run)×方向(8 或 4 向)取样;速度轴按真实根速度建(不再魔法缩放)。低位用 Relaxed BS、瞄准用 Aim BS。转出:速度→0→(急停过渡 *_to_Stand_Relaxed)→待机。
原地转身 Turn-in-place
静止 + 转视角累计超阈值 → 播转身(步枪=循环按 yaw 缩放;手枪=离散 45/90/135/180 步)。转到位回待机。空手/近战无转身片段 → 退化为直接旋转根骨。
空中子机 Airborne
IsFalling() 进入:起跳 → 滞空(循环)→ 落地。步枪有真正的 Start/Air/End 三段裂跳;手枪/近战是单片跳(按速度档选)。落地按下落速度软化 + 回地面状态。
交互与动作状态
Interaction & Action States — Montage Slots动作不进 locomotion 状态机,而是经动作槽 · Montage Slot叠在当前移动姿势之上:上半身槽(开火/换弹/掏枪,腿照常跑)或全身槽(大动作)。服务器权威结算、各端多播表现。
上半身槽 UPPER开火 Fire
服务器校验冷却/弹药/命中后,多播把 UCSEquipmentAnimProfile.FireAnimation 播到上半身动作槽(UpperBodyActionSlot);后坐力仅本地。不瞄不能开火(读复制的 bIsAiming)。站/蹲各一套(Stand_Fire_Single/Continuous)。
上半身槽 UPPER换弹 Reload
R 键 → 服务器起计时 → 多播播 ReloadAnimation,播放速率贴合有效换弹时长。换弹期间左手 IK 按槽权重淡出(不和动作打架)。弹匣/弹种系统见 枪械系统。
上半身槽 UPPER掏枪 / 收枪 Equip
装备变化触发 EquipAnimation(各端随复制触发)。步枪用背后取枪/归位(Get/Return To Back),手枪用掏枪/插枪(Unholster/Holster)。掏枪完成才进该武器的 locomotion 层。
全身槽 FULL近战攻击 Melee
近战走全身 montage(AN_Knife_Light_Melee01..03 三连),命中只在 UCSAnimNotifyState_MeleeWindow 窗口内由服务器扫刀刃。火器近战/枪托留后续。
入/出瞄过渡 ToAim
低位↔瞄准切换时,可选在上半身槽播一条很短的 To_Aim/To_Relaxed 过渡(站/蹲各一),盖住"移动中切瞄准"那一下的衔接。这是这套方案唯一保留的"手感手调件"。
交互 / 投掷 / 用药 Interact
交互(E,UCSInteractionComponent 焦点目标)、投掷(蓄力/引信,见枪械/装备)、用消耗品(UCSStatusEffectComponent Buff)。当前多为即时结算,动作表现可后续接全身/上半身槽。
状态 → UE 动作映射
State → UE Animation Asset Map把上面每个状态对应到 UE 工程里真实的 .uasset。移动循环一律取去根变体(手枪 _Loop_IP / 步枪 _IPC / 近战本就 root-locked)——服务器权威移动需要。路径相对 Content\。命名腿:Relaxed=低位、Aim=瞄准、F/B/L/R=方向、St/Cr=站/蹲。
手枪 Pistol · Content\Animation\Weapons\Pistol\ · 四向 · 已重定向
| 状态 State | 动作资产 Clip | 备注 |
|---|---|---|
| 待机 Idle(低位/瞄准) | AN_Pistol_Stand_Relaxed_Idle · AN_Pistol_Stand_Aim_Idle | 各有 Fgt_v1..v4 待机小动作 |
| 行走 4 向(低位) | AN_Pistol_Walk_{F,B,L,R}_Loop_IP | 无对角(FL/FR/BL/BR),对角靠相邻混合 |
| 行走 4 向(瞄准) | AN_Pistol_Walk_Aim_{F,B,L,R}_Loop_IP | |
| 慢跑 4 向(低位/瞄准) | AN_Pistol_Jog_{F,B,L,R}_Loop_IP · AN_Pistol_Jog_Aim_{F,B,L,R}_Loop_IP | |
| 冲刺 Run(低位,前向弧) | AN_Pistol_Run_{F,L,R}_Loop_IP | |
| 急停过渡 Stop | AN_Pistol_{Jog,Run}_{F,B,L,R}_to_Stand_Relaxed | 无专门起步片段,裸 Walk_F/Jog_F 当起步 |
| 原地转身 Turn | AN_Pistol_Stand_{Relaxed,Aim}_{L,R}_{45,90,135,180} | 离散步;蹲转 AN_Pistol_Crouch_* |
| 蹲待机/蹲走(低位/瞄准) | AN_Pistol_Crouch_Idle · _Aim_Idle · AN_Pistol_CrouchWalk_{F,B,L,R}_Loop_IP(+_Aim_) | |
| 瞄准网格 Aim_Point(站/蹲 9 格) | AN_Pistol_{Stand,Crouch}_Aim_Point_{Center,U90,D90,L90,R90,LU45,LD45,RU45,RD45} | 叠加 AimOffset 源 |
| 姿态过渡(蹲/瞄) | _Stand_Relaxed_To_Crouch · _To_Aim · _Crouch_To_Stand_Relaxed · _Aim_To_Relaxed … | 站↔蹲、低位↔瞄准各向 |
| 跳跃 Jump(单片) | AN_Pistol_Stand_{Relaxed,Aim}_Jump · 移动跳 AN_Pistol_{Jog,Run,Walk}_*_Jump_IP | 非裂跳;用 _IP 变体 |
| 开火 Fire(站/蹲) | AN_Pistol_{Stand,Crouch}_Fire_{Single,Continuous} | 动作槽 |
| 换弹 Reload | AN_Pistol_Stand_{Aim,Relaxed}_Reload(+_Unjam) | 无蹲姿换弹片段 → 蹲着换弹=播站姿换弹的上半身槽 + 保持蹲姿下半身(动作槽天然分层兜底,已决定,不需额外动作) |
| 掏/收枪 Equip/Holster | AN_Pistol_Stand_{Relaxed,Aim}_{Unholster,Holster} | 仅站姿 |
步枪 Rifle · Content\Animation\Weapons\Rifle\ · 八向 · 最全 · 已重定向(84a)
| 状态 State | 动作资产 Clip(_IPC = 去根) | 备注 |
|---|---|---|
| 待机 Idle(低位/瞄准) | AN_Rifle_Stand_{Relaxed,Aim}_Idle_IPC | 各有 _Idle_v2 + Fgt_v1..v4 |
| 行走/慢跑 8 向(低位) | AN_Rifle_{Walk,Jog}_{F,B,L,R,FL,FR}_Loop_IPC · {BL,BR}_BkPd_Loop_IPC | 含对角;后向对角=后撤步 BkPd |
| 行走/慢跑 8 向(瞄准) | AN_Rifle_{Walk,Jog}_Aim_{F,B,L,R,FL,FR}_Loop_IPC · _Aim_{BL,BR}_BkPd_Loop_IPC | 另有 CIR 绕圈扫射变体 |
| 冲刺 Run(低位,前向弧) | AN_Rifle_Run_{F,FL,FR,L,R}_Loop_IPC | 无 Aim-while-Run |
| 起步 Start(方向化,最全) | AN_Rifle_Stand_{Relaxed,Aim}_To_{Jog,Run,Walk}_{F,B,L,R…}_IPC | 唯一有完整方向起步的层 |
| 急停 Stop | AN_Rifle_{Jog,Run}_{F,B,L,R}_to_Stand_Relaxed_IPC(+LU/RU 落脚) | Aim 停:_Jog_Aim_*_to_Stand_Aim_IPC |
| 原地转身 Turn(循环) | AN_Rifle_{Stand,Crouch}_{Rlx,Aim}_Turn_In_Place_{L,R}_Loop_IPC | 按 yaw 缩放;另有离散步 |
| 蹲待机/蹲走 8 向 | AN_Rifle_Crouch_{Aim_}Idle_IPC · AN_Rifle_CrouchWalk_{Aim_}{F,B,L,R,FL,FR,BL_BkPd,BR_BkPd}_Loop_IPC | |
| 瞄准网格 Aim_Point(站/蹲) | AN_Rifle_{Stand,Crouch}_Aim_Point_{Center,U90,D90,L90,R90,LU45,LD45,RU45,RD45} | 另有更密 5×5 格 |
| 跳跃 Jump(裂跳 Start/Air/End) | AN_Rifle_Stand_{Relaxed,Aim}_Jump_{Start,Air,End}_IPC · 移动跳 _{Jog,Walk,Run}_*_Jump_{LU,RU}_{Start,Air,End}_IPC | 唯一真三段裂跳 |
| 开火 Fire(站/蹲) | AN_Rifle_{Stand,Crouch}_Fire_{Single,Continuous,Burst,Powerful}_IPC | 含点射/全自动/重击 |
| 换弹 Reload | AN_Rifle_Stand_{Aim,Relaxed}_Reload_IPC · AN_Rifle_Crouch_Aim_Reload_IPC | 有蹲姿换弹(比手枪全) |
| 取/收枪 Equip/Holster(背后) | AN_Rifle_*_Equip_Back_Get_From_MOB · _Return_To_MOB | 背后取枪/归位 |
近战 Knife · Content\Animation\Weapons\Knife\ · 单姿态 · 已重定向
| 状态 State | 动作资产 Clip | 备注 |
|---|---|---|
| 待机 Idle(站/蹲) | AN_Knife_St_Idle_00 · AN_Knife_Cr_Idle_00 | 单姿态,无低位/瞄准之分 |
| 行走 8 向(站) | AN_Act_Walk_{F,B,L,R,45L,45R,135L,135R} | 角度命名:45L≈FL、135L≈BL;Walk 有 L/R 无 90 |
| 奔跑 8 向(站) | AN_Act_Run_{F,B,45L,45R,90L,90R,135L,135R} | Run 有 90 无直 L/R(与 Walk 相反,需重映射补格) |
| 蹲走/蹲跑 8 向 | AN_Cr_{Walk,Run}_{F,B,L,R,45L,45R,135L,135R} | 蹲也有 Run 档(比枪层多) |
| 姿态过渡 站↔蹲 | AN_Knife_St_to_Cr · AN_Knife_Cr_to_St | 无瞄准轴 |
| 跳跃 Jump(按速度档) | AN_Knife_St_Jump_{Idle,Walk,Run} | 单片跳 |
| 近战攻击 Melee(全身槽) | AN_Knife_Light_Melee01 / 02 / 03 | 三连;命中窗口 notify 扫刀刃 |
| 受击 / 死亡 | AN_Knife_St_Hit_Light_F · AN_Knife_St_Death_F | 各一条正面 |
空手 Unarmed · Content\Characters\Mannequins\Anims\Unarmed\ · Manny 自带 · 同骨架免重定向
| 状态 State | 动作资产 Clip | 备注 |
|---|---|---|
| 待机 Idle | MM_Idle | 单 idle,无瞄准 |
| 行走 8 向 | MF_Unarmed_Walk_{Fwd,Bwd,Left,Right,Fwd_Left,Fwd_Right,Bwd_Left,Bwd_Right} | 真八向(foot-phased、root-locked) |
| 慢跑 8 向(最高速档) | MF_Unarmed_Jog_{Fwd,Bwd,Left,Right,Fwd_Left,Fwd_Right,Bwd_Left,Bwd_Right} | 无 Run/Sprint |
| 跳跃 Jump(三段) | Jump\MM_Jump · MM_Fall_Loop · MM_Land | 起跳/滞空/落地 |
| 拳击 Melee(可选) | Attack\MM_Attack_01..03 · MM_ChargedAttack | 若空手加攻击 |
| 参考混合空间 | BS_Idle_Walk_Run(+ ABP_Unarmed 样板) | 样板级,非正式 |
_Loop_IP/_IPC 量得 0(原地,正确)→ 速度数须量带位移的 _Loop 或源 clip。BlendSpace 速度轴样本即按这些真实值摆放,配套删掉 UCSPlayerAnimInstance 的 ×600/306 等输入缩放——两者必须同时改(先改 BS 不删缩放会取错样本)。落地路线
Build Roadmap从当前"两套系统 + 手调"重写到上面这套,分阶段、每段可验证、删旧债放最后、全程留可回滚备份。【手工】=编辑器 Persona 人工,【脚本/代码】=可自动化。
先做什么 First Step
P0 + P1:先把基础图和手枪层搭出来——手枪最全、又是低位/瞄准的样板。低位↔瞄准手感纯靠 PIE 视觉迭代,用户点头才算过。
联机验收 Net Check
每个里程碑用 Listen Server + ≥1 客户端验:远端看到的低位/瞄准、换弹时序、换武器换层是否一致。单端 PIE 不算过。
工具边界 Tooling
状态机/转换/sequence player 能脚本搭一部分;BlendSpace player / AimOffset / Linked Layer 节点 Python 建不了 → P0/P1 是开编辑器手摆节点(可 MCP 改属性/连线辅助)。
诚实取舍 Trade-off
手调没清零,是把"无限增长的手调债"换成"每把枪一次性小账单"(量一组真速度 + 压一组 BS + 4 条入出瞄过渡)。丢了 MM 的连续 360°/攀爬(要的话单独补)。
⬜ P0–P5 全待做 · 详细拆分见 Docs/Development/WeaponAnimSystem_*(双姿态重构,方向已更新为分层重写)。
术语表
Glossary本页采用的标准动画 / 运动术语(中文 · English · 一句话定义 · 落点)。
| 中文 | English | 定义 / 落点 |
|---|---|---|
| 运动系统 / 混合空间 | Locomotion / BlendSpace | 移动动画的容器:按速度×方向在采样点间混合出走/跑/转。 |
| 状态机 | State Machine (FSM) | 互斥状态 + 转移条件;本作的地面 locomotion 核心(待机/移动/转身/空中)。 |
| 链接动画层 | Linked Anim Layer | 可在运行时替换的子动画图;每武器一个,LinkAnimClassLayers 换层而不换整个蓝图。 |
| 动画层接口 | Anim Layer Interface | 各武器层共同实现的函数契约(如"出 locomotion 姿势"),基础图按接口调用。 |
| 瞄准偏移 | Aim Offset (AO) | 按瞄准左右上下角度在一张姿势网格取样,让上半身朝准星偏。 |
| 加性动画 | Additive | 相对某基准姿势的"差值",叠加只改它管的骨头(如上半身),腿照跑。 |
| 动作槽 | Montage Slot | 把一次性动作(开火/换弹/攻击)叠在 locomotion 之上的插槽,上半身或全身。 |
| 去根 / 原地 | De-root / In-Place (IP/IPC) | 剥掉 clip 自带位移;联机服务器权威移动必须用,位移交 CharacterMovement。 |
| 低位持枪 / 瞄准 | Low-Ready / ADS | 枪放胸口的默认持枪态 / 举枪瞄准;本作 firearm 层的两套姿势,bIsAiming 切。 |
| 原地转身 | Turn-in-place | 站定大幅转视角时脚步原地倒动,避免脚钉地拧身。 |
| 朝向锁定(横移) | Strafe / Orient-to-Control | 瞄准时身体转向准星、左右输入变横移(vs 平时朝移动方向转)。 |
| 服务器权威 | Server-Authoritative | 真值与决策只在服务器;客户端发请求 + 演表现;动画只读复制态。 |
| 线程安全更新 | Thread-safe Anim Update | 动画在工作线程更新,禁碰 UWorld;查世界的量游戏线程算好缓存、动画只读。 |
| 换层 vs 换蓝图 | LinkAnimClassLayers vs SetAnimInstanceClass | 前者只替子层、保留基础图/槽/IK 不断;后者换整个 AnimInstance(旧法、已弃)。 |
| Motion Matching | Motion Matching (MM) | 不写状态机、按运动特征从大库实时匹配帧;本作已弃用(见 §00)。 |
图例 & 调参
Status Legend & Tuning调参入口 Tuning Entry Points
- 移动手感(速度/转身/瞄准减速/镜头):
ACSPlayerCharacter的WalkSpeed/SprintSpeed/CrouchSpeed/AimingMoveSpeedMultiplier/Aiming*等 EditDefaults 属性。 - 步频对齐 / 不滑步:调 BlendSpace 采样点(按实测真实根速度摆放),不在 CSV、不再用魔法缩放。
- 每武器动作集 / 层类:
UCSEquipmentAnimProfile(低位/瞄准 BS、Fire/Reload/Equip、LocomotionLayerClass),数据驱动、换枪=换表。 - 左手握把 / 瞄准对位:武器
BP_Weapon_*的握点 socket / 左手 IK;预览台M_WeaponPreview所见即所得。
Source/CoopSurvival/Character 与 Content/Animation/Weapons/*,单元状态以 DevelopmentUnits.md 为准。架构 / 类对类地图见 系统设计总览 · 战斗 与 UE_CodeArchitecture.md;枪械机制/表现见 枪械系统。