跨层传递:结构体、枚举与资产引用

暴露单个变量容易,跨层传递复杂数据才是细节所在。

结构体:USTRUCT(BlueprintType)

USTRUCT(BlueprintType)
struct FDamageInfo
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float Amount = 0.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FName DamageType;      // 物理/火焰/冰...

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    AActor* Instigator;    // 伤害来源
};

蓝图里就能把它当一个值传递(Break/Make 节点自动生成)。注意:结构体不要包含 TMap/TSet,蓝图不支持;结构体之间不要互相循环引用。

枚举:UENUM(BlueprintType)

UENUM(BlueprintType)
enum class EEnemyState : uint8
{
    Idle    UMETA(DisplayName = "待机"),
    Chase   UMETA(DisplayName = "追击"),
    Attack  UMETA(DisplayName = "攻击"),
    Dead    UMETA(DisplayName = "死亡")
};

UMETA(DisplayName) 给中文显示名——蓝图的 Combobox 里就是中文了。给策划看的东西,尽量有中文 DisplayName。

类引用与软引用

// 硬引用:加载此类时,引用的资产也被加载
UPROPERTY(EditDefaultsOnly, Category=" Combat")
TSubclassOf<AActor> ProjectileClass;      // "要生成哪种投射物"

// 软引用:按需加载(第 4 章详谈)
UPROPERTY(EditDefaultsOnly, Category="Combat")
TSoftClassPtr<AActor> BigBossClass;
引用类型 C++ 写法 加载时机 适用
硬引用 TSubclassOf<T> / UObject* 立即 常用资源
软引用 TSoftClassPtr / TSoftObjectPtr 手动 Load 大资源、低频资源

数据资产的公开

UCLASS(BlueprintType)   // 让 DataAsset 也能被蓝图直接读写
class USkillAsset : public UPrimaryDataAsset
{
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Skill")
    float Cooldown = 1.f;
    ...
};

蓝图里拖一个 SkillAsset 到节点,直接读 Cooldown。这是"策划改数值不动代码"闭环的最后一环。

一个反面教材

曾有个项目用 FString 装一切:"伤害类型"是个字符串,到处 FString::Format,一个月后没人记得该填 "Fire" 还是 "fire"。正确做法:能用枚举绝不用字符串—— EDamageType 在编辑器里是下拉框,填错从机制上就不可能。

本章小结

  • 结构体 / 枚举暴露前加 BlueprintType;枚举用 UMETA(DisplayName) 给中文名。
  • TMap/TSet 不暴露,改用结构体数组或按 Key 查询的函数。
  • 类引用 TSubclassOf、软引用 TSoftClassPtr 分清"立即加载/按需加载"。
  • DataAsset 加 BlueprintType,让蓝图直接读配置,闭环配置流。