先和大家打个招呼。一次实战项目中,我在 UE5 里实现角色的近战普通攻击时,先是直接往角色蓝图里堆节点,结果连招手感、伤害判定、动画触发全部挤在一起,改一个需求就要在几百个节点里翻找。后续把攻击逻辑抽离到独立的BP_SystemAttack蓝图后,状态清晰了,调试也方便了不少。这篇文章就围绕这个攻击系统蓝图,结合课程中近战平A这一集的内容,完整拆解 UE5 攻击蓝图的编写思路、节点逻辑和常见坑点。
这篇文章适合刚学 UE5 蓝图、想让角色打出近战平A的开发者。学完后你可以独立完成一次“输入触发 → 蒙太奇播放 → 动画通知 → 碰撞检测 → 伤害输出 → 特效反馈”的攻击链路,并且知道如何扩展为三连击、重击或者技能系统。
1. 近战攻击系统的作用与设计思路
1.1 什么是 BP_SystemAttack
BP_SystemAttack从命名上可以拆成两部分:System表示这是一个系统级蓝图,Attack表示它承载的是攻击逻辑。通俗地讲,它可以是一个 Actor、一个 ActorComponent,也可以是一个挂在角色身上的普通蓝图。它负责管理角色“攻击”这个行为的所有数据与流程。
没有攻击系统蓝图时,很多初学者会把攻击逻辑直接写在角色蓝图(BP_Character)中。这样做在只有一个角色、一个攻击动作时没问题,但一旦出现多个角色共享攻击逻辑,或者攻击动作需要频繁改动,角色蓝图就会变得臃肿。比如,角色蓝图既要管移动、跳跃、摄像机,又要管出生、受伤、死亡,再把攻击责任全部塞进去,蓝图图表会很难维护。
抽出BP_SystemAttack的目的就是让攻击逻辑单独存在。它只关心“能不能攻击”、“攻击哪一段”、“打到了谁”、“造成了多少伤害”,画面表现仍由角色动画负责,命中的特效和音效则交给 Niagara 与音频组件。这种“逻辑与表现分离”的设计,在常见的中大型 UE5 项目中几乎都是标配。
1.2 近战平A的完整流程
一次近战平A,从玩家按下按键到敌人掉血,完整链路可以拆成 6 个阶段:
- 输入阶段:玩家按下鼠标左键或手柄按键,输入系统把事件发送给角色蓝图。
- 状态判断:攻击系统检查角色当前是否允许攻击。比如角色正在攻击、正在翻滚、正在死亡,就不能再次触发攻击。
- 动作播放:角色播放攻击蒙太奇(AnimMontage),通常在这时锁定角色的移动或转向。
- 判定窗口:攻击动画播放到中间的某一帧时,动画通知(AnimNotify)触发攻击判定事件,攻击系统开始检测攻击范围。
- 命中处理:检测到攻击范围内有可伤害目标后,调用目标的受伤接口,计算伤害值,触发
Niagara命中特效和音效。 - 状态复位:动画播放完毕,攻击状态重置,角色可以再次进行下一次攻击。
在这个流程中,阶段 2 和阶段 4 是最容易出问题的。状态判断没做好,角色会被攻击指令“打断”到一半的动画;判定窗口没做对,会出现“动画已经打到人了,但实际没有伤害”或者“动画还没碰到人,伤害已经打出去了”。
1.3 为什么用蓝图而不是C++
UE5 中实现攻击逻辑可以用 C++,也可以用蓝图。两者的选择取决于项目定位和团队结构。
对于初学者、独立开发者或者以原型验证为目的的项目,蓝图有很明显的优势:写节点比写代码直观,变量和事件都能可视化,调试时可以直接在节点上打断点查看数据流向。而且攻击逻辑本身并不复杂,蓝图性能开销在普通规模项目中完全可接受。
对于需要大量网络同步、需要高性能计算、或者需要多人协作的大型项目,C++ 会更合适。BP_SystemAttack这种系统蓝图更多作为“数据容器”和“流程编排器”存在,逻辑中消耗性能的部分再放到 C++ 函数中完成。
本文以蓝图为主,课程中的示例也是基于蓝图的,适合入门阶段理解攻击系统原理。
2. 环境准备与项目结构
2.1 UE5 版本与基础配置
本文示例使用的是 UE5 常见的标准第三人称模板,版本上以 5.x 为例。
需要特别说明的是,不同 UE5 小版本在蓝图节点名称、动画资产细节、Niagara 创建入口等方面会有细微差异。
你在自己的项目中如果发现个别节点名称不同,可以先查看当前 UE5 版本对应的蓝图节点手册,或者直接在蓝图搜索框中输入中文/英文关键词,找到功能最接近的节点。
在创建项目时,建议选择“游戏”类别中的“第三人称”模板,这样角色蓝图、基础动画蓝图、输入配置都已经具备,可以专注于攻击系统的开发。项目名称可以命名为UE5AttackDemo,目标平台使用“桌面平台”即可。
2.2 角色与动画资产准备
实现近战攻击前,至少需要以下资产:
- 一个角色模型(
SKM_Character、Mesh)。 - 角色蓝图(
BP_Character)。 - 动画蓝图(
ABP_Character)。 - 攻击蒙太奇(
AM_Attack)。 - 攻击时的碰撞检测数据。
如果暂时没有自己的角色模型,可以直接使用 UE5 第三人称模板自带的SK_Mannequin模型。课程演示中也通常以引擎自带资产为主,重点在逻辑编写。
攻击蒙太奇需要从动画资产创建。在内容浏览器中选中一个攻击动作动画,右键选择“创建” → “创建 AnimMontage”。
创建后双击打开,把动画片段拖拽到时间轴中。这里要注意:动画片段在时间轴上出现的帧位置,就是后续添加 AnimNotify 的位置。
2.3 创建 BP_SystemAttack 蓝图
在内容浏览器中调用“蓝图类” → “Actor”来创建攻击系统蓝图。注意,这里选择 Actor 还是 ActorComponent,取决于你想把攻击系统当成独立个体还是在角色身上挂载的组件。
课程中的BP_SystemAttack使用的是 Actor 方式,把它作为攻击系统的逻辑载体。如果你更习惯组件化开发,也可以选择ActorComponent。两种方式节点本质相同,只是挂载方式不同。
创建完成后命名为BP_SystemAttack,并添加一个Billboard组件,方便在场景中辨认它的位置。
2.4 输入映射设置
在 UE5 中打开“项目设置” → “输入”,默认已经存在IA_Attack或Attack输入操作。如果没有,就新建一个:
| 输入操作名称 | 类型 | 按键 |
|---|---|---|
| IA_Attack | 数字布尔(Digital Bool) | 鼠标左键 |
| IA_Combo | 数字布尔(Digital Bool) | 鼠标左键连点 |
在角色蓝图中把IA_Attack绑定到攻击事件的调用入口。绑定方式有两种:一是使用EnhancedInput的InputAction节点,二是使用旧的InputAxis或InputAction事件。UE5 默认推荐EnhancedInput,本文示例以该方式展开。
// 输入映射思路 输入动作 IA_Attack → 事件 IA_Attack(角色蓝图 Event Graph) → 调用 BP_SystemAttack 的 StartAttack 自定义事件3. 攻击状态机设计
3.1 攻击状态变量定义
在设计BP_SystemAttack之前,首先要明确攻击过程需要哪些状态变量。这些变量会贯穿整个攻击逻辑。
在BP_SystemAttack中创建以下变量:
| 变量名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| CanAttack | Boolean | true | 当前是否可以攻击 |
| IsAttacking | Boolean | false | 是否正在攻击中 |
| ComboCount | Integer | 0 | 当前连击段数 |
| MaxCombo | Integer | 3 | 最大连击段数 |
| AttackMontage | AnimMontage | 无 | 攻击蒙太奇资产 |
| AttackRadius | Float | 150.0 | 攻击检测半径 |
| AttackDamage | Float | 30.0 | 攻击伤害值 |
这些变量在后续节点中会频繁使用。CanAttack与IsAttacking的区别需要理解清楚:CanAttack表示角色处于“允许发起攻击”的状态,比如角色还在走路、待机时值为 true;IsAttacking表示角色已经进入攻击动作,例如攻击动画还在播放。实际判断时是两个条件同时检查。
3.2 状态切换与互斥逻辑
攻击逻辑中一个关键点是“互斥”:角色在攻击动作期间不能重复触发攻击,否则会出现动画闪断、伤害多次触发。在BP_SystemAttack中使用分支(Branch)节点判断:
StartAttack 自定义事件 ├── [分支] 判断 CanAttack 是否为 true │ ├── false → 直接返回,不做任何处理 │ └── true → 继续执行 ├── [设置] CanAttack = false ├── [设置] IsAttacking = true ├── [播放] AttackMontage └── [延迟] 等待动画结束后调用 EndAttack这里有一个常见误区:只用IsAttacking判断,不使用CanAttack。这样会导致攻击结束后,攻击状态变量仍然停留在某个旧值,下一次攻击无法触发。一个简单的经验是:CanAttack负责“入口开关”,IsAttacking负责“执行过程标志”,两者职责分明。
3.3 连击窗口(Combo Window)
近战平A如果只有一次攻击,会显得很单薄。课程中演示了最基础的三连击设计,核心思路是:攻击动画播放到一定位置时开启“连击窗口”,在这个窗口内玩家再次按下攻击键,会触发下一段攻击;如果超出窗口,攻击结束。
合理设计连击变量:
ComboCount从 0 开始。- 触发第一段时,
ComboCount = 1。 - 动画通知
Notify_ComboWindowStart将CanCombo = true。 - 玩家再次攻击时,检查
CanCombo,如果为 true,则ComboCount++,并切换到第二段蒙太奇。 - 动画通知
Notify_ComboWindowEnd将CanCombo = false。 - 如果
ComboCount达到最大值,暂停接收连击输入。
连击窗口的时间范围要与动画节奏匹配。窗口开启太早,玩家连续按键会跳过前摇动画;窗口开启太晚,按键后需要反应时间,连击手感会变得“不跟手”。一般以攻击动画中“动作已经发生明显变化”的位置作为窗口起点,比如武器挥出到最高速度的那一帧。
4. 核心攻击检测逻辑
4.1 两个关键检测时机:AnimNotify 与 AnimNotifyState
在攻击动画播放过程中,攻击系统需要知道“什么时候开始检测、什么时候结束检测”。这个“时机”不能靠纯粹的定时器猜测,而是应该在动画时间轴上明确标记。
UE5 提供两类节点:
| 类型 | 名称 | 作用 |
|---|---|---|
| AnimNotify(动画通知) | AttackStart | 播放到该帧时触发一次事件,开始检测 |
| AnimNotify(动画通知) | AttackEnd | 播放到该帧时触发一次事件,结束检测 |
| AnimNotifyState(动画通知状态) | AttackCheck | 在指定时间段内持续触发,可在其中做多帧判定 |
使用AnimNotifyState的优势在于,它可以绑定一段区间,蓝图中可以区分“区间开始、区间结束、区间刷新”三个时机。课程中通常使用两个独立的AnimNotify从时间轴上标记攻击的“前摇结束”和“后摇开始”。
在攻击蒙太奇中,找到动画片段中武器挥动到目标方向的那一帧,右键添加通知,命名为AttackHitNotify。后续在BP_SystemAttack中通过Bind AnimNotify或直接使用AnimNotify事件绑定来触发检测逻辑。
4.2 球形碰撞检测方案
攻击判定最常用的方式是球形碰撞检测:以角色前方某个位置为圆心,以AttackRadius为半径,检测范围内所有带碰撞的 Actor。
在BP_SystemAttack中使用SphereOverlapActors节点,核心参数如下:
| 参数 | 设置值 | 说明 |
|---|---|---|
| Spheres Center | Socket 或 Vector | 通常放在武器骨骼插槽位置,或角色前方偏移位置 |
| Sphere Radius | AttackRadius | 攻击检测半径 |
| Object Types | WorldDynamic, Pawn | 只检测需要的对象类型 |
| Class Filter | Character 或 Actor | 过滤目标类型 |
| Ignore Actors | 角色自身 | 避免攻击到自己 |
节点输出Actors数组,遍历数组对每个目标调用伤害接口。
这种方案的优点是逻辑简单、调试容易。你可以用DrawDebugSphere节点在视口中可视化攻击范围,直观看到检测半径是否合理。DrawDebugSphere仅用于开发调试,正式发布时应移除。
// 碰撞检测逻辑 AttackHitNotify 触发 → SphereOverlapActors 检测 → ForEachLoop 遍历结果 → [判断] 是否属于可伤害目标 → 是 → 调用目标的 ReceiveDamage 函数 → 否 → 忽略4.3 射线检测方案
除了球形碰撞检测,部分近战攻击也可以使用射线检测,例如直线枪刺、远程剑气。射线检测方案在 UE5 中常用LineTraceByChannel或LineTraceForObjects。
LineTraceByChannel从起点发射一条射线到终点,返回第一个被击中的对象。它可以检测到墙面、敌人、障碍物。在近战攻击中,可以把射线起点放在角色视线方向,终点放在前方一定距离处,当命中敌人时触发伤害。
UE5 热词中常提到的“射线障碍检测”就是这个思路的扩展:不仅检测第一个目标,还要检测路径上是否有阻挡物。比如角色在一个箱子后面出刀,射线先打中箱子,就应该停止继续检测后方敌人。
实现方式是在射线命中物体后,判断命中对象是否为障碍物,如果Hit.BlockingHit为 true,就不再进行后续穿透。
使用射线检测时需要注意:射线检测只能检测到直线路径上的目标,适合“突刺”、“射击”类攻击,不适合“横扫”类近战。如果角色拿的是大剑或棍棒,球形重叠检测会更符合直觉。
4.4 伤害计算与命中反馈
检测命中目标后,BP_SystemAttack需要把伤害值传递出去。UE5 中常用两种方式:
第一种是直接调用目标蓝图上的自定义事件,事件名比如ReceiveDamage,传入参数为DamageValue、HitDirection、HitFromDirection等。这种方式直观,但要求所有可伤害目标蓝图都有相同命名的自定义事件。
第二种是使用 UE5 的GameplayStatics -> ApplyDamage节点。该节点会向目标 Actor 发送TakeDamage事件,是通用伤害接口。蓝图和 C++ 都支持,适合后续扩展技能系统。
推荐使用第二种方式,因为它的兼容性更好。后续如果接入 GAS(Game Ability System),或者把系统迁移到 C++,伤害通路不用重写。
命中反馈包括:
- 播放命中音效。
- 在命中点生成 Niagara 特效(比如血液飞溅、火花、能量迸发)。
- 给目标一个屏幕 hitshake 或受击动画。
Niagara 特效可以在角色蓝图或攻击系统蓝图中通过Spawn System at Location节点生成,位置取Hit.ImpactPoint。如果命中目标是可破坏物或 NPC,还可以在目标身上调用PlayHitReact之类的动画事件。
5. 完整蓝图串联与运行验证
5.1 BP_SystemAttack 事件逻辑
在实际编写时,BP_SystemAttack的 Event Graph 节点并没有想象中复杂。下面用一个文本形式的伪代码说明完整的节点连接逻辑:
事件 BeginPlay(BP_SystemAttack) ├── [设置] OwnerCharacter = 方案生成的拥有者角色 自定义事件 StartAttack ├── [分支] CanAttack == true │ ├── false → Return │ └── true │ ├── [设置] CanAttack = false │ ├── [设置] IsAttacking = true │ ├── [设置] ComboCount = 1 │ ├── [播放蒙太奇] AM_Attack_1 │ └── [设置定时器] ResetAttackState, 延迟 0.5 秒 自定义事件 ComboAttack ├── [分支] IsAttacking == true 且 CanCombo == true │ ├── false → Return │ └── true │ ├── [设置] CanCombo = false │ ├── [增量] ComboCount++ │ ├── [切换蒙太奇] 根据 ComboCount 播放 AM_Attack_2 / AM_Attack_3 │ └── 再次设置定时器 自定义事件 EndAttack ├── [设置] IsAttacking = false ├── [设置] CanAttack = true ├── [设置] ComboCount = 0 └── [通知] 动画蓝图恢复移动状态 事件 AttackHitNotify(动画通知绑定) ├── [执行] SphereOverlapActors ├── [循环] 遍历 OverlapActors │ ├── [判断] Actor 是否可伤害 │ │ → 是 → ApplyDamage + Niagara 特效 │ └── [结束循环]这个流程中,ResetAttackState定时器可以用Set Timer by Event节点实现。定时器时间不宜过短,否则连击窗口无法形成;也不宜太长,否则攻击结束后角色会有一小段“卡住”体感。课程中一般建议在动画后摇开始时重置状态。
5.2 角色蓝图中调用攻击系统
在角色蓝图BP_Character中,需要把输入事件连接到攻击系统。
首先在角色蓝图中放置一个BP_SystemAttack类型的变量,命名为SystemAttackRef。然后在BeginPlay中Spawn Actor这个蓝图类,并设置它的拥有者为当前角色。
在 Event Graph 中添加IA_Attack输入事件:
事件 IA_Attack(按下) ├── [分支] SystemAttackRef 是否有效 │ ├── false → 创建并生成 SystemAttackRef │ └── true │ └── [调用] SystemAttackRef -> StartAttack 事件 IA_Combo(按下) ├── [分支] SystemAttackRef 是否有效 │ ├── false → Return │ └── true │ └── [调用] SystemAttackRef -> ComboAttack这里出现一个细节:攻击系统蓝图里的事件,如何被角色调用?两种方式都可行:
- 将角色蓝图中的自定义事件设置为
Public访问级别。 - 或在
BP_SystemAttack中把自定义事件设为“可调用”。
建议在BP_SystemAttack中创建自定义事件时,把Input相关参数保留出来,方便外部传参。比如StartAttack中传入AttackDirection、AttackType等参数,这样后续扩展技能攻击时不需要修改入口。
5.3 动画通知相关设置
在攻击蒙太奇AM_Attack_1中,需要把动画通知与BP_SystemAttack连接起来。动画通知本身不会自动调用任意蓝图事件,需要做一次“绑定”。
常见做法是:在角色动画蓝图(ABP_Character)中处理AnimNotify事件,再把事件转发给BP_SystemAttack。也可以在攻击系统蓝图中使用Bind AnimNotify的方式,不过后者对初学者来说更绕。
具体操作步骤:
- 打开攻击蒙太奇,将动画片段拖入时间轴。
- 在时间轴上右键,添加通知
AttackHitNotify。 - 打开动画蓝图,找到该通知的事件节点。
- 在事件节点中获取攻击系统引用,调用
AttackHit或PerformHitDetection自定义事件。
这样动画播放到指定帧时,通知会被动画蓝图捕获,再转发给攻击系统执行检测逻辑。如果动画蓝图中没有该通知的事件节点,通常是因为通知名称拼写不一致,或者动画蓝图的类不是该动画使用的类。
5.4 运行验证
完成上述设置后,按PIE运行游戏。测试清单如下:
| 验证项目 | 预期结果 |
|---|---|
| 按下鼠标左键 | 角色播放第一段攻击动画 |
| 动画中再次按下左键 | 连击窗口开放时触发第二段攻击 |
| 动画未结束强制按键 | 不会打断当前动画 |
| 攻击范围内有敌人 | 敌人掉血,生成命中特效 |
| 攻击范围外攻击 | 不产生任何伤害判定 |
| 攻击结束后立即攻击 | 可正常触发第一段攻击 |
调试时可以在攻击判定处增加打印节点,输出被命中目标的名称。如果打印为空,先检查碰撞检测半径、对象类型和Ignore Actors的设置。
6. 常见问题与排查思路
蓝图攻击系统写完后,最容易遇到以下几类问题。我根据不同现象整理了排查思路:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 按下攻击键没有任何反应 | 输入动作没有绑定,或攻击系统引用为空 | 检查输入映射、BeginPlay中是否成功生成BP_SystemAttack |
| 攻击动画播放了,但没有伤害 | 动画通知没有触发,或检测范围设得太小 | 在动画时间轴中确认AttackHitNotify位置,开启DrawDebugSphere查看检测范围 |
| 攻击动画被连续按键打断 | 状态判断不完整 | 检查CanAttack与IsAttacking分支逻辑,攻击中应阻止再次触发 |
| 连击只能打出第一段 | ComboCount没有在动画结束后重置 | 在连击窗口结束后重置ComboCount,或在EndAttack中归零 |
| 攻击检测到了自己 | 没有在SphereOverlapActors中忽略自身 | 在Ignore Actors数组中加入当前角色 |
| 动画播放结束后一段时间内无法再次攻击 | 定时器时长设置太长 | 缩短ResetAttackState延迟,或在动画结束后立即调用EndAttack |
| Niagara 特效没有生成 | 特效资产未加载,或生成位置错误 | 确认Spawn System at Location的模板资产已添加,位置改为命中点 |
| 网络联机时伤害不同步 | 未使用Execute Server/Multicast | 使用 Server 确认逻辑与 Multicast 广播伤害事件 |
其中最常见的是“动画播放了但没有伤害”。排查顺序为:先看动画通知有没有触发,再看检测半径是否覆盖目标,最后确认目标是否被过滤。使用Print String在AttackHitNotify事件中打印一行字符,如果字符没有输出,说明动画通知绑定没有走通,优先处理通知相关设置。
另一个容易被忽略的问题是“攻击过程中角色可以移动”。如果攻击动画播放中允许移动,会造成攻击判定范围与表现不匹配。常规做法是在StartAttack中设置角色MovementMode为None,在EndAttack中恢复为Walking,或者使用角色移动组件的MaxWalkSpeed临时降为 0。
7. 最佳实践与工程建议
7.1 状态变量的命名与脚本规范
蓝图变量命名建议统一加前缀:布尔类型变量用b开头,比如bCanAttack、bIsAttacking;对象引用用Ref结尾,比如OwnerCharacterRef。虽然蓝图不强制类型前缀,但规范命名在项目变大后能显著降低理解成本。
攻击蓝图内的自定义事件也可以按照“动作 + 时机”命名,例如StartAttack、ComboAttack、EndAttack、PerformHitDetection。不要用Event_1、Func_2这类无意义名称。
7.2 参数配置不要写死在节点里
攻击半径、伤害值、蒙太奇资源等参数,尽量作为变量暴露在BP_SystemAttack的 Details 面板中。这样后续调整攻击手感时,可以直接在蓝图实例上修改,不需要重新排节点。
可以勾选变量的“Instance Editable”和“Expose on Spawn”,这样在Spawn Actor时就能直接传入不同参数。比如不同武器可以在生成攻击系统时传入不同的攻击半径和蒙太奇。
7.3 攻击检测建议放在 Server 端
如果项目是联机游戏,攻击检测不能只在客户端执行。否则每个玩家的伤害结果不一致,甚至会出现“我这边打中了,对方没掉血”的情况。
实现思路是:使用Has Authority分支判断服务器权限。在服务器端执行碰撞检测和伤害计算,然后通过Multicast或RPC通知所有客户端播放特效和音效。客户端的表现只做视觉反馈,不做逻辑判定。
单机开发阶段可以暂时忽略这一层,但如果提前加上服务器判断,后期接入联机时会省很多事。
7.4 Niagara 特效与攻击节奏的配合
Niagara 系统在攻击中的常见用法是两类:一类是攻击挥动时的拖尾特效,另一类是命中时的迸发特效。拖尾特效可以挂在武器的骨骼插槽上,使用 Niagara 的Skeletal Mesh Location更新器跟随武器移动;命中特效则在AttackHitNotify触发位置生成。
特效细节要注意:命中特效经常出现“没打到人但特效就爆了”的错觉,原因是生成点不在真实命中点。在碰撞检测返回中,优先使用Hit.ImpactPoint或者Out Hit Result.ImpactPoint作为特效生成位置,而不是直接使用角色位置。
7.5 攻击帧与动画事件的一致性
攻击检测的触发帧必须与动画表现一致。一个常见的节奏错误是:动画中的武器在攻击动作第 10 帧就挥到了敌人面前,但通知设置在第 20 帧,导致玩家感觉“打到了却没有伤害反馈”。
建议在动画资源中打开“预览网格体”,逐帧查看武器到达目标的时间点。然后在时间轴上把攻击通知放置在那个时间点附近,不要提前太多。通过反复试玩来微调这个偏移,通常能得到比较舒服的打击手感。
8. 总结与下一步学习方向
这一集中,我们完成了BP_SystemAttack蓝图的核心框架:从输入绑定、状态变量、连击窗口、攻击蒙太奇,到碰撞检测、伤害输出和 Niagara 命中特效。这套逻辑是后续技能系统、敌人受击反馈、AI 攻击判断的基础。
在开始写自己的攻击系统时,可以参考以下几个练习方向:
- 给
BP_SystemAttack增加一个重击分支,使用不同蒙太奇和更大伤害值。 - 实现“受击队列”功能,记录同一帧内被命中的所有目标,避免重复伤害。
- 尝试把攻击检测改为多段式检测,例如每隔 0.05 秒检测一次,适配更长的挥砍动画。
- 使用动画通知状态(AnimNotifyState)替代两个独立 AnimNotify,体验持续判定和一次判定的差别。
- 给攻击系统增加耐力消耗,角色没有耐力时无法攻击。
近战攻击虽然是最基础的动作能力,但它涉及了 UE5 中蓝图、动画、物理、Niagara 多个系统的配合。把这套逻辑梳理清楚后,再做怪物 AI、Boss 连招、技能组合都会顺手很多。