“碰撞事件?不就是加个Collision组件,勾上Generate Overlap Events,然后Bind OnComponentBeginOverlap吗?”——三年前,我对着刚入行的新人这么吹牛。结果在那之后的一个多月里,我被这句话疯狂打脸。那是一个ARPG项目,主角要能砍怪、怪能砍主角、机关要能被触发、掉落物要能被磁吸、场景里还有一堆可破坏的瓶瓶罐罐。听起来不就是Overlap和Hit吗?对,就是这两个词,让我读了三遍源码,翻了五遍官方论坛,最后在项目复盘会上立了块白板,画了整整两小时的“碰撞决策树”。今天这篇文章,我把这趟浑水里的所有教训一次性倒出来——不讲教科书定义,只聊项目里真刀真枪干出来的认知。

一、需求拆解:为什么“Overlap和Hit”能把人逼疯?
先交代背景。项目是第三人称动作游戏,核心交互有五类:
- 武器挥砍怪物 → 需要知道砍没砍到、砍到了谁、从哪个方向砍的、砍了几次;
- 怪物攻击主角 → 需要受击反馈、方向判定、连击计数;
- 踩到压力板/走进光圈 → 触发机关、显示UI;
- 拾取金币/药水 → 靠近吸附、碰到即消失;
- 可破坏物件 → 被刀砍碎、被火球炸飞。
这五类需求,表面上看都是“检测到东西碰上了”,但背后需要的物理信息量完全不同。武器砍怪物,我需要接触点、法线、冲量;踩压力板,我只需要一个“在不在里面”的布尔值;金币吸附,我甚至不想用物理,只想要距离。这就是第一个认知拐点:Overlap和Hit不是两个可以随便换用的开关,它们是两套物理查询语义。
💡 老司机提示:如果你在项目初期就无脑把所有碰撞体勾上Generate Overlap Events,后期一定会被事件风暴和性能问题反噬。先想清楚“我需要什么信息”,再决定用哪种事件。
二、技术选型:Overlap是关系,Hit是瞬间
我把引擎底层翻了一遍,用最人话的方式总结:
Overlap事件描述的是“两个碰撞体之间的持续包含关系”。它由物理引擎的Broadphase阶段(粗筛阶段)产生——引擎用AABB包围盒快速排除不可能相交的物体,剩下的进入Narrowphase(细筛)。当两个物体的碰撞形状在细筛阶段被判定为“重叠”,引擎就会在下一帧发送BeginOverlap;当它们分开,发送EndOverlap。注意,Overlap不包含任何接触点、法线、冲量信息——因为它压根没走到接触求解那一步。
Hit事件描述的是“一次物理接触的瞬间”。它由Narrowphase之后的Contact Generation(接触生成)阶段产生。引擎不仅判断“碰上了”,还要计算接触点、穿透深度、接触法线,然后交给物理求解器去解算。因此Hit事件天然携带FHitResult,里面有ImpactPoint、ImpactNormal、NormalImpulse、PhysMaterial等一整套数据。
用一句话记住:Overlap是“你们俩在一块儿”,Hit是“你们俩撞了一下”。

基于这个认知,我重新做了技术选型表:
| 需求 | 事件类型 | 关键理由 |
|---|---|---|
| 武器砍中怪物 | Hit | 需要ImpactPoint做血花、ImpactNormal做击退方向 |
| 怪物攻击主角 | Hit | 需要冲量计算硬直、方向判定格挡 |
| 踩压力板 | Overlap | 只需要“进入/离开”状态,不需要物理反馈 |
| 金币吸附 | Overlap + 自定义距离 | 吸附用Overlap触发,移动用代码插值 |
| 可破坏物件 | Hit | 需要冲量判断破坏阈值 |
三、踩坑现场:那些让我凌晨三点还在查源码的问题
坑1:Overlap事件为什么“时有时无”?
项目做到中期,测试提了个Bug:角色有时候能踩到压力板,有时候踩上去没反应。我一开始以为是碰撞体没对齐,后来发现是碰撞通道(Collision Channel)和响应设置(Response)没配对。UE5的碰撞系统是一个“通道+响应”的矩阵,每个碰撞体有一个Object Type,每个Query有Trace Channel,响应可以是Ignore、Overlap、Block。关键来了:要让Overlap事件触发,两个物体之间的响应必须是Overlap或Block;如果任意一方把对方设为Ignore,事件永远不会来。
更坑的是,Generate Overlap Events这个勾选项只控制“我是否愿意产生Overlap事件”,但它不控制对方是否响应。也就是说,A勾了、B没勾,或者A的通道对B是Ignore,都收不到事件。我的解决方案是:把碰撞矩阵画成一张表贴在工位上,每次新加一类物体,先填表再写代码。
坑2:Hit事件重复触发,一刀砍出五段伤害
武器挥砍用的是Hit事件,结果测试反馈“一刀下去怪物掉五次血”。原因很简单:武器碰撞体和怪物碰撞体在那一帧里产生了多个接触点,每个接触点都触发一次Hit。引擎没有帮你做“同一次挥砍只算一次”的逻辑,这是游戏层的事。我的解决方法是给武器加一个“本次挥砍已命中列表”,在OnComponentBeginOverlap之外,改用OnComponentHit并在Actor层记录已命中的唯一ID,挥砍动画结束时清空。
void AWeapon::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (!OtherActor || OtherActor == GetOwner()) return;
if (HitActorsThisSwing.Contains(OtherActor)) return; // 本次挥砍已命中
HitActorsThisSwing.Add(OtherActor);
// 处理伤害、击退、特效...
}
⚠️ 注意:Hit事件和Overlap事件一样,都可能在同一个物理帧里对同一个物体触发多次。永远不要假设“一次碰撞=一次事件”。
坑3:Overlap事件不按帧来,按物理子步来
UE5的物理模拟默认以固定时间步长(默认是1/60秒)运行,但渲染帧可能高于或低于这个值。这意味着Overlap事件的触发频率和你的游戏帧率解耦。我在做金币吸附时写了个逻辑:在BeginOverlap里把金币标记为“可吸附”,在Tick里插值移动。结果在高帧率下金币飞得飞快,低帧率下慢如蜗牛。后来改成用FMath::VInterpConstantTo配合DeltaTime,问题解决。
四、底层原理:为什么Overlap和Hit的性能差这么多?
这个问题是我在一次性能优化会上被主程问住的。当时场景里有三百多个可交互物体,全开了Hit事件,帧率掉了15帧。我一开始以为是事件回调本身的开销,后来用Unreal Insights抓了一帧才发现:Hit事件触发了完整的接触求解,而Overlap只走了Broadphase和Narrowphase的相交测试。
具体来说,物理引擎的管线是:Broadphase粗筛 → Narrowphase细筛 → Contact Generation接触生成 → Solver求解。Overlap事件在Narrowphase之后就可以发出,而Hit事件必须等到Contact Generation完成。接触生成不仅要算几何相交,还要算穿透深度、接触法线、摩擦锥,这些数据要喂给物理求解器。所以Hit事件的计算量可能是Overlap的三到五倍。
我的优化策略是:能用Overlap就不用Hit,能用Trace就不用事件。比如金币拾取,我最终改成了每帧用SphereOverlapMultiByChannel做一次查询,而不是让金币一直挂着Overlap事件。这样可控性更强,性能也更稳定。

五、交付复盘:我总结的“碰撞决策四问”
项目上线后,我把这套经验固化成了四个问题,每次新人问我碰撞怎么搞,我就让他先回答:
- 我需要物理反馈吗?需要冲量、接触点、法线 → Hit;不需要 → Overlap。
- 我需要持续状态吗?需要知道“还在里面” → Overlap;只需要“碰了一下” → Hit或Trace。
- 我能接受事件风暴吗?高频率物体(子弹、粒子) → 用Trace或自定义查询,别用事件。
- 碰撞矩阵配好了吗?Object Type和Response没配好,写什么代码都白搭。
最后说句掏心窝子的话:Overlap和Hit本身不难,难的是你知道什么时候不该用它。我在项目里犯的最大错误,不是不会写事件,而是“手里有锤子,看什么都像钉子”。碰撞检测是物理引擎的入口,但绝不是唯一入口。Trace、Sweep、自定义查询,每一样都有它的适用场景。
如果你也在UE5的碰撞系统里挣扎过,别慌,这是每个进阶设计师的必经之路。把物理管线画一遍,把碰撞矩阵填一遍,把事件触发条件读一遍,你会发现那些“玄学Bug”其实都有迹可循。
关于火星人教育
火星人教育创办24年来,一直专注数字艺术与AIGC实战职业技能培训。我们开设的课程包括:AI漫剧创作、AIGC视觉设计、UE5游戏特效、室内全屋定制、MAYA三维动画、C4D动态设计、工业设计、NUKE影视后期、摄影摄像实训。北京、深圳双校区开设线下面授班,面向美术生、在校大学生及意向转行的职场人群,以项目化实训教学为核心,夯实专业技能,助力就业与职业提升。如果你也想在UE5的物理系统和游戏特效领域深耕,欢迎咨询:010-65918670。








评论(0)