UE5 零基础入门第三弹: 碰撞与触发交互,解锁场景机关与蓝图封装(高娱乐性学习)


观众老爷们大家好 我是邪修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 的通信方法。

相关推荐
今天你TLE了吗3 小时前
LLM到Agent&RAG——AI概念概述 第二章:提示词
人工智能·笔记·后端·学习
烤麻辣烫3 小时前
JS基础
开发语言·前端·javascript·学习
red_redemption3 小时前
自由学习记录(168)
学习·已经运行中世界-模与约束·闭环
2601_954971134 小时前
2026数学专业,靠什么技能能发挥数理优势转数据岗?
学习
xuanwenchao4 小时前
ROS2学习笔记 - 2、类的继承及使用
服务器·笔记·学习
ILYT NCTR5 小时前
爬虫学习案例3
爬虫·python·学习
不灭锦鲤5 小时前
网络安全学习第59天
学习·安全·web安全
楼田莉子6 小时前
同步/异步日志系统:日志落地模块\日志器模块\异步日志模块
linux·服务器·c++·学习·设计模式
旖-旎7 小时前
递归(汉诺塔问题)(1)
c++·学习·算法·leetcode·深度优先·递归