弹体系统
概述
弹体系统提供了两套实现方案:传统的 Actor 弹体和实验性的数据导向弹体。Actor 弹体方案更成熟,集成了对象池、聚合 Tick 等优化;数据导向方案通过 WorldSubsystem 管理无 Actor 的轻量级弹体数据,是一种性能探索。
Actor 弹体方案
ARogueProjectile(弹体基类)
文件: Source/ActionRoguelike/Projectiles/RogueProjectile.h/.cpp
所有 Actor 弹体的抽象基类,实现 IRogueActorPoolingInterface 支持对象池。
组件:
USphereComponent- 碰撞球URogueProjectileMovementComponent- 自定义移动组件UNiagaraComponent- 循环粒子效果(飞行拖尾)UAudioComponent- 飞行音效
关键特性:
- 碰撞时调用
Explode()播放爆炸特效、音效和摄像机抖动 - 对象池支持:
PoolBeginPlay/PoolEndPlay管理 VFX/Audio 的暂停/恢复 LifeSpanExpired()重写为释放到对象池而非销毁- 使用 Niagara AutoRelease 池化粒子系统
- 使用 Unreal Insights 计数器追踪活跃弹体数量
ARogueProjectile_Magic(魔法弹)
文件: Source/ActionRoguelike/Projectiles/RogueProjectile_Magic.h/.cpp
主要攻击弹体,支持伤害、格挡反弹和施加 Buff。
伤害流程:
- 检测重叠(
OnActorOverlap) - 检查目标是否有 ParryTag(格挡),若有则反弹
- 通过
CanApplyDamage检查是否可以造成伤害 - 调用
ApplyDirectionalDamage造成方向性伤害(含物理冲量) - 可选施加 BurningActionClass(燃烧 Buff)
格挡机制:
if (OtherActionComp->ActiveGameplayTags.HasTag(ParryTag))
{
MoveComp->Velocity = -MoveComp->Velocity; // 反转速度
SetInstigator(Cast<APawn>(OtherActor)); // 反射者成为弹体拥有者
}
ARogueProjectile_Dash(冲刺弹)
文件: Source/ActionRoguelike/Projectiles/RogueProjectile_Dash.h/.cpp
特殊弹体,在爆炸后将发射者传送到弹体位置。
流程:
- BeginPlay 设置延迟引爆定时器
- 爆炸时停止移动、禁用碰撞、播放特效
- 延迟
TeleportDelay秒后传送玩家 - 传送后播放摄像机抖动
- 最后销毁弹体(不使用对象池)
ARogueProjectile_Blackhole(黑洞弹)
文件: Source/ActionRoguelike/Projectiles/RogueProjectile_Blackhole.h/.cpp
黑洞弹体,使用径向力场吸引和销毁物理物体。
特性:
URadialForceComponent持续施加负向径向力- 仅对 PhysicsBody 通道响应重叠
- 使用
URogueCurveAnimSubsystem驱动径向力半径的动态变化 - 根据生命周期自动计算曲线播放速率
URogueProjectileMovementComponent
文件: Source/ActionRoguelike/Projectiles/RogueProjectileMovementComponent.h/.cpp
自定义弹体移动组件,与 Tick 聚合子系统集成。
- BeginPlay 时注册到
URogueTickablesSubsystem - EndPlay 时注销
Reset()方法支持对象池复用
数据导向弹体方案
URogueProjectilesSubsystem
文件: Source/ActionRoguelike/Projectiles/RogueProjectilesSubsystem.h/.cpp
编译开关: USE_DATA_ORIENTED_PROJECTILES (默认 0 = 关闭)
无 Actor 的弹体管理子系统,所有弹体数据存储在简单数组中。
运行时数据 (FProjectileInstance):
- Position, Velocity, ID(每帧更新)
配置数据 (FProjectileItem):
- InitialPosition, InitialDirection, ConfigDataAsset, InstigatorActor, HitResult
Tick 流程:
- 遍历所有弹体实例,计算下一帧位置
- SweepMultiByChannel 检测碰撞和重叠
- 处理命中(伤害、友方过滤、VFX)
- 清理过期弹体
客户端预测:
- 客户端生成唯一 ID(基于位置和时间的哈希)
- 客户端立即创建弹体,同时通过 RPC 通知服务端
- 服务端收到时检查是否已存在(避免重复)
URogueProjectileData
文件: Source/ActionRoguelike/Projectiles/RogueProjectileData.h
弹体配置数据资产,用于数据导向方案:
- ProjectileEffect / ImpactEffect - Niagara 特效
- ImpactDecal_DataChannel - 使用 Niagara Data Channel 的弹痕贴花
- InitialSpeed, Lifespan, DamageCoefficient
FProjectileArray(网络复制)
文件: Source/ActionRoguelike/Projectiles/RogueProjectileReplication.h/.cpp
使用 FFastArraySerializer 实现高效的弹体数据网络同步:
PostReplicatedAdd- 客户端收到新弹体时创建PreReplicatedRemove- 弹体移除时清理PostReplicatedChange- 命中信息更新时播放冲击 VFX
伤害计算
弹体伤害使用系数制:
实际伤害 = Instigator.AttackDamage × (DamageCoefficient × 0.01)
通过 URogueGameplayFunctionLibrary::ApplyDamage() 统一处理。