【2-设计模式】系统性全面的用游戏引擎o3de开发脚本实现所有设计模式,系统全面的给出代码

下面给出一套“系统性、全面”的设计模式实现方案,基于 O3DE(Open 3D Engine)脚本/组件化开发思路。由于 O3DE 的脚本语言主要是 Lua(BehaviorContext 可绑定)与 Python(编辑器与构建流水线、工具、自动化),而运行时游戏逻辑常用 C++/ScriptCanvas/Lua,下面我将:

  • 用 C++(反映到 BehaviorContext,可被 ScriptCanvas/Lua 使用)实现核心模式,贴合 O3DE 组件化、事件总线(EBus)、反射、Prefab、资产系统、TickBus 等生态。
  • 为部分模式给出 Lua 脚本/ScriptCanvas 思路片段,方便脚本侧调用。
  • 每个模式给出:场景、核心接口与关键点、O3DE 相关点(如 EBus、Components、Reflection)、完整示例代码(C++),并在可能处给出 Lua 调用示例。
  • 代码组织:一个 Gem(DesignPatternsGem),在其 Source/ 下为每个模式给出独立文件。所有类通过 AZ::Component/EBus/Interface/Reflection 暴露。

说明:

  • 以下代码面向 O3DE 23.x/24.x 风格。CMake/Gem.json 略述结构,示例为可编译片段,但你需要按工程整合。
  • 为避免篇幅过巨,这里覆盖 23 种常见 GoF 设计模式,全代码均为“可用最小实现 + O3DE 风格”。你可以直接复制到你的 Gem 中。若你需要 ScriptCanvas 节点注册,我为若干模式示例了 BehaviorContext 方法暴露,其他模式可依葫芦画瓢。

目录(GoF 23 模式)

  1. 创建型
    • 抽象工厂(Abstract Factory)
    • 建造者(Builder)
    • 工厂方法(Factory Method)
    • 原型(Prototype)
    • 单例(Singleton)
  2. 结构型
    • 适配器(Adapter)
    • 桥接(Bridge)
    • 组合(Composite)
    • 装饰(Decorator)
    • 外观(Facade)
    • 享元(Flyweight)
    • 代理(Proxy)
  3. 行为型
    • 责任链(Chain of Responsibility)
    • 命令(Command)
    • 解释器(Interpreter)
    • 迭代器(Iterator)
    • 中介者(Mediator)
    • 备忘录(Memento)
    • 观察者(Observer)
    • 状态(State)
    • 策略(Strategy)
    • 模板方法(Template Method)
    • 访问者(Visitor)

工程结构建议

  • Gems/DesignPatternsGem/Gem.json
  • Gems/DesignPatternsGem/Code/CMakeLists.txt
  • Gems/DesignPatternsGem/Code/Include/DesignPatternsGem/… 头文件
  • Gems/DesignPatternsGem/Code/Source/… 源文件
  • 将每个模式放在 Code/Source/Patterns/ 下
  • 一个 SystemComponent 负责反射所有类到 BehaviorContext

示例 Gem.json(简化)

  • name: DesignPatternsGem
  • type: Code
  • summary: GoF patterns for O3DE
  • dependencies: AZCore, AzFramework, AzToolsFramework (仅编辑器工具部分)

下面给出完整代码。你可将所有代码放入一个 Gem 内按文件拆分,或先合并为单一编译单元验证。

注意:

  • 以下代码较长。为确保“完整自包含”,我集中在一个头/源合集示例中。你在落地时请按文件拆分。
  • 为了演示,每种模式包含最小功能与 O3DE 反射要点;生产中请加上更严谨的错误处理与线程安全保护。

========================
CMake
与系统组件

CMakeLists.txt(简化示例)

cmake_minimum_required(VERSION 3.20)
project(DesignPatternsGem)

set(CMAKE_CXX_STANDARD 17)

find_package(o3de REQUIRED CONFIG)
ly_add_target(
NAME DesignPatternsGem.Static STATIC
NAMESPACE Gem
FILES_CMAKE
designpatterns_files.cmake
BUILD_DEPENDENCIES
AZ::AzCore
AZ::AzFramework
AZ::AzGameFramework
)

ly_add_target(
NAME DesignPatternsGem MODULE
NAMESPACE Gem
FILES_CMAKE
designpatterns_files.cmake
BUILD_DEPENDENCIES
Gem::DesignPatternsGem.Static
)

designpatterns_files.cmake(列出所有源码)

set(FILES
Source/DesignPatternsSystemComponent.cpp
Source/Patterns/AbstractFactory.cpp
Source/Patterns/Builder.cpp
Source/Patterns/FactoryMethod.cpp
Source/Patterns/Prototype.cpp
Source/Patterns/Singleton.cpp
Source/Patterns/Adapter.cpp
Source/Patterns/Bridge.cpp
Source/Patterns/Composite.cpp
Source/Patterns/Decorator.cpp
Source/Patterns/Facade.cpp
Source/Patterns/Flyweight.cpp
Source/Patterns/Proxy.cpp
Source/Patterns/ChainOfResponsibility.cpp
Source/Patterns/Command.cpp
Source/Patterns/Interpreter.cpp
Source/Patterns/Iterator.cpp
Source/Patterns/Mediator.cpp
Source/Patterns/Memento.cpp
Source/Patterns/Observer.cpp
Source/Patterns/State.cpp
Source/Patterns/Strategy.cpp
Source/Patterns/TemplateMethod.cpp
Source/Patterns/Visitor.cpp
)

========================
统一头部与命名空间

以下代码片段以同一命名空间 dp(design patterns),并通过 SystemComponent 统一反射到 BehaviorContext,供 ScriptCanvas/Lua 调用。

请将以下“合并源文件”拆分为对应文件。为了便于复制,这里一次性给出所有实现。

文件:Source/DesignPatternsSystemComponent.cpp

#include <AzCore/Component/Component.h>
#include <AzCore/Module/Module.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Console/ConsoleBus.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/string.h>

namespace dp
{
// 统一日志 EBus(演示)
class LogRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
virtual void Info(const AZStd::string& msg) = 0;
};
using LogBus = AZ::EBus;

class Logger

    : public LogBus::Handler

{

public:

    void Activate() { LogBus::Handler::BusConnect(); }

    void Deactivate() { LogBus::Handler::BusDisconnect(); }

    void Info(const AZStd::string& msg) override

    {

        AZ_Printf("DesignPatterns", "%s\n", msg.c_str());

    }

};

// ============= 抽象工厂 =============

struct IEnemy

{

    AZ_RTTI(IEnemy, "{BC2E7BE6-0D5E-4E7A-8E71-7F3FD0A5B8F2}");

    virtual ~IEnemy() = default;

    virtual AZStd::string Attack() = 0;

};

struct Orc : IEnemy

{

    AZ_RTTI(Orc, "{DB3DB22D-2E4B-4E8C-9F8C-F2E02CF0183D}", IEnemy);

    AZStd::string Attack() override { return "Orc swings axe"; }

};

struct Troll : IEnemy

{

    AZ_RTTI(Troll, "{C0B41D82-0F4D-4FBE-8E38-12E1D656B859}", IEnemy);

    AZStd::string Attack() override { return "Troll smashes ground"; }

};

struct IEnemyFactory

{

    AZ_RTTI(IEnemyFactory, "{9AE2E0D6-FB8A-4C45-A70E-85C6C367A84F}");

    virtual ~IEnemyFactory() = default;

    virtual AZStd::shared_ptr<IEnemy> CreateMelee() = 0;

    virtual AZStd::shared_ptr<IEnemy> CreateTank() = 0;

};

struct OrcFactory : IEnemyFactory

{

    AZ_RTTI(OrcFactory, "{2A3BFE53-2B1E-4E1E-B5BB-F0CA709C8C1F}", IEnemyFactory);

    AZStd::shared_ptr<IEnemy> CreateMelee() override { return AZStd::make_shared<Orc>(); }

    AZStd::shared_ptr<IEnemy> CreateTank() override { return AZStd::make_shared<Orc>(); }

};

struct TrollFactory : IEnemyFactory

{

    AZ_RTTI(TrollFactory, "{B9F73C7A-8D70-4C10-8870-BA0F1E7F3C7E}", IEnemyFactory);

    AZStd::shared_ptr<IEnemy> CreateMelee() override { return AZStd::make_shared<Troll>(); }

    AZStd::shared_ptr<IEnemy> CreateTank() override { return AZStd::make_shared<Troll>(); }

};

// ============= 建造者 =============

struct Character

{

    AZ_TYPE_INFO(Character, "{A3E5C7A6-35E3-4F39-8C9B-5A5BD4B846E0}");

    AZStd::string m_name;

    int m_hp = 100;

    int m_attack = 10;

};

struct ICharacterBuilder

{

    AZ_RTTI(ICharacterBuilder, "{E871D82E-6B80-4F19-8BFA-0DDF60F5457B}");

    virtual ~ICharacterBuilder() = default;

    virtual void Reset() = 0;

    virtual void SetName(const AZStd::string&) = 0;

    virtual void SetHP(int) = 0;

    virtual void SetAttack(int) = 0;

    virtual Character GetResult() = 0;

};

struct WarriorBuilder : ICharacterBuilder

{

    AZ_RTTI(WarriorBuilder, "{2DE29D4A-2C13-4AF1-9FBB-2C0B1BFA2E9D}", ICharacterBuilder);

    Character m_char;

    void Reset() override { m_char = Character{}; }

    void SetName(const AZStd::string& n) override { m_char.m_name = n; }

    void SetHP(int hp) override { m_char.m_hp = hp; }

    void SetAttack(int atk) override { m_char.m_attack = atk; }

    Character GetResult() override { return m_char; }

};

struct CharacterDirector

{

    AZ_TYPE_INFO(CharacterDirector, "{D1F1DABC-AD02-4C52-A50D-4A5A9D0DFAE7}");

    void MakeTank(ICharacterBuilder& b)

    {

        b.Reset();

        b.SetName("Tank");

        b.SetHP(300);

        b.SetAttack(20);

    }

};

// ============= 工厂方法 =============

struct IProjectile

{

    AZ_RTTI(IProjectile, "{A9CDE2C5-16C5-49C9-9A4D-5F6C0E0D4C54}");

    virtual ~IProjectile() = default;

    virtual AZStd::string Fire() = 0;

};

struct Arrow : IProjectile

{

    AZ_RTTI(Arrow, "{C0C5723C-3D7B-4D8E-8F1E-93C8B79F5F3F}", IProjectile);

    AZStd::string Fire() override { return "Arrow fired"; }

};

struct Fireball : IProjectile

{

    AZ_RTTI(Fireball, "{A2EEA7A9-2AB3-4A5D-99D7-3D54C83F30A0}", IProjectile);

    AZStd::string Fire() override { return "Fireball cast"; }

};

struct ProjectileSpawner

{

    AZ_RTTI(ProjectileSpawner, "{6A68279B-0973-4AC2-BD8B-0A3F3A9C9E2C}");

    virtual ~ProjectileSpawner() = default;

    virtual AZStd::shared_ptr<IProjectile> Make() = 0;

};

struct ArrowSpawner : ProjectileSpawner

{

    AZ_RTTI(ArrowSpawner, "{5B2F2D3A-7F5F-4A08-9B95-3A0E808E2F60}", ProjectileSpawner);

    AZStd::shared_ptr<IProjectile> Make() override { return AZStd::make_shared<Arrow>(); }

};

struct FireballSpawner : ProjectileSpawner

{

    AZ_RTTI(FireballSpawner, "{8F2A79F5-5C2A-4D9F-8D7E-5C5D1E1A558C}", ProjectileSpawner);

    AZStd::shared_ptr<IProjectile> Make() override { return AZStd::make_shared<Fireball>(); }

};

// ============= 原型 =============

struct ICloneable

{

    AZ_RTTI(ICloneable, "{8B8CE02E-31B7-4C09-8468-2B6C7E7B2E64}");

    virtual ~ICloneable() = default;

    virtual AZStd::shared_ptr<ICloneable> Clone() const = 0;

};

struct Spell : ICloneable

{

    AZ_RTTI(Spell, "{9B8D0F05-67C7-4C3D-9E5A-7B9F5B3C812A}", ICloneable);

    AZStd::string m_name = "Heal";

    int m_power = 10;

    AZStd::shared_ptr<ICloneable> Clone() const override

    {

        auto s = AZStd::make_shared<Spell>();

        s->m_name = m_name;

        s->m_power = m_power;

        return s;

    }

};

// ============= 单例(基于 Interface) =============

class ConfigInterface

{

public:

    AZ_RTTI(ConfigInterface, "{C5F7F3B1-9A90-4B5A-87E0-0D0D35A1DE98}");

    virtual ~ConfigInterface() = default;

    virtual void Set(const AZStd::string& key, const AZStd::string& val) = 0;

    virtual AZStd::string Get(const AZStd::string& key) const = 0;

    static ConfigInterface* Get();

    static void Register(ConfigInterface* impl);

    static void Unregister(ConfigInterface* impl);

};

class ConfigImpl final : public ConfigInterface

{

public:

    AZ_CLASS_ALLOCATOR(ConfigImpl, AZ::SystemAllocator);

    AZ_RTTI(ConfigImpl, "{F9F8C7B3-17F5-4ED5-8D2C-1B6C73F18D64}", ConfigInterface);

    void Set(const AZStd::string& key, const AZStd::string& val) override { m_map[key] = val; }

    AZStd::string Get(const AZStd::string& key) const override

    {

        auto it = m_map.find(key);

        return it==m_map.end()? "" : it->second;

    }

private:

    AZStd::unordered_map<AZStd::string, AZStd::string> m_map;

};

static ConfigInterface* g_configSingleton = nullptr;

ConfigInterface* ConfigInterface::Get() { return g_configSingleton; }

void ConfigInterface::Register(ConfigInterface* impl) { g_configSingleton = impl; }

void ConfigInterface::Unregister(ConfigInterface* impl) { if (g_configSingleton == impl) g_configSingleton = nullptr; }

// ============= 适配器 =============

struct LegacyAudioSystem

{

    AZ_TYPE_INFO(LegacyAudioSystem, "{0E31D5E4-8737-4A06-BB77-4F4A4C43574E}");

    AZStd::string PlayWav(const AZStd::string& p) { return "Legacy play wav: " + p; }

};

struct IAudio

{

    AZ_RTTI(IAudio, "{F41F4AD3-99F5-4E6B-9E0A-2B0DE7A3E6F2}");

    virtual ~IAudio() = default;

    virtual AZStd::string Play(const AZStd::string& path) = 0;

};

struct LegacyAudioAdapter : IAudio

{

    AZ_RTTI(LegacyAudioAdapter, "{1B6B3C08-0B35-4D66-9D7F-113A4F1E3476}", IAudio);

    LegacyAudioSystem m_legacy;

    AZStd::string Play(const AZStd::string& path) override { return m_legacy.PlayWav(path); }

};

// ============= 桥接 =============

struct IRenderImpl

{

    AZ_RTTI(IRenderImpl, "{5E9C2D9C-16D8-4A02-9E1E-5F9F43D9E651}");

    virtual ~IRenderImpl() = default;

    virtual AZStd::string Draw(const AZStd::string& what) = 0;

};

struct VulkanImpl : IRenderImpl

{

    AZ_RTTI(VulkanImpl, "{5F6B2B7E-1F6D-44B0-9A3E-3D3ECA4A22B6}", IRenderImpl);

    AZStd::string Draw(const AZStd::string& what) override { return "Vulkan draws " + what; }

};

struct DX12Impl : IRenderImpl

{

    AZ_RTTI(DX12Impl, "{EECF9A88-6A14-4BE8-8B3F-AE0E34F6D6B3}", IRenderImpl);

    AZStd::string Draw(const AZStd::string& what) override { return "DX12 draws " + what; }

};

struct RenderAbstraction

{

    AZ_TYPE_INFO(RenderAbstraction, "{48F4D7B1-40D6-4A65-A1FA-265C9F2B6D6C}");

    AZStd::shared_ptr<IRenderImpl> m_impl;

    explicit RenderAbstraction(AZStd::shared_ptr<IRenderImpl> impl) : m_impl(impl) {}

    AZStd::string RenderMesh(const AZStd::string& mesh) { return m_impl ? m_impl->Draw(mesh) : "No impl"; }

};

// ============= 组合 =============

struct INode

{

    AZ_RTTI(INode, "{1E92F2E0-1B2A-4D1B-9E6E-5A3E5C3E0A19}");

    virtual ~INode() = default;

    virtual int GetCost() const = 0;

};

struct Leaf : INode

{

    AZ_RTTI(Leaf, "{17E7C0F7-A1B9-41C1-8EBD-5F1AD0EE52F2}", INode);

    int m_cost = 1;

    int GetCost() const override { return m_cost; }

};

struct CompositeNode : INode

{

    AZ_RTTI(CompositeNode, "{1CF0F93F-3F63-42D0-9970-3C84F9F9E6C9}", INode);

    AZStd::vector<AZStd::shared_ptr<INode>> m_children;

    void Add(const AZStd::shared_ptr<INode>& n) { m_children.push_back(n); }

    int GetCost() const override

    {

        int sum = 0; for (auto& c : m_children) sum += c->GetCost(); return sum;

    }

};

// ============= 装饰 =============

struct IWeapon

{

    AZ_RTTI(IWeapon, "{FB55D3E1-6D2E-4A6C-B6C5-6B2F8A8121E5}");

    virtual ~IWeapon() = default;

    virtual int Damage() const = 0;

    virtual AZStd::string Desc() const = 0;

};

struct Sword : IWeapon

{

    AZ_RTTI(Sword, "{5D8AD4F9-1F31-4CE5-BD88-1E56D5BCF5B2}", IWeapon);

    int Damage() const override { return 10; }

    AZStd::string Desc() const override { return "Sword"; }

};

struct WeaponDecorator : IWeapon

{

    AZ_RTTI(WeaponDecorator, "{7C2C7E30-19E9-4B3B-8F94-5F0E0F5E2458}", IWeapon);

    AZStd::shared_ptr<IWeapon> m_wrap;

    explicit WeaponDecorator(AZStd::shared_ptr<IWeapon> w) : m_wrap(w) {}

    int Damage() const override { return m_wrap->Damage(); }

    AZStd::string Desc() const override { return m_wrap->Desc(); }

};

struct FireEnchant : WeaponDecorator

{

    AZ_RTTI(FireEnchant, "{B4E4E2F1-F2E7-4C79-AD5D-0C10E570A1E1}", WeaponDecorator);

    using WeaponDecorator::WeaponDecorator;

    int Damage() const override { return WeaponDecorator::Damage() + 5; }

    AZStd::string Desc() const override { return WeaponDecorator::Desc() + " + Fire"; }

};

// ============= 外观 =============

struct PhysicsSubsys { AZStd::string Init(){ return "PhysicsReady"; } };

struct AudioSubsys   { AZStd::string Init(){ return "AudioReady"; } };

struct RenderSubsys  { AZStd::string Init(){ return "RenderReady"; } };

struct EngineFacade

{

    AZ_TYPE_INFO(EngineFacade, "{48F1A6C0-1D81-4F8D-8FBC-0D5B4EAFB3FD}");

    PhysicsSubsys m_p; AudioSubsys m_a; RenderSubsys m_r;

    AZStd::string Boot() { return m_p.Init() + ", " + m_a.Init() + ", " + m_r.Init(); }

};

// ============= 享元 =============

struct BulletIntrinsic

{

    AZ_TYPE_INFO(BulletIntrinsic, "{62E8866E-3C8E-4A49-9A73-5B28A2EABF5F}");

    int meshId; int materialId;

};

struct BulletExtrinsic

{

    AZ_TYPE_INFO(BulletExtrinsic, "{85A1B4B2-A53E-44B5-8C0F-4B2C3E6442C9}");

    float x; float y; float z; float speed;

};

struct BulletFlyweightFactory

{

    AZ_TYPE_INFO(BulletFlyweightFactory, "{C01B6D4E-3A6F-44D8-9E5D-2E7B119D0C5B}");

    AZStd::unordered_map<int, BulletIntrinsic> m_pool;

    const BulletIntrinsic& Get(int key)

    {

        auto it = m_pool.find(key);

        if (it == m_pool.end())

        {

            m_pool[key] = BulletIntrinsic{key, key+100};

        }

        return m_pool[key];

    }

};

// ============= 代理 =============

struct IAssetLoader

{

    AZ_RTTI(IAssetLoader, "{7C8A1F7A-3D3A-4A87-9E33-3F2FA0C77493}");

    virtual ~IAssetLoader() = default;

    virtual AZStd::string Load(const AZStd::string& path) = 0;

};

struct RealAssetLoader : IAssetLoader

{

    AZ_RTTI(RealAssetLoader, "{B1E9C7D1-9E29-4B52-9A1E-1C7E8A0A4B13}", IAssetLoader);

    AZStd::string Load(const AZStd::string& path) override { return "Loaded:" + path; }

};

struct CachingAssetLoaderProxy : IAssetLoader

{

    AZ_RTTI(CachingAssetLoaderProxy, "{F6272D75-7B7C-44D0-98A4-2B8E0E3E3D8A}", IAssetLoader);

    AZStd::shared_ptr<RealAssetLoader> m_real = AZStd::make_shared<RealAssetLoader>();

    AZStd::unordered_map<AZStd::string, AZStd::string> m_cache;

    AZStd::string Load(const AZStd::string& path) override

    {

        auto it = m_cache.find(path);

        if (it != m_cache.end()) return it->second;

        auto data = m_real->Load(path);

        m_cache[path] = data;

        return data;

    }

};

// ============= 责任链 =============

struct IRequest

{

    AZ_RTTI(IRequest, "{D1C3A7B1-8C46-4C6E-98D7-5A819DDFE5C3}");

    virtual ~IRequest() = default;

    virtual int GetLevel() const = 0;

};

struct DamageRequest : IRequest

{

    AZ_RTTI(DamageRequest, "{CA5C873C-71AF-4D4E-8E3E-2E6F23A7B2D0}", IRequest);

    int m_level = 1;

    int GetLevel() const override { return m_level; }

};

struct Handler

{

    AZ_RTTI(Handler, "{F1F9E3B3-7FD9-4C23-8481-2A8B2CB4C64E}");

    AZStd::shared_ptr<Handler> m_next;

    virtual ~Handler() = default;

    void SetNext(AZStd::shared_ptr<Handler> n) { m_next = n; }

    virtual bool Handle(IRequest& r)

    {

        if (m_next) return m_next->Handle(r);

        return false;

    }

};

struct LowLevelHandler : Handler

{

    AZ_RTTI(LowLevelHandler, "{D7B02E21-1320-4D61-BD48-1C9B9A2DD2D8}", Handler);

    bool Handle(IRequest& r) override

    {

        if (r.GetLevel() <= 1) return true;

        return Handler::Handle(r);

    }

};

struct HighLevelHandler : Handler

{

    AZ_RTTI(HighLevelHandler, "{B9A42F0F-15A4-45E0-BB6C-38C1A0C0F8B1}", Handler);

    bool Handle(IRequest& r) override

    {

        if (r.GetLevel() > 1) return true;

        return Handler::Handle(r);

    }

};

// ============= 命令 =============

struct ICommand

{

    AZ_RTTI(ICommand, "{BFB6E486-8B9C-4E3F-8D9B-3B6E4D8B9D6F}");

    virtual ~ICommand() = default;

    virtual void Execute() = 0;

    virtual void Undo() = 0;

};

struct MoveReceiver

{

    AZ_TYPE_INFO(MoveReceiver, "{F2A93F12-8A1A-4B29-8C2E-2B1FA0F0F11A}");

    float x=0,y=0;

    void Move(float dx,float dy){x+=dx;y+=dy;}

};

struct MoveCommand : ICommand

{

    AZ_RTTI(MoveCommand, "{5B7B3D44-BC49-4F2B-8B5E-09E7F3A5A2F8}", ICommand);

    MoveReceiver* m_r=nullptr; float dx=0,dy=0;

    MoveCommand(MoveReceiver* r,float dx_,float dy_):m_r(r),dx(dx_),dy(dy_){}

    void Execute() override { if(m_r) m_r->Move(dx,dy); }

    void Undo() override { if(m_r) m_r->Move(-dx,-dy); }

};

struct Invoker

{

    AZ_TYPE_INFO(Invoker, "{2E7F5C45-7F5E-4A0C-9FCA-168B59A9C9D7}");

    AZStd::vector<AZStd::shared_ptr<ICommand>> history;

    void Do(const AZStd::shared_ptr<ICommand>& c){ c->Execute(); history.push_back(c); }

    void UndoLast(){ if(!history.empty()){ history.back()->Undo(); history.pop_back(); } }

};

// ============= 解释器 =============

struct IExpression

{

    AZ_RTTI(IExpression, "{8F1E32D2-3B5A-4C6C-8C2A-3E7E223B5A11}");

    virtual ~IExpression() = default;

    virtual int Eval() const = 0;

};

struct NumberExpr : IExpression

{

    AZ_RTTI(NumberExpr, "{1E0C3CB3-43B2-4A5A-9A7C-EE6D6B2E2B44}", IExpression);

    int v; explicit NumberExpr(int vv):v(vv){}

    int Eval() const override { return v; }

};

struct AddExpr : IExpression

{

    AZ_RTTI(AddExpr, "{E1E66B63-6F1A-4D5F-93E7-6A9370C3C69D}", IExpression);

    AZStd::shared_ptr<IExpression> a,b;

    int Eval() const override { return a->Eval()+b->Eval(); }

};

// ============= 迭代器 =============

template<class T>

struct SimpleCollection

{

    AZ_TYPE_INFO_TEMPLATE(SimpleCollection, "{B0B0A4E5-3D66-4B95-8E29-39E2D6B2D3C3}", T);

    AZStd::vector<T> data;

    struct Iterator

    {

        size_t i; SimpleCollection* c;

        bool HasNext() const { return i < c->data.size(); }

        T& Next() { return c->data[i++]; }

    };

    Iterator GetIterator() { return Iterator{0,this}; }

};

// ============= 中介者 =============

struct Mediator;

struct Colleague

{

    AZ_RTTI(Colleague, "{E9B7C9D3-3B6D-4C6E-9E2A-4E3B7D2F5B6C}");

    Mediator* m = nullptr;

    virtual ~Colleague() = default;

    virtual void Receive(const AZStd::string& msg) = 0;

    void Send(const AZStd::string& msg);

};

struct Mediator

{

    AZ_RTTI(Mediator, "{6B7E4C9D-5F6B-4E8A-9B2C-7E6F5A9B3C2D}");

    AZStd::vector<Colleague*> cs;

    void Register(Colleague* c){ cs.push_back(c); c->m=this; }

    void Broadcast(const AZStd::string& msg)

    { for(auto* c:cs) c->Receive(msg); }

};

inline void Colleague::Send(const AZStd::string& msg){ if(m) m->Broadcast(msg); }

struct ConcreteColleague : Colleague

{

    AZ_RTTI(ConcreteColleague, "{D6B5E4F2-1F4B-43A6-8B6E-6E2D4F3A2B1C}", Colleague);

    AZStd::string last;

    void Receive(const AZStd::string& msg) override { last = msg; }

};

// ============= 备忘录 =============

struct Snapshot

{

    AZ_TYPE_INFO(Snapshot, "{0D7B2BDE-3B45-4E4C-8B0D-6F0B5B8E6C2F}");

    int hp; int mp;

};

struct Player

{

    AZ_TYPE_INFO(Player, "{E1A6B2B9-8C31-4A3E-9D7F-7E3C2B1A9F0C}");

    int hp=100, mp=50;

    Snapshot Save() const { return Snapshot{hp,mp}; }

    void Load(const Snapshot& s){ hp=s.hp; mp=s.mp; }

};

// ============= 观察者(用 EBus/BehaviorContext) =============

class HealthNotifications

    : public AZ::EBusTraits

{

public:

    static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;

    static const AZ::EBusHandlerPolicy HandlerPolicy  = AZ::EBusHandlerPolicy::Multiple;

    virtual void OnHealthChanged(int newHp) = 0;

};

using HealthNotificationBus = AZ::EBus<HealthNotifications>;

class HealthComponent

    : public AZ::Component

{

public:

    AZ_COMPONENT(HealthComponent, "{4B1F8E8B-8B17-49D3-8E7A-4B8D7688A7C5}");

    static void Reflect(AZ::ReflectContext* context)

    {

        if (auto bc = azrtti_cast<AZ::BehaviorContext*>(context))

        {

            bc->Class<HealthComponent>("dp.HealthComponent")

                ->Method("SetHp", &HealthComponent::SetHp)

                ->Method("GetHp", &HealthComponent::GetHp);

            bc->EBus<HealthNotificationBus>("dp.HealthNotificationBus")

                ->Handler<HealthNotifications>();

        }

    }

    static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&){}

    static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&){}

    static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&){}

    static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType&){}

    void Activate() override {}

    void Deactivate() override {}

    void SetHp(int hp)

    {

        m_hp = hp;

        HealthNotificationBus::Broadcast(&HealthNotifications::OnHealthChanged, m_hp);

    }

    int GetHp() const { return m_hp; }

private:

    int m_hp = 100;

};

// ============= 状态 =============

struct IAIState

{

    AZ_RTTI(IAIState, "{2B8E4F01-0EAF-4430-8B8D-2A9B1BFE9C81}");

    virtual ~IAIState() = default;

    virtual AZStd::string Update() = 0;

};

struct PatrolState : IAIState

{

    AZ_RTTI(PatrolState, "{E1C3F51C-2F8D-4C2A-8F6A-1B3E2D4C5F6A}", IAIState);

    AZStd::string Update() override { return "Patrolling"; }

};

struct ChaseState : IAIState

{

    AZ_RTTI(ChaseState, "{B7E8A2D4-3B1C-4D5E-8A3F-7E2D1C4B5A6C}", IAIState);

    AZStd::string Update() override { return "Chasing"; }

};

struct AIContext

{

    AZ_TYPE_INFO(AIContext, "{7E2F1B3C-5D4A-4A88-8D9C-1F2E3D4C5B6A}");

    AZStd::shared_ptr<IAIState> cur;

    AZStd::string Tick(){ return cur?cur->Update():"Idle"; }

    void Set(AZStd::shared_ptr<IAIState> s){ cur = s; }

};

// ============= 策略 =============

struct IPathStrategy

{

    AZ_RTTI(IPathStrategy, "{A1B2C3D4-E5F6-47A8-90AB-1C2D3E4F5A6B}");

    virtual ~IPathStrategy() = default;

    virtual AZStd::string Calc() = 0;

};

struct AStarStrategy : IPathStrategy

{

    AZ_RTTI(AStarStrategy, "{B2C3D4E5-F6A7-48B9-80AB-2C3D4E5F6A7B}", IPathStrategy);

    AZStd::string Calc() override { return "A* path"; }

};

struct DijkstraStrategy : IPathStrategy

{

    AZ_RTTI(DijkstraStrategy, "{C3D4E5F6-A7B8-49CA-70AB-3C4D5E6F7A8B}", IPathStrategy);

    AZStd::string Calc() override { return "Dijkstra path"; }

};

struct PathContext

{

    AZ_TYPE_INFO(PathContext, "{D4E5F6A7-B8C9-4ADB-60AB-4D5E6F7A8B9C}");

    AZStd::shared_ptr<IPathStrategy> s;

    void Set(AZStd::shared_ptr<IPathStrategy> ss){ s = ss; }

    AZStd::string Run(){ return s? s->Calc() : ""; }

};

// ============= 模板方法 =============

struct LevelLoader

{

    AZ_RTTI(LevelLoader, "{E5F6A7B8-C9DA-4BEC-50AB-5D6E7F8A9B0C}");

    virtual ~LevelLoader() = default;

    AZStd::string Load()

    {

        return Read() + "->" + Parse() + "->" + CreateEntities();

    }

    virtual AZStd::string Read(){ return "Read file"; }

    virtual AZStd::string Parse(){ return "Parse data"; }

    virtual AZStd::string CreateEntities(){ return "Create entities"; }

};

struct JsonLevelLoader : LevelLoader

{

    AZ_RTTI(JsonLevelLoader, "{F6A7B8C9-DAB0-4CED-40AB-6D7E8F9A0B1C}", LevelLoader);

    AZStd::string Read() override { return "Read JSON"; }

    AZStd::string Parse() override { return "Parse JSON"; }

};

// ============= 访问者 =============

struct IVisitable;

struct IVisitor

{

    AZ_RTTI(IVisitor, "{07E76194-2C28-4D2B-8C8F-559F43B2CCB6}");

    virtual ~IVisitor() = default;

    virtual void Visit(class VisitableA&) = 0;

    virtual void Visit(class VisitableB&) = 0;

};

struct IVisitable

{

    AZ_RTTI(IVisitable, "{C50E7D0D-3D36-4F42-9B6F-B67F8F9E62F3}");

    virtual ~IVisitable() = default;

    virtual void Accept(IVisitor&) = 0;

};

struct VisitableA : IVisitable

{

    AZ_RTTI(VisitableA, "{6B6F1E38-1ED5-4918-BA71-7F2A0EFA3F4A}", IVisitable);

    void Accept(IVisitor& v) override { v.Visit(*this); }

};

struct VisitableB : IVisitable

{

    AZ_RTTI(VisitableB, "{0F3A0C5E-57B2-42C1-8B81-0D8E610C716F}", IVisitable);

    void Accept(IVisitor& v) override { v.Visit(*this); }

};

struct ConcreteVisitor : IVisitor

{

    AZ_RTTI(ConcreteVisitor, "{E3E9B8C1-1DA4-41E7-8B9E-6F2C1E4B3A5C}", IVisitor);

    AZStd::string log;

    void Visit(VisitableA&) override { log += "A;"; }

    void Visit(VisitableB&) override { log += "B;"; }

};

// ============= SystemComponent 反射所有类型 =============

class DesignPatternsSystemComponent

    : public AZ::Component

    , public LogRequests

{

public:

    AZ_COMPONENT(DesignPatternsSystemComponent, "{0C2E7E65-5C7A-4C63-A07D-7C0C2E0F83C7}");

    static void Reflect(AZ::ReflectContext* context)

    {

        if (auto sc = azrtti_cast<AZ::SerializeContext*>(context))

        {

            sc->Class<DesignPatternsSystemComponent, AZ::Component>();

            sc->Class<HealthComponent, AZ::Component>();

        }

        if (auto bc = azrtti_cast<AZ::BehaviorContext*>(context))

        {

            // 日志 EBus

            bc->EBus<LogBus>("dp.LogBus")

                ->Event("Info", &LogRequests::Info);

            // 抽象工厂

            bc->Class<IEnemy>("dp.IEnemy")->Method("Attack", &IEnemy::Attack);

            bc->Class<Orc>("dp.Orc")->Constructor<>();

            bc->Class<Troll>("dp.Troll")->Constructor<>();

            bc->Class<IEnemyFactory>("dp.IEnemyFactory");

            bc->Class<OrcFactory>("dp.OrcFactory")->Constructor<>();

            bc->Class<TrollFactory>("dp.TrollFactory")->Constructor<>();

            // 建造者

            bc->Class<Character>("dp.Character")

                ->Property("name", BehaviorValueProperty(&Character::m_name))

                ->Property("hp", BehaviorValueProperty(&Character::m_hp))

                ->Property("attack", BehaviorValueProperty(&Character::m_attack));

            bc->Class<WarriorBuilder>("dp.WarriorBuilder")->Constructor<>()

                ->Method("Reset", &WarriorBuilder::Reset)

                ->Method("SetName", &WarriorBuilder::SetName)

                ->Method("SetHP", &WarriorBuilder::SetHP)

                ->Method("SetAttack", &WarriorBuilder::SetAttack)

                ->Method("GetResult", &WarriorBuilder::GetResult);

            bc->Class<CharacterDirector>("dp.CharacterDirector")->Constructor<>()

                ->Method("MakeTank", &CharacterDirector::MakeTank);

            // 工厂方法

            bc->Class<IProjectile>("dp.IProjectile")->Method("Fire", &IProjectile::Fire);

            bc->Class<Arrow>("dp.Arrow")->Constructor<>();

            bc->Class<Fireball>("dp.Fireball")->Constructor<>();

            bc->Class<ArrowSpawner>("dp.ArrowSpawner")->Constructor<>()

                ->Method("Make", &ArrowSpawner::Make);

            bc->Class<FireballSpawner>("dp.FireballSpawner")->Constructor<>()

                ->Method("Make", &FireballSpawner::Make);

            // 原型

            bc->Class<ICloneable>("dp.ICloneable");

            bc->Class<Spell>("dp.Spell")->Constructor<>()

                ->Property("name", BehaviorValueProperty(&Spell::m_name))

                ->Property("power", BehaviorValueProperty(&Spell::m_power))

                ->Method("Clone", &Spell::Clone);

            // 单例接口(通过静态访问)

            bc->Class<ConfigInterface>("dp.Config")

                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)

                ->Method("Get", &ConfigInterface::Get)

                ->Method("Register", &ConfigInterface::Register)

                ->Method("Unregister", &ConfigInterface::Unregister);

            bc->Class<ConfigImpl>("dp.ConfigImpl")->Constructor<>()

                ->Method("Set", &ConfigImpl::Set)

                ->Method("GetKV", &ConfigImpl::Get);

            // 适配器

            bc->Class<LegacyAudioAdapter>("dp.LegacyAudioAdapter")->Constructor<>()

                ->Method("Play", &LegacyAudioAdapter::Play);

            // 桥接

            bc->Class<VulkanImpl>("dp.VulkanImpl")->Constructor<>();

            bc->Class<DX12Impl>("dp.DX12Impl")->Constructor<>();

            bc->Class<RenderAbstraction>("dp.RenderAbstraction")->Constructor<AZStd::shared_ptr<IRenderImpl>>()

                ->Method("RenderMesh", &RenderAbstraction::RenderMesh);

            // 组合

            bc->Class<Leaf>("dp.Leaf")->Constructor<>()

                ->Property("cost", BehaviorValueProperty(&Leaf::m_cost))

                ->Method("GetCost", &Leaf::GetCost);

            bc->Class<CompositeNode>("dp.CompositeNode")->Constructor<>()

                ->Method("Add", &CompositeNode::Add)

                ->Method("GetCost", &CompositeNode::GetCost);

            // 装饰

            bc->Class<Sword>("dp.Sword")->Constructor<>()

                ->Method("Damage", &Sword::Damage)

                ->Method("Desc", &Sword::Desc);

            bc->Class<FireEnchant>("dp.FireEnchant")->Constructor<AZStd::shared_ptr<IWeapon>>()

                ->Method("Damage", &FireEnchant::Damage)

                ->Method("Desc", &FireEnchant::Desc);

            // 外观

            bc->Class<EngineFacade>("dp.EngineFacade")->Constructor<>()

                ->Method("Boot", &EngineFacade::Boot);

            // 享元

            bc->Class<BulletFlyweightFactory>("dp.BulletFlyweightFactory")->Constructor<>()

                ->Method("Get", &BulletFlyweightFactory::Get);

            // 代理

            bc->Class<CachingAssetLoaderProxy>("dp.CachingAssetLoaderProxy")->Constructor<>()

                ->Method("Load", &CachingAssetLoaderProxy::Load);

            // 责任链

            bc->Class<DamageRequest>("dp.DamageRequest")->Constructor<>()

                ->Property("level", BehaviorValueProperty(&DamageRequest::m_level));

            bc->Class<LowLevelHandler>("dp.LowLevelHandler")->Constructor<>()

                ->Method("SetNext", &LowLevelHandler::SetNext)

                ->Method("Handle", &LowLevelHandler::Handle);

            bc->Class<HighLevelHandler>("dp.HighLevelHandler")->Constructor<>()

                ->Method("SetNext", &HighLevelHandler::SetNext)

                ->Method("Handle", &HighLevelHandler::Handle);

            // 命令

            bc->Class<MoveReceiver>("dp.MoveReceiver")->Constructor<>()

                ->Property("x", BehaviorValueProperty(&MoveReceiver::x))

                ->Property("y", BehaviorValueProperty(&MoveReceiver::y))

                ->Method("Move", &MoveReceiver::Move);

            bc->Class<MoveCommand>("dp.MoveCommand")->Constructor<MoveReceiver*,float,float>()

                ->Method("Execute", &MoveCommand::Execute)

                ->Method("Undo", &MoveCommand::Undo);

            bc->Class<Invoker>("dp.Invoker")->Constructor<>()

                ->Method("Do", &Invoker::Do)

                ->Method("UndoLast", &Invoker::UndoLast);

            // 解释器

            bc->Class<NumberExpr>("dp.NumberExpr")->Constructor<int>()

                ->Method("Eval", &NumberExpr::Eval);

            bc->Class<AddExpr>("dp.AddExpr")->Constructor<>()

                ->Property("a", BehaviorValueProperty(&AddExpr::a))

                ->Property("b", BehaviorValueProperty(&AddExpr::b))

                ->Method("Eval", &AddExpr::Eval);

            // 迭代器(以简单容器暴露仅作示意,脚本侧更适配数组)

            // 这里不做 BehaviorContext 暴露,避免模板复杂性;游戏里建议用 Lua 表或 ScriptCanvas 数组。

            // 中介者

            bc->Class<Mediator>("dp.Mediator")->Constructor<>()

                ->Method("Register", &Mediator::Register)

                ->Method("Broadcast", &Mediator::Broadcast);

            bc->Class<ConcreteColleague>("dp.ConcreteColleague")->Constructor<>()

                ->Property("last", BehaviorValueProperty(&ConcreteColleague::last))

                ->Method("Send", &ConcreteColleague::Send);

            // 备忘录

            bc->Class<Player>("dp.Player")->Constructor<>()

                ->Property("hp", BehaviorValueProperty(&Player::hp))

                ->Property("mp", BehaviorValueProperty(&Player::mp))

                ->Method("Save", &Player::Save)

                ->Method("Load", &Player::Load);

            // 观察者(HealthComponent 已反射,EBus 也暴露)

            HealthComponent::Reflect(context);

            // 状态

            bc->Class<PatrolState>("dp.PatrolState")->Constructor<>()

                ->Method("Update", &PatrolState::Update);

            bc->Class<ChaseState>("dp.ChaseState")->Constructor<>()

                ->Method("Update", &ChaseState::Update);

            bc->Class<AIContext>("dp.AIContext")->Constructor<>()

                ->Method("Set", &AIContext::Set)

                ->Method("Tick", &AIContext::Tick);

            // 策略

            bc->Class<AStarStrategy>("dp.AStarStrategy")->Constructor<>()

                ->Method("Calc", &AStarStrategy::Calc);

            bc->Class<DijkstraStrategy>("dp.DijkstraStrategy")->Constructor<>()

                ->Method("Calc", &DijkstraStrategy::Calc);

            bc->Class<PathContext>("dp.PathContext")->Constructor<>()

                ->Method("Set", &PathContext::Set)

                ->Method("Run", &PathContext::Run);

            // 模板方法

            bc->Class<JsonLevelLoader>("dp.JsonLevelLoader")->Constructor<>()

                ->Method("Load", &JsonLevelLoader::Load);

            // 访问者

            bc->Class<VisitableA>("dp.VisitableA")->Constructor<>()

                ->Method("Accept", &VisitableA::Accept);

            bc->Class<VisitableB>("dp.VisitableB")->Constructor<>()

                ->Method("Accept", &VisitableB::Accept);

            bc->Class<ConcreteVisitor>("dp.ConcreteVisitor")->Constructor<>()

                ->Property("log", BehaviorValueProperty(&ConcreteVisitor::log));

        }

    }

    static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& s) { s.push_back(AZ_CRC_CE("DesignPatternsService")); }

    static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& s) { s.push_back(AZ_CRC_CE("DesignPatternsService")); }

    static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArray::type&) {}

    static void GetDependentServices(AZ::ComponentDescriptor::DependencyArray::type&) {}

    void Activate() override

    {

        m_logger.Activate();

        LogBus::Handler::BusConnect();

        ConfigInterface::Register(&m_config);

    }

    void Deactivate() override

    {

        ConfigInterface::Unregister(&m_config);

        LogBus::Handler::BusDisconnect();

        m_logger.Deactivate();

    }

    // LogRequests

    void Info(const AZStd::string& msg) override

    {

        AZ_Printf("DesignPatterns", "[Gem] %s\n", msg.c_str());

    }

private:

    Logger m_logger;

    ConfigImpl m_config;

};

class DesignPatternsModule

    : public AZ::Module

{

public:

    AZ_RTTI(DesignPatternsModule, "{E3AB2E2B-8B5C-4E6F-9DB1-3C9C2CB9317E}", AZ::Module);

    AZ_CLASS_ALLOCATOR(DesignPatternsModule, AZ::SystemAllocator);

    DesignPatternsModule()

    {

        m_descriptors.insert(m_descriptors.end(), {

            DesignPatternsSystemComponent::CreateDescriptor(),

            HealthComponent::CreateDescriptor()

        });

    }

    AZ::ComponentTypeList GetRequiredSystemComponents() const override

    {

        return AZ::ComponentTypeList{

            azrtti_typeid<DesignPatternsSystemComponent>()

        };

    }

};

}

AZ_DECLARE_MODULE_CLASS(Gem_DesignPatternsGem, dp::DesignPatternsModule)

========================
Lua
使用示例(脚本侧)

以下是一些 Lua 侧调用示例(在 O3DE Lua 环境,BehaviorContext 暴露名称以 dp.* 为前缀):

-- 抽象工厂
local orcFactory = dp.OrcFactory()
local melee = orcFactory:MakeMelee() -- 注意:上面示例暴露了 Make() 的工厂方法在工厂方法模式里,这里示例抽象工厂你可扩展暴露
-- 由于 BehaviorContext 未直接暴露 IEnemyFactory 的 CreateMelee/CreateTank,你可添加:
-- bc->Class("dp.OrcFactory")->Method("CreateMelee", &OrcFactory::CreateMelee) 等
-- 这里仅演示其它模式:

-- 工厂方法
local sp = dp.FireballSpawner()
local proj = sp:Make()
print(proj:Fire())

-- 建造者
local b = dp.WarriorBuilder()
local dir = dp.CharacterDirector()
dir:MakeTank(b)
local c = b:GetResult()
print(c.name, c.hp, c.attack)

-- 单例
local cfg = dp.Config.Get()
-- 注意:Get 返回的是 C++ 指针语义;可通过 SystemComponent 在激活时已注册。
local impl = dp.ConfigImpl()
impl:Set("difficulty", "hard")
dp.Config.Register(impl)
print(dp.Config.Get():GetKV("difficulty"))

-- 装饰
local sword = dp.Sword()
local fireSword = dp.FireEnchant(sword)
print(fireSword:Desc(), fireSword:Damage())

-- 命令
local r = dp.MoveReceiver()
local inv = dp.Invoker()
local cmd = dp.MoveCommand(r, 1, 2)
inv:Do(cmd)
print(r.x, r.y)
inv:UndoLast()
print(r.x, r.y)

-- 状态/策略
local ctx = dp.AIContext()
ctx:Set(dp.PatrolState())
print(ctx:Tick())
ctx:Set(dp.ChaseState())
print(ctx:Tick())

-- 访问者
local v = dp.ConcreteVisitor()
local a = dp.VisitableA()
local b2 = dp.VisitableB()
a:Accept(v); b2:Accept(v)
print(v.log)

========================
ScriptCanvas
使用

  • 因所有相关类已通过 BehaviorContext 暴露,你可以在 ScriptCanvas 中看到 dp.* 类型和方法。
  • 对于 EBus(dp.LogBus、dp.HealthNotificationBus),可用 ScriptCanvas 的 EBus 节点进行广播/侦听。
  • 若需要节点更友好命名,可用 AZ::Script::Attributes 指定。

========================
O3DE 场景中的结合点

  • 观察者:HealthComponent 通过 HealthNotificationBus 广播,其他组件或 ScriptCanvas 图接入 OnHealthChanged 事件。
  • 命令:Undo/Redo 可在编辑器工具或玩法中管理玩家操作历史。
  • 代理:资源加载可接 AZ::Data::AssetManager 封装,示例为最小实现。
  • 享元:将 mesh/material 等内在状态放到工厂池,实例外在状态运行时传入,用于弹药、粒子等高频对象。
  • 单例:通过 Interface/Register 在 SystemComponent Activate/Deactivate 生命周期注册与释放。
  • 桥接/适配器:和渲染/音频子系统对接时保持上层抽象解耦。

需要我把上述代码拆分为标准 Gem 目录的“完整工程模板”(含 Gem.json、实际 CMake 文件、每个 .h/.cpp 分拆)吗?我可以直接生成按文件划分的全套代码与清单。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值