
“平A”这个看似简单的动作在 UE5 蓝图里落地时会牵扯出一连串问题怎么触发攻击怎么限制连击节奏动画播到哪一帧开始判定伤害如果只在角色蓝图里随便连一个 Play Montage 节点后续加连击、加特写、加命中特效时蓝图逻辑会迅速变成一团乱麻。本文将围绕 BP_SystemAttack 攻击蓝图从 UE5 新手的视角系统拆解近战平A攻击逻辑的完整编写过程。这是“上篇”重点解决攻击入口、状态控制、蒙太奇播放、动画通知触发以及基础的伤害判定思路。学完你能理解 UE5 动作攻击蓝图的骨架也能跟着步骤在第三人称模板上做出一个可玩的近战平A Demo。1. 为什么要单独做一个攻击蓝图很多初学者做攻击功能时习惯直接把“键盘按下”和“播放动画”连在一起跑起来好像没问题但一旦加入连击、后摇、攻击位移、命中检测就会遇到几个躲不开的问题攻击状态与其他行为跑、跳、受到伤害互相打断。动画还没播完玩家再次按攻击键动画被强行重置。判定伤害的时机很难和动画帧对齐。后续加特效、音效、受击反馈时逻辑散落在各个蓝图里。BP_SystemAttack 的价值就是把这些零散节点组织成一套“可复用的攻击状态机”。它不只是一个蓝图而是一种处理攻击流程的思路输入处理、状态判断、动画播放、通知事件、伤害结算各司其职。本文实现的框架如下玩家输入(左键) - 攻击状态锁判断 - 连击计数更新 - 播放攻击蒙太奇 - 动画通知(Notify)触发判定事件 - 碰撞查询找到目标 - ApplyDamage 造成伤害这个链路里“上篇”会写到动画通知触发为止同时把伤害判定的入口和关键节点讲清楚让下篇能够直接在此基础上扩展。2. 环境准备与项目设定2.1 引擎版本说明本教程基于 UE5 蓝图系统编写。不同 UE5 小版本之间部分节点名称、菜单位置会有差异例如 UE5.1 之后第三人称模板默认使用增强输入Enhanced Input而旧项目可能还在使用传统输入轴映射。本文示例以 UE5 通用方案为准不绑定某个具体小版本。如果你打开项目设置时看到的界面和本文描述不一致优先检查项目是否开启了 Enhanced Input 插件或者按你自己的工程版本调整输入处理方式。2.2 推荐项目模板与资产建议从第三人称模板创建工程这样可以直接使用默认的 ThirdPersonCharacter 和 Mannequin 骨骼网格体省去自己搭建角色的时间。如果你有自己的角色资产也可以替换。攻击动画方面示例中会用到一段近战挥砍动画和配套的蒙太奇资产。你可以使用商店资源、自己制作的动画也可以用引擎自带动画重定向后凑合。本文重点是蓝图逻辑动画资源不要求很高品质但建议至少保证有一段完整的单手挥砍动画时长在 0.5 到 1 秒左右。动画有明显的“攻击帧”也就是武器挥到目标位置的那一帧方便后面放置 Notify。2.3 创建测试角色与基础场景在内容浏览器中创建基于 Character 的蓝图类命名BP_TestCharacter。如果你的工程没有自定义角色也可以直接在第三人称模板的 BP_ThirdPersonCharacter 上加逻辑。为了后续测试方便场景里放一个用于攻击的目标。可以用引擎自带的 Cube 搭建一个假人给它添加 StaticMesh 和碰撞体后面通过蓝图打印伤害数值来验证攻击是否生效。3. 近战平A攻击的核心概念动手之前先理解四个关键概念。很多新手写攻击蓝图失败不是因为节点复杂而是没搞清动画系统、碰撞系统和伤害系统分别负责什么。3.1 攻击流程中的“三阶段”一次完整近战攻击可以拆成三个阶段前摇阶段角色从静止进入攻击动画这个阶段没有伤害判定。伤害判定阶段动画播放到特定帧武器挥出此时执行碰撞检测。后摇阶段伤害判定结束角色恢复待机。前摇和后摇决定了攻击手感伤害判定决定了攻击是否命中。蓝图里最难做的不是伤害数值而是“如何让伤害判定严格对齐动画帧”。3.2 动画蒙太奇与动画通知动画蒙太奇Anim Montage是 UE5 中管理动画片段播放的容器。你可以把它理解为一段“动画脚本”它能控制动画播放、暂停、跳转还可以在动画时间线上的特定位置插入通知。动画通知AnimNotify和通知状态AnimNotifyState是挂在动画序列或蒙太奇上的标记AnimNotify触发一次类似事件瞬间。AnimNotifyState触发开始和结束两个事件适合“从武器抬起开始检测到武器收回结束检测”这种区间逻辑。近战攻击中常用 AnimNotifyState 控制伤害检测的有效时间区间。更简单粗暴的做法是在动画的“攻击帧”放一个 Notify在动画结束前放一个关闭标记。本文上篇先用 Notify 的方式打开判定通道方便理解事件流。3.3 碰撞检测与伤害结算碰撞检测负责回答“这次攻击打中了谁”伤害结算负责回答“被击中者扣多少血”。两者在 UE5 蓝图中通常分开处理碰撞检测使用 Sphere Overlap Actor 或 Sweep Single by Channel 等节点从角色/武器位置向外检测。伤害结算使用 GameplayStatics 库的 ApplyDamage 节点或直接调用目标身上的自定义伤害函数。后面会专门演示一个最小可用的判定入口。4. 输入与攻击状态锁4.1 输入映射在 UE5 中攻击输入可以用传统 InputAction 或增强输入系统处理。以增强输入为例你需要一个 IA_Attack 输入动作并把它绑定到鼠标左键。输入动作配置参考{ InputActionName: IA_Attack, Trigger: Pressed, Bindings: [ { Key: LeftMouseButton, Modifiers: [] } ] }具体操作路径内容浏览器右键 - 输入 - 输入动作创建IA_Attack然后在项目设置 - 输入 - 默认玩家输入的映射中添加绑定。如果你是旧版输入系统可以在角色蓝图的 EventGraph 中直接使用InputAction Attack事件节点。两种方式最终的逻辑入口是一样的。4.2 攻击状态锁攻击状态锁是防止玩家在攻击动画播放期间重复起手的关键。通常使用一个布尔变量bIsAttacking表示角色是否正在攻击。逻辑图如下输入事件触发 - Branch - 条件bIsAttacking false - 执行攻击 - bIsAttacking true - 如果为 true直接忽略本次输入需要明确的是bIsAttacking true不能一直保持否则角色会永远无法再次攻击。通常选择在动画蒙太奇结束时通过OnCompleted事件把状态复位或者用一个定时器延迟复位。4.3 连击窗口与连击计数平A不只打一下往往需要支持“三连击”或“四连击”。这要求玩家在攻击后摇阶段再次按键时能够进入下一段攻击而不是被状态锁直接忽略。常用方案是引入连击计数AttackCount和连击窗口玩家第一次攻击AttackCount 从 0 变为 1播放第一段动画。动画播到后摇阶段时打开“连击窗口”bCanCombo true。玩家在窗口内再次按攻击键AttackCount 1播放第二段动画。若超过窗口时间未按键AttackCount 重置为 0角色回到待机。蓝图里可以使用定时器或 Delay 节点实现窗口。这里有一个重要技巧Delay 节点在被再次触发时会取消之前的等待。简单说玩家每次按下攻击键都会把上一次的“重置计时器”冲掉并重新计时。这样玩家只要连续按键计数就不会被中途重置。4.4 攻击输入入口伪代码为了更好理解 EventGraph 节点排列下面用伪代码形式描述攻击入口逻辑Event Attack Input - If (bIsAttacking true) return - If (bCanCombo true) - AttackCount 1 - else - AttackCount 1 - 播放对应攻击蒙太奇 - bIsAttacking true - 启动连击窗口计时器 (2秒后重置 AttackCount)这里的bCanCombo会在前一段攻击动画播放到某个时间点后由动画通知打开。下面来看动画通知如何接入蓝图。5. 播放攻击蒙太奇与动画通知5.1 创建攻击蒙太奇在内容浏览器中选中你的挥砍动画右键 - 创建 - 创建 AnimMontage动画蒙太奇。命名建议AM_Attack_01。打开蒙太奇编辑器后要处理两件事确认动画时长和循环设置正确。在攻击帧位置添加 AnimNotify。先不急着加太多通知建议从最小闭环开始加一个名为MeleeHit的通知作为“这一帧开始判定伤害”的信号。5.2 在蓝图里播放蒙太奇角色蓝图中播放蒙太奇有两种常见方式从角色组件里找到网格体调用Play Anim Montage节点。获取动画实例在动画蓝图里调用播放入口。角色蓝图中更简洁的是直接调用Play Anim Montage英文界面节点名可能是Play Anim Montage或Play Montage不同版本有差异。节点输入参数包括Montage to Play要播放的蒙太奇资产。Play Rate播放速度默认 1.0。Start Section Name起始段名可以留空从默认段播放。Start Montage At时间偏移默认从零开始。播放结束后蒙太奇节点会有OnCompleted、OnBlendOut、OnInterrupted等输出事件建议绑定一个自定义事件在动画播完或被打断时统一处理状态复位。5.3 处理动画通知事件动画通知到蓝图之间的传递有两种常见做法。第一种直接在动画蓝图中创建事件。在动画蓝图事件图表中添加对应通知名称的自定义事件例如AnimNotify_MeleeHit。但这个事件发生在动画蓝图内部要把信号传给角色蓝图需要额外调用。第二种把通知事件广播给角色。在动画蓝图中收到AnimNotify_MeleeHit后通过Try Get Pawn Owner获取角色引用调用角色上的自定义事件MeleeAttackHit。这样角色蓝图内就可以统一处理伤害逻辑了。这里有一个工程经验尽量不要在动画蓝图中写大量伤害逻辑。动画蓝图专注于动画播放攻击判定和伤害计算应该回到角色蓝图。动画蓝图里只做“转发信号”这一件事。5.4 蒙太奇分组的说明如果角色同时有上身攻击和下身走路动画蒙太奇分组 Slot 的配置就很重要。默认情况下蒙太奇播放时会覆盖整个身体动画。在更复杂的动作游戏中通常会让攻击动画只播放上半身下半身保留移动或蹲伏动画。此时需要在动画蓝图中添加 Slot 节点把DefaultSlot和UpperBody之类的插槽区分开。对于本文的简单平A来说可以先不处理分组整段播放。等后面做“移动攻击”时再引入分组这个概念。5.5 完整事件流示例下面是一个精简的动画通知转发参考写法动画蓝图 EventGraph: AnimNotify_MeleeHit - Owner Try Get Pawn Owner - Cast To BP_TestCharacter - 调用 BP_TestCharacter.MeleeAttackHit角色蓝图 EventGraph: MeleeAttackHit 自定义事件 - 执行伤害检测与结算这样角色蓝图拿到“攻击帧到了”的信号后就可以开始做碰撞检测了。6. 基础近战伤害判定与结算6.1 选择碰撞检测方式近战伤害判定常见有三种方案球形重叠检测Sphere Overlap Actors在角色前方生成一个球体检测该球体半径内是否有可被攻击的对象。优点是实现快适合演示。射线检测Line Trace Single从武器起始点到指定方向打一条射线适合刀剑挥砍的瞬时检测。基于武器碰撞体的 Overlap 检测在武器网格体上放置碰撞体攻击时激活碰撞并监听 Overlap。新手阶段推荐先用Sphere Overlap Actors因为节点参数直观不容易踩碰撞预设的坑。下篇再讲更精细的武器碰撞方案。6.2 设置忽略自身用Sphere Overlap Actors时有一个必须处理的点自己也是一个 Actor如果不忽略自己武器一挥角色自身的骨骼网格体也会被检测到。节点Sphere Overlap Actors的Actors to Ignore参数需要把自己放进去。直接传入self即可。如果需要忽略队友可以按 Actor Tag、碰撞通道或蓝图接口进行过滤。过滤逻辑越早做后面扩展越安全。6.3 伤害结算接口UE5 本身自带一套通用伤害接口核心是ApplyDamage。它的参数包括Damaged Actor被伤害的目标。Base Damage伤害数值。Event Instigator伤害来源的 Controller。Damage Causer伤害来源 Actor通常是角色或武器。Damage Type Class伤害类型类可留空。在蓝图中可以从 GameplayStatics 库拖出ApplyDamage节点。然后在目标的蓝图或通用 Actor 类中覆写ReceiveAnyDamage事件当该 Actor 被 ApplyDamage 击中时ReceiveAnyDamage会自动触发。这里给一个对应的 C 对比接口帮助理解蓝图背后的概念// DamageIntensity.h UINTERFACE(MinimalAPI) class UDamageIntensity : public UInterface { GENERATED_BODY() }; class IDamageIntensity { GENERATED_BODY() public: UFUNCTION(BlueprintNativeEvent, Category Damage) void ReceiveMeleeDamage(float BaseDamage, AActor* DamageCauser); };蓝图版本则可以直接用ReceiveAnyDamage事件不需要额外建接口。如果你希望自定义受击反馈也可以在角色蓝图上写ReceiveMeleeDamage自定义事件然后从攻击侧直接调用目标身上的这个自定义事件。6.4 最小判定流程伪代码MeleeAttackHit 事件 - 获取角色前方向量 - 设置检测球体中心 ActorLocation ForwardVector * 150 - Sphere Overlap Actors - Sphere Radius 100 - Actors to Ignore [self] - 遍历所有 Overlap Actors - 如果是目标可攻击角色 / 假人 - ApplyDamage - 打印命中对象名称这段逻辑完成之后攻击时只要动画播放到MeleeHit通知帧角色前方区域内的敌人就会被扣血。上篇的核心链路到这里已经完整了。7. 常见问题排查与工程建议7.1 常见问题表格问题现象常见原因解决思路按攻击键没反应输入映射未配置或增强输入资产未添加到映射上下文检查项目设置输入绑定确认攻击按键的 Trigger 类型是 Pressed动画播放后角色卡死无法再次攻击bIsAttacking 没有在动画结束时复位绑定 Play Anim Montage 的 OnCompleted 事件在事件里复位状态变量攻击判定只在第一段动画生效后续连击蒙太奇没有添加 MeleeHit 通知为每一段攻击动画都添加对应通知并统一命名为 MeleeHit 或按段区分角色攻击时把自己打到了Sphere Overlap Actors 没有忽略自身把 self 加入 Actors to Ignore 列表动画通知事件没有触发通知名称与蓝图事件名称不一致或通知放在了错误的轨道打开蒙太奇/动画序列确认通知位置核对动画通知事件命名目标受到伤害但不会死亡目标蓝图没有血量变量或死亡逻辑在目标 Actor 上定义血量监听伤害事件并执行销毁/死亡动画判定范围过大或过小SphereOverlap 半径参数和攻击动画不匹配先打开可视化辅助调试反复调整球体半径与中心偏移7.2 蓝图布局建议事件图表中节点一多新手很容易迷失。建议把 EventGraph 分成几个区块用注释框Comment Box圈起来输入处理区所有输入事件入口。状态控制区攻击状态锁、连击计数、定时器。动画播放区播放蒙太奇和状态复位。伤害判定区MeleeAttackHit 之后的碰撞与 ApplyDamage。模块之间的调用建议走自定义事件或蓝图接口不要用一堆Cast To互相拖线。特别是角色蓝图和动画蓝图之间保持单向调用关系动画蓝图只发通知角色蓝图统一处理结果。7.3 调试技巧在蓝图节点上点击右键可以添加断点。运行游戏后攻击时观察断点是否命中可以快速判断输入、动画通知、碰撞检测哪一段链路断了。碰撞检测阶段建议先用Draw Debug Sphere可视化检测范围。这样你一眼就能看出球体的位置和半径到底对不对。Debug 节点在验证完后记得删除否则打包后可能影响性能。7.4 性能与安全注意Overlap 检测不要每帧执行只在动画通知触发时才执行。Actors to Ignore不要只填一个角色要尽可能填上所有不参与判定的 Actor减少遍历开销。伤害处理严格区分客户端与服务器。本文是单机演示逻辑相对简单如果是联机项目伤害结算必须由服务器权威执行客户端只负责表现。修改血量、销毁 Actor 这类操作要谨慎。尤其涉及网络属性复制时建议先在本地单机测试再考虑多人同步。7.5 命名与目录建议一个攻击系统会涉及蒙太奇、动画通知、蓝图类、特效资产项目资源目录尽量按模块划分避免所有资产堆在根目录Content/ Characters/ Mannequin/ Animations/ Montages/ Notifies/ Blueprints/ Character/ System/ FX/ Niagara/蓝图命名也保持统一角色蓝图BP_TestCharacter攻击系统蓝图BP_SystemAttack攻击蒙太奇AM_Attack_01、AM_Attack_02通知命名MeleeHit、MeleeComboWindowOpen、MeleeEnd8. 后续扩展Niagara 特效与完整战斗反馈经过上面这些步骤你的角色已经可以完成一次“平A - 命中 - 扣血”的最小闭环。这是战斗系统最核心的地基。接下来可以继续扩展的方向有很多第二个、第三个连击段以及不同段位的伤害倍率。命中停顿Hit Stop在命中瞬间让动画短暂暂停提升打击感。伤害数字、飘血、命中闪白。受击动画和死亡动画。Niagara 命中特效在命中点生成刀光、血液飞溅、攻击拖尾。其中 Niagara 特效与攻击判定的衔接方式通常是命中检测拿到目标 Hit Result 或 Overlap 位置之后在该位置Spawn System at Location播放 Niagara 特效。例如在MeleeAttackHit事件中检测到目标后生成攻击特效系统。与动画的配合上武器拖尾通常作为 Niagara 组件附加在武器骨骼插槽上在攻击前摇阶段隐藏在攻击判定阶段显示后摇或动画结束时隐藏。这部分的“显示/隐藏”时机依然可以通过 AnimNotify 来控制。所以不要急着把特效、音效都堆在上篇里。先把“输入 - 动画 - 检测 - 伤害”这条主线跑通你会发现后续接 Niagara、接音效都只是在这条链路上增加几个分支而已。从工程经验来说战斗系统最忌讳一开始就铺太开。建议一步一步来今天先做出可玩的单段平A明天再加连击后天再加特效。Battle 系统的手感是“调”出来的不是一次写出来的。如果你在跟着本文操作时遇到了报错先别急着改大逻辑按第 7 节的排查表格逐项检查输入映射、通知名称、碰撞过滤三件事大部分问题都出在这三个地方。把这套最小闭环跑顺了再往后走的信心会完全不一样。