UE5中的原型设计模式

先贴链接:https://gpp.tkchu.me/prototype.html
轮到原型模式了,传统原型模式在现代游戏引擎中基本没用,但原型思想的应用还是较为广泛。

UE5中的"原型"实现

1. Class Default Object (CDO) - UE的核心原型系统

// UE的CDO就是原型模式的高级实现
class YOURGAME_API AMyActor : public AActor
{
    GENERATED_BODY()

public:
    AMyActor()
    {
        // CDO构造时设置的值成为"原型"
        PrimaryActorTick.bCanEverTick = true;
        Health = 100.0f;
        MaxHealth = 100.0f;
    }

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float Health;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float MaxHealth;
};

// 每个类只有一个CDO(原型对象)
AMyActor* CDO = AMyActor::StaticClass()->GetDefaultObject<AMyActor>();

// 所有实例都从CDO"克隆"初始值
AMyActor* NewInstance = GetWorld()->SpawnActor<AMyActor>();
// NewInstance的Health和MaxHealth都是从CDO复制的100.0f

关键:UE的每个UClass都有一个CDO,这就是原型,所有实例创建时都从CDO复制初始状态。

2. Blueprint类系统 - 可视化原型设计

// Blueprint类就是运行时原型系统
class UBlueprintGeneratedClass : public UClass
{
    // Blueprint编辑器中设置的所有默认值
    // 都存储在这个类的CDO中
    virtual void InitializeDefaultObject(UObject* DefaultObject) override
    {
        Super::InitializeDefaultObject(DefaultObject);
        
        // 从Blueprint数据初始化CDO(原型)
        for (const auto& PropertyValue : BlueprintDefaultValues)
        {
            PropertyValue.ApplyToObject(DefaultObject);
        }
    }
};

关键:Blueprint编辑器实际上就是一个可视化的原型设计工具

3. Data Table & Data Asset - 数据驱动的原型

// DataTable行就是数据原型
USTRUCT(BlueprintType)
struct FWeaponData : public FTableRowBase
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FString WeaponName;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float Damage;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float Range;
};

// 使用原型数据创建武器实例
class AWeapon : public AActor
{
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FDataTableRowHandle WeaponDataHandle;

public:
    void InitializeFromDataTable()
    {
        if (FWeaponData* Data = WeaponDataHandle.GetRow<FWeaponData>(""))
        {
            // 从原型数据"克隆"属性
            WeaponName = Data->WeaponName;
            Damage = Data->Damage;
            Range = Data->Range;
        }
    }
};

这就是文章中提到的JSON原型委托思想在UE中的实现

4. UE5的实际原型应用场景

Spawner系统的现代实现

// UE5中真正的Enemy Spawner实现
UCLASS(BlueprintType)
class YOURGAME_API UEnemySpawner : public UObject
{
    GENERATED_BODY()

public:
    // 使用SubClass而不是传统原型Clone
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSubclassOf<AEnemy> EnemyClassToSpawn;

    // 原型数据 - 可以覆盖CDO的默认值
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FEnemySpawnParameters SpawnParameters;

    AActor* SpawnEnemy(UWorld* World, const FVector& Location)
    {
        if (!EnemyClassToSpawn) return nullptr;

        // UE的"克隆"实际上是类实例化 + 参数覆盖
        AEnemy* Enemy = World->SpawnActor<AEnemy>(EnemyClassToSpawn, Location, FRotator::ZeroRotator);
        
        // 应用原型参数(覆盖CDO默认值)
        if (Enemy)
        {
            Enemy->SetHealth(SpawnParameters.Health);
            Enemy->SetSpeed(SpawnParameters.Speed);
            Enemy->SetAIBehavior(SpawnParameters.AIBehaviorClass);
        }
        
        return Enemy;
    }
};

为什么UE不用传统Clone模式?

  1. 性能考虑:UE的对象有复杂的组件层次和引用关系,深拷贝代价太高
  2. 内存管理:UE有垃圾回收系统,Clone会破坏对象生命周期管理
  3. 序列化复杂性:UE对象需要支持保存/加载,Clone会让序列化变得复杂

UE5中原型模式的应用

GameplayAbilitySystem中的原型思想

// Ability的Grant就是原型模式应用
class UGameplayAbility : public UObject
{
    // Ability类本身就是"原型"
    virtual UGameplayAbility* CreateAbilityInstance() const
    {
        // 没用简单的Clone,而是智能的实例化
        UGameplayAbility* Instance = NewObject<UGameplayAbilityClass>();
        Instance->SetAbilityLevel(this->AbilityLevel);
        Instance->SetCooldownDuration(this->CooldownDuration);
        return Instance;
    }
};

World Partition的原型加载

// UE5的World Partition也使用了原型思想
class UWorldPartitionStreamingSource
{
    // StreamingSource本身就是原型
    // 每个加载的Cell都是从原型派生的变体
    void LoadCell(const FWorldPartitionCellCoord& CellCoord)
    {
        // 从原型数据创建Cell实例
        UWorldPartitionCell* Cell = CreateCellFromPrototype(CellCoord);
        Cell->LoadActors(); // 加载Cell中的Actors(也是从原型实例化)
    }
};

何时在UE项目中应用原型思想

1. 数据配置系统

// 使用DataAsset作为配置原型
UCLASS(BlueprintType)
class UEnemyConfigAsset : public UDataAsset
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float BaseHealth;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSubclassOf<UEnemyAIComponent> AIComponentClass;

    // 这是原型的"克隆"方法
    UFUNCTION(BlueprintCallable)
    void ApplyToEnemy(AEnemy* Enemy) const
    {
        Enemy->SetMaxHealth(BaseHealth);
        Enemy->CreateAIComponent(AIComponentClass);
    }
};

2. 程序化生成系统

// 使用原型数据驱动程序化内容
USTRUCT(BlueprintType)
struct FBuildingPrototype
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TArray<FVector> WindowPositions;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSubclassOf<AActor> DoorClass;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UMaterialInterface* WallMaterial;
};

// 程序化建筑生成器
class UProceduralBuildingGenerator
{
    TArray<FBuildingPrototype> BuildingPrototypes;

public:
    AActor* GenerateBuilding(int32 PrototypeIndex, const FTransform& Transform)
    {
        const FBuildingPrototype& Prototype = BuildingPrototypes[PrototypeIndex];
        
        // 从原型"克隆"建筑
        ABuilding* Building = CreateBuilding(Transform);
        Building->ApplyPrototype(Prototype); // 应用原型数据
        
        return Building;
    }
};

核心:UE5中的原型模式已经演化成了数据驱动的实例化系统,而非传统的对象克隆。这种设计更符合现代游戏引擎的需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值