UFUNCTION:把函数交给蓝图
函数暴露比变量更常用,也更容易出错。先看最典型的几种形态:
public:
// 纯蓝图可调用
UFUNCTION(BlueprintCallable, Category="Combat")
void TakeDamage(float Amount);
// 蓝图可调用 + 编辑器里也能调用(做测试按钮)
UFUNCTION(BlueprintCallable, CallInEditor, Category="Combat")
void ResetHealth();
// 纯函数:蓝图里适用,无副作用
UFUNCTION(BlueprintPure, Category="Combat")
bool IsAlive() const;
// 蓝图可实现:C++ 只声明,蓝图来连(下页详讲)
UFUNCTION(BlueprintImplementableEvent, Category="Combat")
void OnDeath();
// 蓝图可重载:C++ 有默认实现,蓝图可覆盖
UFUNCTION(BlueprintNativeEvent, Category="Combat")
void OnHit(AActor* Damager);
BlueprintCallable vs BlueprintPure
两者的区别不是"有没有返回值",而是有没有副作用:
| BlueprintCallable | BlueprintPure | |
|---|---|---|
| 白色/纯函数节点外观 | 有执行引脚 | 无执行引脚 |
| 适合 | 修改状态、播特效、发 RPC | 取值、查询、计算 |
| 蓝图里 | 必须连执行线 | 随时可取 |
经验:查询函数尽量做 Pure。IsAlive()、GetHealth() 这类做成 Pure 后,策划连线时少拖一根执行线,图表干净很多。
参数与返回值的可暴露性
不是所有 C++ 类型都能暴露给蓝图。可暴露的:
- 基本类型(
int32/float/bool/FString/FName/FText) UObject*及其派生USTRUCT结构体(须是USTRUCT(BlueprintType))UENUM(BlueprintType)枚举TArray<T>(元素可暴露时)TSubclassOf<T>(类引用,蓝图里选类)
不可暴露的(常见踩坑):
TMap、TSet(蓝图不支持,须用TArray包装或自定义结构体)- 指针的指针、原始 C++ 类(非 UObject)
float&输出参数蓝图也不支持(用返回值或结构体)
想暴露
TMap?常见做法是定义USTRUCT里放TArray<KeyStruct>,或者干脆提供GetByKey(FName Key)函数。
蓝图函数库 vs 组件函数
把函数写在哪里,决定了蓝图的调用方式:
| 写法 | 调用形态 | 适合 |
|---|---|---|
| Actor/Component 成员函数 | 从"Self/目标"引脚调用 | 与对象状态相关 |
UBlueprintFunctionLibrary |
全局静态节点 | 工具函数(数学、辅助) |
静态 UFUNCTION |
右键直接搜 | 引擎工具类 |
蓝图函数库是收纳"公共函数"的好地方——第 1 章反模式一"复制粘贴"的修复方案就是它。注意函数库函数必须是 static。
一条实战经验:暴露最小集
新手容易把一个类的 40 个函数全标 BlueprintCallable。结果蓝图的右键菜单像装满杂物的抽屉。原则:只暴露玩法层会用到的函数,查询用 BlueprintPure,调试用 CallInEditor。
CallInEditor是被低估的说明符。给关键调试函数加上它,就能在 Details 面板里出现"调用"按钮,策划测试时不用进蓝图。
本章小结
BlueprintCallable(可调用)、BlueprintPure(无副作用查询)、CallInEditor(测试按钮)是最常用三件套。- 类型可暴露性有边界:
TMap/TSet不行,结构体/枚举需BlueprintType。 - 公共函数收进
UBlueprintFunctionLibrary;与对象相关的做成组件成员函数。 - 暴露最小集:蓝图右键菜单的整洁度是接口设计的一部分。
