
观众老爷们大家好 我是邪修KING 欢迎来到我的TA->UE游戏引擎博客---入门篇! C++!高门槛!精选学习! 系列衔接:上一篇我们完成了 Actor 蓝图创建、自动旋转、WASD 键盘移动、鼠标点击变色 4 个核心交互,实现了单物体的动态效果。本篇我们将解锁 UE 多物体联动的核心 ------碰撞与触发系统 ,同时结合 C++ 面向对象的封装思想,完成蓝图逻辑的模块化重构,彻底告别 "面条蓝图",是新手从 "会操作" 到 "懂开发" 的关键一步。
适配人群:有 C/C++ 基础、已掌握 UE 基础操作的新手,全程沿用前序项目,无需从零搭建场景。
前置准备1.沿用前两篇的 UE 项目,场景中保留已实现 WASD 移动的BP_CubeTest蓝图实例(玩家控制立方体)
2.已掌握蓝图基础操作、C++ 类与对象、函数封装、条件判断等基础语法
3.引擎版本:UE5.0+,全版本操作通用,无兼容问题
一、核心概念前置:用 C++ 知识秒懂 UE 碰撞体系
UE 的碰撞系统是所有交互的基础,新手最容易被 "碰撞预设、碰撞通道、重叠事件" 等术语劝退,但只要有 C++ 基础,就能直接对应底层逻辑,这是你学 UE 的最大优势:
| UE 碰撞术语 | 对应 C++ 核心概念 | 一句话核心说明 |
|---|---|---|
| 碰撞体(Collision) | 类的成员属性(边界描述) | 物体的 "物理边界",而非视觉网格体。UE 只检测碰撞体的相交,而非模型面,对应 C++ 中用结构体描述的物体边界范围 |
| 碰撞预设 | 类的访问权限修饰符 | 预定义了物体的碰撞类型、可交互的对象,比如「静态物体」预设对应场景中不动的障碍物,「Pawn」预设对应玩家控制的物体,和 C++ 的 public/private 限定访问范围逻辑完全一致 |
| 碰撞通道 | C++ 枚举类型 | 用于给物体分类,实现碰撞过滤。比如玩家通道、场景物体通道、敌人通道,UE 只会检测你指定通道的物体碰撞,避免无效计算,对应 C++ 中用枚举做类型区分 |
| 碰撞事件(Hit) | C++ 带条件判断的回调函数 | 两个物体物理碰撞阻挡时触发,比如玩家撞墙、子弹击中物体,必须满足 "碰撞体阻挡" 的前提 |
| 触发事件(Overlap) | C++ 无阻挡的回调函数 | 两个物体碰撞体相交时触发,无物理阻挡效果,比如玩家走进触发区开门、吃道具,对应 C++ 的 "范围检测 + 触发回调" |
| 蓝图函数 | C++ 类的成员函数 | 将重复的逻辑封装成独立模块,可重复调用、传参、设置返回值,核心是实现代码复用,对应 C++ 函数封装的核心思想 |
二、分步实操:4 个核心模块,从碰撞基础到模块化开发
实操 1:碰撞基础配置,搞定 90% 新手踩坑的前提设置
前序我们的立方体可以移动,但会直接穿过场景中的其他物体,没有任何碰撞反馈,核心就是没有完成正确的碰撞配置。
1.给玩家控制的立方体设置碰撞
+双击打开BP_CubeTest蓝图,选中左侧「组件」面板中的StaticMeshComponent0(立方体的网格体组件)
+右侧「细节」面板,找到碰撞 分类:
--碰撞预设:选择「Pawn」(UE 为玩家控制物体预设的碰撞配置,适配移动交互)
--勾选生成碰撞事件 (核心!不勾选永远无法触发碰撞 / 触发事件,90% 新手碰撞无效的根源)
--碰撞复杂度:选择「简单碰撞」(新手入门优先用简单碰撞,性能更高,逻辑更简单)
2.给场景创建障碍物并配置碰撞
+回到主场景,在左侧「放置 Actor」→「基本」中,拖入多个立方体 / 球体,作为场景障碍物,给它们赋予不同的材质
+选中所有障碍物,右侧「细节」面板→碰撞分类:
--碰撞预设:选择「静态物体」
--勾选生成碰撞事件
--检查「静态网格体」分类下,是否有简单碰撞体(若没有,点击「生成简单碰撞」,UE 会自动生成匹配模型的碰撞边界)
3.验证碰撞效果
点击播放,用 WASD 控制立方体移动,此时立方体不会再穿过障碍物,而是会被物理阻挡,基础碰撞配置完成!
核心原理补充
UE 的碰撞检测逻辑:只有两个物体的碰撞通道互相匹配,且都开启了「生成碰撞事件」,才会触发碰撞回调,对应 C++ 中「两个对象满足预设条件,才会执行回调函数」的逻辑,避免了全场景无差别碰撞检测的性能浪费。
实操 2:碰撞销毁效果,实现玩家碰撞清除障碍物
这是碰撞事件的最基础应用,我们将实现:玩家控制的立方体碰到障碍物时,障碍物自动销毁,同时播放变色反馈,完美衔接上一篇的动态材质知识。
1.创建障碍物蓝图类
选中场景中任意一个障碍物,右键→转为蓝图类,命名为BP_Obstacle,双击打开蓝图编辑器
设计思路:和 C++ 一样,我们需要先定义一个通用的障碍物类,所有场景障碍物都用这个类实例化,后续修改逻辑只需改蓝图类,无需逐个修改场景实例,这就是面向对象的封装思想。
2.编写碰撞事件逻辑
+进入「事件图表」,选中左侧组件面板的StaticMeshComponent0,在右侧细节面板最下方,找到事件分类,点击「On Component Hit」,自动生成碰撞事件节点
原理说明:OnComponentHit是 UE 的碰撞回调事件,当该组件被其他物体碰撞时触发,对应 C++ 中绑定的碰撞回调函数,事件会自动返回碰撞的对象、碰撞位置等参数。
+右键搜索分支 节点,拖入图表中,对应 C++ 的if条件判断语句,用于过滤碰撞对象,避免被其他物体碰撞时误触发销毁。
+节点连线与逻辑设置:
--将「On Component Hit」节点的执行引脚,与「分支」节点的执行引脚相连
--将「On Component Hit」节点的其他物体 输出引脚,与「分支」节点的条件 引脚相连,右键搜索「等于」节点,设置判断条件:其他物体 的类 等于 BP_CubeTest
核心逻辑:只有碰撞我们的玩家立方体时,才会执行后续逻辑,对应 C++ 的if(碰撞对象类型 == 玩家类)条件判断,避免无效触发。
--右键搜索销毁 Actor节点,拖入图表中,将「分支」节点的「真」执行引脚,与该节点的执行引脚相连,目标保持Self(自身)
--衔接上一篇的动态材质知识:在销毁前,添加「设置向量参数值」节点,给障碍物材质设置随机颜色,实现碰撞瞬间的变色反馈
+点击编译→保存,回到主场景,将所有障碍物替换为BP_Obstacle蓝图实例
3.效果验证
点击播放,控制玩家立方体碰撞障碍物,障碍物会先变色,然后自动销毁,碰撞销毁效果完成!
对应 C++ 核心代码实现
cpp
// 障碍物类头文件
#pragma once
#include "GameFramework/Actor.h"
#include "BP_Obstacle.generated.h"
UCLASS()
class YOUR_PROJECT_API ABP_Obstacle : public AActor
{
GENERATED_BODY()
public:
ABP_Obstacle();
// 声明网格体组件,对应蓝图中的StaticMeshComponent
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* MeshComp;
// 声明碰撞回调函数,对应蓝图的OnComponentHit事件
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
protected:
virtual void BeginPlay() override;
};
// 障碍物类源文件
#include "BP_Obstacle.h"
#include "BP_CubeTest.h"
#include "Materials/MaterialInstanceDynamic.h"
ABP_Obstacle::ABP_Obstacle()
{
PrimaryActorTick.bCanEverTick = false;
// 创建网格体组件
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
RootComponent = MeshComp;
// 开启碰撞事件,对应蓝图勾选生成碰撞事件
MeshComp->SetGenerateOverlapEvents(true);
MeshComp->SetCollisionProfileName(TEXT("StaticObject"));
}
void ABP_Obstacle::BeginPlay()
{
Super::BeginPlay();
// 绑定碰撞回调函数,对应蓝图的事件绑定
MeshComp->OnComponentHit.AddDynamic(this, &ABP_Obstacle::OnHit);
}
// 碰撞回调函数实现,对应蓝图的碰撞逻辑
void ABP_Obstacle::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
// 条件判断:只有碰撞玩家立方体时执行,对应蓝图的分支节点
if(OtherActor && OtherActor->IsA<ABP_CubeTest>())
{
// 动态修改材质颜色,对应蓝图的设置向量参数值
UMaterialInstanceDynamic* DynamicMat = MeshComp->CreateAndSetMaterialInstanceDynamic(0);
if(DynamicMat)
{
DynamicMat->SetVectorParameterValue(TEXT("BaseColor"), FLinearColor::MakeRandomColor());
}
// 销毁自身,对应蓝图的销毁Actor节点
Destroy();
}
}
实操 3:触发区域机关,实现玩家进入区域自动开门
触发事件是 UE 场景交互的核心,几乎所有游戏的机关、剧情触发、交互提示都基于此。我们将实现:场景中创建一个门,玩家走进触发区域,门自动打开,走出区域门自动关闭。
1.创建门模型与基础设置
+主场景中,拖入 2 个立方体,调整大小拼成门框,再拖入 1 个立方体调整为门板大小,赋予不同材质,组合成完整的门
+选中门板,右键→转为蓝图类,命名为BP_Door,双击打开蓝图编辑器
2.添加触发盒组件
+蓝图编辑器左侧「组件」面板,点击「添加」→搜索「盒碰撞体」,命名为TriggerBox,对应 C++ 中创建一个碰撞体成员变量
+调整盒碰撞体的大小,使其覆盖门前方的区域(玩家走进这个区域就会触发事件)
+选中TriggerBox组件,右侧细节面板→碰撞分类:
--碰撞预设:选择「触发器」
--勾选模拟生成触发事件(触发事件生效的核心前提)
3.编写触发事件逻辑
+选中TriggerBox组件,右侧细节面板→事件分类,点击「On Component Begin Overlap」(组件开始重叠)和「On Component End Overlap」(组件结束重叠),自动生成两个触发事件节点
原理说明:BeginOverlap对应玩家走进触发区的回调,EndOverlap对应玩家走出触发区的回调,对应 C++ 中两个不同状态的回调函数。
+核心逻辑设计:
--玩家进入触发区→门板向上移动,实现开门效果
--玩家离开触发区→门板向下移动,回到初始位置,实现关门效果
+变量创建:在「我的蓝图」→变量中,创建 2 个变量:
--OpenOffset:浮点型,默认值300.0,对应门打开的高度,勾选「可编辑实例」
--MoveSpeed:浮点型,默认值200.0,对应门开关的速度,勾选「可编辑实例」
--InitLocation:向量型,默认值为空,不勾选可编辑,用于存储门的初始位置,对应 C++ 的私有成员变量
+逻辑编写:
--右键搜索事件 BeginPlay,拖入图表中,添加「获取 Actor 位置」节点,将返回值赋值给InitLocation变量,实现游戏启动时记录门的初始位置,对应 C++ 的初始化函数。
--「On Component Begin Overlap」节点:添加分支判断,仅当重叠对象是玩家BP_CubeTest时执行,添加时间轴节点(用于实现平滑的移动动画),时间轴输出门的位置,从初始位置过渡到InitLocation + OpenOffset的高度。
--「On Component End Overlap」节点:同样添加分支判断,玩家离开时,用时间轴控制门从打开位置回到初始位置。
+点击编译→保存,回到主场景,调整门与触发区的位置
4.效果验证
点击播放,控制玩家立方体走进触发区,门自动平滑打开;走出触发区,门自动关闭,触发机关效果完成!
实操 4:蓝图函数封装,告别 "面条蓝图"
前序我们的逻辑都写在事件图表中,一旦逻辑复杂,就会变成杂乱的 "面条蓝图",难以维护和复用。现在我们用 C++ 函数封装的思想,将重复逻辑封装成蓝图函数,实现模块化开发。
1.创建蓝图函数
打开BP_Obstacle蓝图,左侧「我的蓝图」→「函数」面板,点击 + 号,创建函数,命名为ObstacleHitHandler,对应 C++ 的类成员函数。
2.函数逻辑编写
双击进入函数编辑界面,将之前写在碰撞事件中的「材质变色 + 销毁 Actor」逻辑,全部剪切到函数中,对应 C++ 中将业务逻辑封装到成员函数中。
--可添加输入参数:比如添加「Color」向量型参数,可自定义碰撞后的变色,对应 C++ 函数的形参
--可添加返回值:比如添加「IsDestroyed」布尔型返回值,返回是否销毁成功,对应 C++ 函数的返回值
3.函数调用
回到事件图表,删除之前的杂乱节点,右键搜索我们创建的ObstacleHitHandler函数,拖入图表中,将「On Component Hit」事件的执行引脚,与函数的执行引脚相连,仅保留分支判断节点,事件图表瞬间变得清晰整洁。
4.复用扩展
后续如果要给障碍物添加碰撞音效、积分增加等逻辑,只需修改ObstacleHitHandler函数即可,无需修改事件图表,所有该蓝图类的实例都会同步更新,完美实现了 C++ 的封装与代码复用思想。
三、新手碰撞系统避坑指南(100% 踩坑率总结)
1.碰撞 / 触发事件完全不执行
优先检查 3 个核心设置:①两个物体都勾选了生成碰撞事件 / 模拟生成触发事件;②碰撞体的碰撞预设互相匹配,触发器必须选「触发器」预设;③静态网格体有有效的简单碰撞体,没有碰撞体永远无法触发事件。
2.物体直接穿模,无物理阻挡
检查碰撞预设的通道设置:两个物体的碰撞通道,必须一个是「阻挡」,一个是「被阻挡」,比如玩家 Pawn 预设对静态物体是阻挡,静态物体对 Pawn 也是阻挡,才会有物理阻挡效果。
3.触发事件频繁误触发
必须添加对象类型判断,对应 C++ 的 if 条件过滤,只处理你指定的对象(比如玩家),否则场景中任何物体进入触发区,都会触发事件,导致逻辑混乱。
4.蓝图函数调用无效果
检查函数的执行引脚是否正确连接,函数中的变量是否正确赋值,蓝图是否完成编译,对应 C++ 函数调用的参数传递与编译检查。
5.碰撞检测性能卡顿
新手不要用复杂碰撞,优先用简单碰撞体(盒、球、胶囊碰撞体),复杂网格体碰撞会极大增加物理引擎的计算量,对应 C++ 中用简单数据结构做边界检测,降低计算复杂度。
四、本篇总结
本篇我们完成了从单物体交互到多物体联动的跨越,核心收获有 4 点:
1.彻底吃透 UE 碰撞系统的核心逻辑,理解了碰撞事件与触发事件的区别与应用场景,用 C++ 知识打通了底层原理,告别了死记硬背操作。
2.实现了碰撞销毁、自动门触发机关 2 个核心场景交互,掌握了 UE 事件驱动开发的核心思想,能独立制作简单的场景机关。
3.学会了蓝图函数封装,掌握了模块化开发的核心方法,对应 C++ 面向对象的封装思想,彻底告别杂乱的 "面条蓝图"。
4.完成了前序知识点的串联,将动态材质、移动控制、碰撞系统结合起来,形成了完整的交互逻辑闭环。
下一篇预告:UE5 零基础入门第四弹:UMG UI 系统入门,制作交互提示、血量条、菜单界面,实现 UI 与游戏逻辑的联动,同时讲解 C++ 与 UMG 的通信方法。
