跳转至

蓝图笔记

通信方式 · 命名规范 · 踩坑记录。

游戏实例

游戏实例是整个游戏存活期间唯一的全局对象,关掉游戏才销毁。切关卡数据不丢。

项目中的实际用法

BP_ChemistryGameInstance 里设了两个变量:

变量 类型 说明
变换人物 布尔 当前选择的人物(第一人称 / 第三人称)
模式选择 枚举 教学模式 / 考试模式

主菜单选择 → 跨关卡传递

主菜单 setting_start.uasset 的按钮点击 → 设置游戏实例里的"模式选择" → 场景里的 WBP_TaskPanel2.uasset 读取游戏实例 → 根据值显示对应界面。

人物切换效果:主菜单选择模式时,悬浮在考试或教学模式上分别出现不同的人物预览,点击后锁定该模式的人物。切到实验场景时,游戏实例里存的人物被读出,加载对应人物。

// 主菜单按钮点击:写
获取游戏实例  转换为 BP_ChemistryGameInstance  设置 模式选择(枚举)/ 变换人物(布尔)

// 场景 UI 打开时:读
获取游戏实例  转换为 BP_ChemistryGameInstance  获取 模式选择 / 变换人物  决定界面和人物

游戏实例适合放"切关卡不能丢"但"关了游戏不需要保留"的数据。要永久保存用 SaveGame。

蓝图间的通信

参考 B 站视频,讲解了四种通信方式。

方式 1:变量直接引用

在这个蓝图里创建一个变量,类型选你要找的那个蓝图,然后去关卡里指给它"是哪一个"。

步骤:

  1. 蓝图一里新建变量 → 类型选蓝图二(对象引用)
  2. 编译 → 勾选变量的可编辑实例生成时公开
  3. 回到关卡 → 选中蓝图一 → 右侧细节面板就能看到这个变量 → 用滴管吸蓝图二
  4. 蓝图一里拖出这个变量 → 直接调蓝图二的函数或事件

不想勾那两个选项? 把变量类型从"对象引用"改成软对象引用,就可以直接在蓝图默认值里选,不需要去关卡里指。

或者不建变量,直接获取——本项目最常用:

// 场景里只有一个蓝图二时
获取类的Actor(蓝图二)  调它的函数

// 场景里有多个蓝图二,想指定某一个 → 先给它打标签
// 选中蓝图二 → 细节面板 → 标签 → 添加 "实验器材"
通过标签获取Actor("实验器材")  调它的函数

获取类的Actor 是项目里用得最多的通信方式。不用预先建变量,不用去关卡里指认,写哪算哪,最灵活。


方式 2:事件分发器

适合"一件事发生了,通知其他人"。一对多——一个人发广播,多个人收听。

步骤:

  1. 蓝图一(发广播的)→ 左侧面板 → 事件分发器 → 新建一个,起名
  2. 拖这个分发器到图表 → 选调用(就是广播出去)
  3. 蓝图二(收听方)→ 开始运行时先获取蓝图一的引用 → 绑定事件到分发器 → 连到自己的自定义事件
// 蓝图一:发送
事件分发器 OnTaskCompleted  调用    // 广播:任务完成了

// 蓝图二:接收
开始运行:
    获取类的Actor(蓝图一)
     绑定事件到 OnTaskCompleted
     触发时  刷新 UI

方式 3:蓝图接口

先建一个蓝图接口资产,里面定义函数名。谁实现了这个接口,谁就必须写这个函数的具体内容。

创建步骤:

  1. 内容浏览器右键 → 蓝图 → 蓝图接口,起名
  2. 双击打开 → 默认有一个函数 → 改个名
  3. 目标蓝图 → 类设置 → 已实现接口 → 添加刚建的接口
  4. 目标蓝图里会出现接口事件 → 双击实现 → 写具体逻辑

调用方式有两种:


调用方式一:遍历所有实现了接口的 Actor

连接:https://www.bilibili.com/video/BV14hJ9z8EvQ/?spm_id_from=333.1387.favlist.content.click&vd_source=b8f35d6b8b01aaa29ccd685ef5fd7b18
适合"找到场景里所有能交互的东西,挨个通知"。

获取所有带有接口的Actor(你的接口)
 循环遍历  调用(接口函数)

调用方式二:直接对某个 Actor 调接口事件

连接:https://www.bilibili.com/video/BV1YVMizfEP5/?spm_id_from=333.1387.favlist.content.click&vd_source=b8f35d6b8b01aaa29ccd685ef5fd7b18
你已经拿到了一个具体的 Actor,不管它是什么类型,直接让它干活。不用写一堆类型转换。

例子:角色按 E 键,跟面前的物体交互。场景里有门(开门)、吊灯(开关灯)、墙(升降)。

第 1 步:建接口

内容浏览器右键 → 蓝图 → 蓝图接口,起名 BPI_Interact。双击打开,里面默认已经有一个函数,改名为 InteractWithPlayer。这里什么都不用写,只声明。

第 2 步:每个物体实现接口

打开门蓝图 → 顶部菜单 类设置已实现接口 → 点添加 → 选 BPI_Interact

添加后,左侧 我的蓝图 面板里会出现一个 接口 分类,下面有 InteractWithPlayer。右键它 → 实现事件 → 图表里会出现一个事件节点 → 连到开门逻辑。

吊灯、墙同样操作——各自添加接口、各自实现事件、各自连到自己逻辑。

第 3 步:调用

回到玩家蓝图,检测到物体后直接拉线出接口事件:

输入操作 E 键:
    球形重叠检测(起点: 获取Actor位置, 半径: 500)
     数组元素(0)
     InteractWithPlayer(搜消息,选择对应函数)

搜节点时输入 InteractWithPlayer,选带信封图标的那个。

节点对照:球形重叠检测 = Sphere Overlap Actors,数组元素(0) = 取数组第一个。

效果:按 E 键 → 检测到门就开门,检测到灯就开关灯,检测到墙就升降。对方没实现接口的话什么都不发生,不报错。

以后加任何新物体(窗户、抽屉),只需做第 2 步,玩家代码不用改。

不用接口的话,每种物体都得写一段"转换为某蓝图",性能差,而且每加一种就要回来改代码。


什么时候用哪个

情况 用哪个
我明确知道要找谁,一对一 变量引用
一件事发生了,要通知好几个地方 事件分发器
不同类型的东西,要做同一件事 蓝图接口

Widget 创建规范

控件的创建没有硬性规定必须放 HUD 蓝图里。常见做法是哪个蓝图需要就自己创建:

// 任意蓝图里都能创建 Widget
创建控件(类: WBP_任务面板)  添加到视口

实际项目中,UI 面板通常在玩家控制器或具体的界面管理蓝图里统一创建,不用 HUD。


数据持久化:SaveGame

凡是关了游戏还想保留的数据,都用 SaveGame。 音量、分数、段位、通关进度,套路都一样。

三个节点分工

创建saveGame对象  →  给数据赋值  →  保存游戏到插槽    ← 存
加载游戏从插槽   →  取数据                        ← 取

怎么用

第 1 步:建 SaveGame 蓝图

内容浏览器右键 → 蓝图 → SaveGame,起名,打开后加变量(比如 ScoreMasterVolume)。

第 2 步:存数据

// 数据改变时
创建saveGame对象(类: SG_Settings)
   设置 MasterVolume = 当前音量
   保存游戏到插槽("Settings")

第 3 步:取数据

// 游戏启动 / Widget 打开时
加载游戏从插槽("Settings")
   转换为 SG_Settings
   获取 MasterVolume
   应用到音量

和游戏实例的区别

游戏实例 SaveGame
切关卡 还在 还在
关游戏重开 ❌ 没了 ✅ 还在
适合放什么 当前临时数据 永久设置、存档

音量设置关了游戏下次打开还在 → 用 SaveGame,不用游戏实例。


命名规范

前缀 类型 示例
BP_ 蓝图 Actor BP_TaskManager1
WBP_ 控件蓝图 WBP_gameover
MI_ 材质实例 MI_Unlit_Opaque
E_ 枚举 E_PlayMode
S_ 结构体 S_ExperimentRecord
LS_ 关卡序列 LS_YYF