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;与对象相关的做成组件成员函数。
  • 暴露最小集:蓝图右键菜单的整洁度是接口设计的一部分。