游戏开发核心架构指南
游戏开发核心架构指南
深入理解游戏开发中的核心架构模式:ECS、MVC、MVP、MVVM、OOP、DOP、FSM、HFSM、事件驱动、GOAP、Behavior Tree、Utility AI、Component、Observer、Ability System
目录
- 游戏开发核心架构指南
-
- 1. OOP(面向对象编程)
- 2. Component(组件模式)
- 3. DOP(数据导向编程)
- 4. ECS(实体组件系统)
- 5. Ability System(能力系统)
- 6. MVC(模型-视图-控制器)
- 7. MVP(模型-视图-展示器)
- 8. MVVM(模型-视图-视图模型)
- 9. Observer(观察者模式)与Event(事件系统)
- 10. FSM(有限状态机)
- 11. HFSM(分层有限状态机)
- 12. Behavior Tree(行为树)
- 13. GOAP(目标导向行为规划)
- 14. Utility AI(效用AI)
- 15. 架构对比总结
- 16. Unreal Engine 架构映射
- 结语
1. OOP(面向对象编程)
概述
OOP(Object-Oriented Programming)是最经典的游戏开发范式,以"对象"为核心,通过封装、继承、多态三大特性组织代码。
核心概念
游戏中的典型应用
// 基类:游戏角色
class Character
{
protected:
std::string name;
int hp;
int maxHp;
float speed;
public:
Character(const std::string& n, int h, float s)
: name(n), hp(h), maxHp(h), speed(s) {}
virtual void Update(float deltaTime)
{
// 基础更新逻辑
}
virtual void TakeDamage(int damage)
{
hp -= damage;
if (hp <= 0) Die();
}
virtual void Die() { /* 死亡逻辑 */ }
virtual ~Character() = default;
};
// 派生类:玩家
class Player : public Character
{
private:
int experience;
int playerLevel;
public:
Player(const std::string& name)
: Character(name, 100, 5.0f), experience(0), playerLevel(1) {}
void Update(float deltaTime) override
{
HandleInput();
Character::Update(deltaTime);
}
void GainExperience(int exp)
{
experience += exp;
if (experience >= playerLevel * 100) LevelUp();
}
private:
void HandleInput() { /* 键盘/手柄输入处理 */ }
void LevelUp() {
playerLevel++;
maxHp += 20;
hp = maxHp;
speed += 0.5f;
}
};
继承层次结构
现代游戏开发趋势:组合优于继承
传统OOP在游戏行业正在逐渐弱化深度继承,转而强化组合(Composition)。
// ❌ 传统深度继承(已不推荐)
class Monster : public Character {};
class FireMonster : public Monster {};
class FireBossMonster : public FireMonster {};
// ✅ 推荐:OOP + Component(UE风格)
class ACharacter
{
UCameraComponent* Camera;
UInventoryComponent* Inventory;
UAbilitySystemComponent* Abilities;
UEquipmentComponent* Equipment;
};
核心原则:现代游戏开发更推荐组合优于继承(Composition over Inheritance)。用组件拼装对象功能,而非用继承链定义对象类型。
优缺点
| 对比维度 | 传统深层继承(Inheritance) | 现代组件组合(Composition) |
|---|---|---|
| 核心逻辑 | "是"关系 (Is-A) 通过父类是谁来决定自己拥有什么功能。 |
"有"关系 (Has-A) 通过自己挂载了什么组件来决定拥有什么功能。 |
| 解耦程度 | 强耦合(白盒复用) 基类的修改会波及整条继承链,引发"脆弱基类"问题。 |
强解耦(黑盒复用) 组件之间相互独立,行为内聚,接口清晰。 |
| 动态扩展性 | 编译期决定(死板) 无法在游戏运行时动态剥离或增加某个基类行为。 |
运行期决定(极度灵活) 支持在运行时通过代码或编辑器动态 AddComponent / DestroyComponent。 |
| 类体量控制 | 类爆炸 / 菱形继承 为了组合不同功能(如:既能飞又能游泳的怪物),不得不陷入多重继承灾难。 |
线性增长(N个功能 = N个组件) 新功能只需抽象成独立组件,直接挂载到宿主即可,无视继承关系。 |
| 生产力协同 | 程序包揽(不利于策划) 新类型的定制必须由程序编写派生类,关卡设计师无法自由组装。 |
数据驱动(策划友好) 程序写好组件,策划可以在编辑器中通过蓝图或预制体自由拼装、调整参数。 |
| 主要代价/缺点 | 1. 继承链深了以后,代码极难重构与维护。 2. 虚函数虚表查找(V-Table Click)带来额外的 CPU 间接寻址开销。 |
1. 组件间通信(如物理组件调用动画组件)需要特定的解耦设计。 2. 挂载过多组件时,生命周期管理与依赖检查有额外开销。 |
2. Component(组件模式)
概述
Component模式是OOP的演进产物,将对象功能拆分为独立组件,通过组合方式构建复杂对象。UE的ActorComponent、Unity的MonoBehaviour都是这一模式的典型实现。
架构对比
Component C++ 实现(UE风格)
class Actor
{
private:
std::vector<std::unique_ptr<Component>> components;
public:
~Actor() = default;
template<typename T>
T* AddComponent()
{
static_assert(std::is_base_of_v<Component, T>, "T must derive from Component");
auto comp = std::make_unique<T>(this);
T* ptr = comp.get();
comp->Initialize();
components.push_back(std::move(comp));
return ptr;
}
template<typename T>
T* GetComponent()
{
for (auto& c : components)
{
if (auto* casted = dynamic_cast<T*>(c.get()))
return casted;
}
return nullptr;
}
void Update(float dt)
{
for (auto& c : components) c->Tick(dt);
}
};
// 组件基类
class Component
{
protected:
Actor* owner;
public:
Component(Actor* o) : owner(o) {}
virtual ~Component() = default;
virtual void Initialize() {}
virtual void Tick(float dt) {}
};
// 具体组件
class MovementComponent : public Component
{
Vector3 velocity;
public:
void Tick(float dt) override
{
owner->SetPosition(owner->GetPosition() + velocity * dt);
}
};
class HealthComponent : public Component
{
int hp = 100;
public:
void TakeDamage(int dmg) { hp -= dmg; }
bool IsAlive() const { return hp > 0; }
};
// 使用
Actor player;
player.AddComponent<MovementComponent>();
player.AddComponent<HealthComponent>();
player.AddComponent<InventoryComponent>();
优缺点
| 优点 | 缺点 |
|---|---|
| 灵活组合功能 | 组件间通信复杂 |
| 避免继承爆炸 | 运行时类型检查开销 |
| 易于复用和测试 | 组件依赖管理 |
| UE/Unity原生支持 | 过度拆分组件的风险 |
3. DOP(数据导向编程)
概述
DOP(Data-Oriented Programming)数据导向编程,强调以数据为中心组织程序,关注数据在内存中的布局和访问模式,最大化CPU缓存利用率。
核心思想
注意:SoA(Struct of Arrays)是DOP的一种实现方式,而非DOP本身。DOP的核心思想是按访问模式组织数据,SoA只是最常见的实现手段。
C++ 实现
// DOP 风格:数据与逻辑分离,SoA布局
struct GameData
{
std::vector<float> posX;
std::vector<float> posY;
std::vector<float> velocityX;
std::vector<float> velocityY;
std::vector<int> hp;
std::vector<uint8_t> isActive;
};
void UpdatePositions(GameData& data, float dt)
{
const size_t count = std::min({
data.posX.size(), data.posY.size(),
data.velocityX.size(), data.velocityY.size()
});
float* px = data.posX.data();
float* py = data.posY.data();
float* vx = data.velocityX.data();
float* vy = data.velocityY.data();
for (size_t i = 0; i < count; ++i)
{
px[i] += vx[i] * dt;
py[i] += vy[i] * dt;
}
}
struct HotData {
std::vector<float> posX;
std::vector<float> posY;
std::vector<int> hp;
std::vector<uint8_t> active;
};
struct ColdData
{
std::vector<std::string> name;
std::vector<float> respawnTimer;
};
性能对比
constexpr size_t ENTITY_COUNT = 1000000;
// AoS (OOP 风格) - Cache不友好
struct EntityAoS { float x, y, vx, vy; int hp; };
std::vector<EntityAoS> entitiesAoS(ENTITY_COUNT);
// SoA (DOP 风格) - Cache友好
std::unique_ptr<float[]> x(new float[ENTITY_COUNT]);
std::unique_ptr<float[]> y(new float[ENTITY_COUNT]);
std::unique_ptr<float[]> vx(new float[ENTITY_COUNT]);
std::unique_ptr<float[]> vy(new float[ENTITY_COUNT]);
void UpdateAoS(float dt)
{
for (auto& e : entitiesAoS) {
e.x += e.vx * dt;
e.y += e.vy * dt;
}
}
void UpdateSoA(float dt)
{
for (size_t i = 0; i < ENTITY_COUNT; ++i)
{
x[i] += vx[i] * dt;
y[i] += vy[i] * dt;
}
}
优缺点
| 优点 | 缺点 |
|---|---|
| 极高的缓存效率 | 代码可读性较差 |
| 易于并行化(SIMD/多线程) | 开发效率较低 |
| 性能可预测 | 难以建模复杂关系 |
| 适合大规模数据处理 | 调试困难 |
4. ECS(实体组件系统)
概述
ECS(Entity Component System)是游戏开发中广泛使用的架构模式,将数据(Component)与行为(System)彻底分离,实体(Entity)只是一个ID。
架构图
核心概念
// ============ 1. Entity(实体):仅为ID ============
struct Entity
{
uint32_t index;
uint32_t generation;
bool operator==(const Entity& other) const
{
return index == other.index && generation == other.generation;
}
};
// ============ 2. Component(组件):纯数据 ============
struct Position { float x, y; };
struct Velocity { float vx, vy; };
struct Sprite { std::string textureName; int w, h; };
struct Health { int current, max; };
// ============ 3. System(系统):纯逻辑 ============
class MovementSystem
{
public:
void Update(ArchetypeManager& am, float dt)
{
am.ForEach<Position, Velocity>([dt](Position& pos, Velocity& vel)
{
pos.x += vel.vx * dt;
pos.y += vel.vy * dt;
});
}
};
现代 ECS(Archetype/Chunk模型)
ArchetypeManager 简化实现
class ArchetypeManager
{
private:
struct Archetype
{
std::bitset<32> mask;
std::vector<uint8_t> buffer;
size_t entityCount;
};
std::vector<Archetype> archetypes;
template<typename T>
static constexpr size_t GetComponentId() { return 0; }
public:
template<typename... Comps>
void ForEach(std::function<void(Comps&...)> callback)
{
std::bitset<32> requiredMask;
(requiredMask.set(GetComponentId<Comps>()), ...);
for (auto& arch : archetypes)
{
if ((arch.mask & requiredMask) != requiredMask) continue;
size_t offset = 0;
for (size_t i = 0; i < arch.entityCount; ++i)
{
size_t localOff = offset;
callback(*reinterpret_cast<Comps*>(arch.buffer.data() + localOff)...);
((localOff += sizeof(Comps)), ...);
}
}
}
};
对比:OOP vs ECS
| 维度 | OOP | ECS |
|---|---|---|
| 实体定义 | 对象实例 | 数字ID + Generation |
| 数据存储 | 分散在对象中 | 连续数组(SoA) |
| 逻辑组织 | 类方法 | 独立System |
| 缓存效率 | 低 | 极高 |
| 扩展方式 | 继承/组合 | 新增Component/System |
优缺点
| 优点 | 缺点 |
|---|---|
| 数据与逻辑完全分离 | 学习曲线陡峭 |
| 天然缓存友好 | 小项目过度设计 |
| 易于扩展新功能 | 组件通信复杂 |
| 适合大型复杂游戏 | 调试困难 |
| 便于多线程并行 | 某些模式难以表达 |
5. Ability System(能力系统)
概述
Ability System(技能能力系统)是现代商业游戏(尤其是UE项目)中管理技能、Buff、状态效果的核心架构,以数据驱动组装替代传统硬编码技能逻辑。
UE的 Gameplay Ability System(GAS) 是其代表实现,广泛应用于MMO、ARPG、MOBA等品类。
架构图
技能生命周期
C++ 简化实现
// ============ AttributeSet(属性集) ============
struct AttributeSet
{
float maxHp = 100;
float currentHp = 100;
float maxMana = 50;
float currentMana = 50;
float attackPower = 10;
float defensePower = 5;
float moveSpeed = 300;
};
// ============ GameplayTag(标签) ============
struct GameplayTag
{
std::string tag;
bool Matches(const std::string& pattern) const
{
return tag == pattern || tag.find(pattern) == 0;
}
};
// ============ GameplayEffect = 效果/Buff系统 ============
enum class EffectPolicy
{
Instant,
Duration,
Infinite
};
enum class AttributeType
{
MaxHp, CurrentHp, MaxMana, CurrentMana,
AttackPower, DefensePower, MoveSpeed
};
using TagContainer = std::vector<GameplayTag>;
enum class ModifierOp { Add, Multiply, Override };
struct ModifierOperation
{
AttributeType targetAttribute;
float value;
ModifierOp op;
};
class GameplayEffect
{
public:
std::string name;
EffectPolicy policy;
float duration;
std::vector<ModifierOperation> modifiers;
std::vector<GameplayTag> grantedTags;
std::vector<GameplayTag> requiredTags;
bool CanApplyTo(const TagContainer& tags) const
{
for (auto& req : requiredTags)
{
bool found = false;
for (auto& t : tags)
{
if (t.tag == req.tag) { found = true; break; }
}
if (!found) return false;
}
return true;
}
void Execute(AttributeSet& attributes) const
{
for (auto& mod : modifiers)
{
float* attr = nullptr;
switch (mod.targetAttribute)
{
case AttributeType::CurrentHp: attr = &attributes.currentHp; break;
case AttributeType::MaxHp: attr = &attributes.maxHp; break;
case AttributeType::CurrentMana: attr = &attributes.currentMana; break;
case AttributeType::MaxMana: attr = &attributes.maxMana; break;
case AttributeType::AttackPower: attr = &attributes.attackPower; break;
case AttributeType::DefensePower: attr = &attributes.defensePower; break;
case AttributeType::MoveSpeed: attr = &attributes.moveSpeed; break;
}
if (!attr) continue;
if (mod.op == ModifierOp::Add) *attr += mod.value;
else if (mod.op == ModifierOp::Multiply) *attr *= mod.value;
else if (mod.op == ModifierOp::Override) *attr = mod.value;
}
}
};
// ============ GameplayAbility = 技能 ============
class GameplayAbility
{
public:
std::string name;
float cooldown = 0;
float manaCost = 0;
float castTime = 0;
GameplayTag abilityTag;
std::vector<GameplayTag> requiredTags;
std::vector<GameplayTag> blockedTags;
std::vector<GameplayTag> cancelTags;
std::vector<std::shared_ptr<GameplayEffect>> effects;
virtual bool CanActivate(const TagContainer& ownerTags) const
{
for (auto& req : requiredTags)
{
bool found = false;
for (auto& t : ownerTags)
{
if (t.tag == req.tag) { found = true; break; }
}
if (!found) return false;
}
for (auto& blocked : blockedTags)
{
for (auto& t : ownerTags)
{
if (t.tag == blocked.tag) return false;
}
}
return true;
}
virtual void OnActivate(AttributeSet& attributes)
{
attributes.currentMana -= manaCost;
}
virtual void OnExecute(AttributeSet& attributes)
{
for (auto& effect : effects)
effect->Execute(attributes);
}
virtual void OnEnd() {}
virtual void OnCancel() {}
};
// ============ AbilitySystemComponent = 核心管理器 ============
class AbilitySystemComponent
{
private:
std::vector<std::shared_ptr<GameplayAbility>> abilities;
std::vector<std::shared_ptr<GameplayEffect>> activeEffects;
AttributeSet attributes;
TagContainer tags;
public:
void GiveAbility(std::shared_ptr<GameplayAbility> ability)
{
abilities.push_back(std::move(ability));
}
bool TryActivateAbility(const std::string& abilityName)
{
for (auto& ability : abilities)
{
if (ability->name == abilityName && ability->CanActivate(tags))
{
ability->OnActivate(attributes);
return true;
}
}
return false;
}
void ApplyEffect(std::shared_ptr<GameplayEffect> effect)
{
effect->Execute(attributes);
if (effect->policy == EffectPolicy::Duration)
{
activeEffects.push_back(std::move(effect));
}
}
void TickEffects(float dt)
{
for (auto it = activeEffects.begin(); it != activeEffects.end(); )
{
auto& effect = *it;
if (effect->policy == EffectPolicy::Duration)
{
effect->duration -= dt;
if (effect->duration <= 0)
{
it = activeEffects.erase(it);
continue;
}
effect->Execute(attributes);
}
++it;
}
}
};
技能定义示例
auto fireball = std::make_shared<GameplayAbility>();
fireball->name = "Fireball";
fireball->manaCost = 20;
fireball->cooldown = 3.0f;
fireball->castTime = 1.5f;
fireball->abilityTag = GameplayTag{"Ability.Fireball"};
fireball->blockedTags = { GameplayTag{"State.Stun"}, GameplayTag{"State.Silence"} };
auto fireDamage = std::make_shared<GameplayEffect>();
fireDamage->name = "FireDamage";
fireDamage->policy = EffectPolicy::Instant;
fireDamage->modifiers = {
{ AttributeType::CurrentHp, -30, ModifierOp::Add }
};
fireball->effects.push_back(fireDamage);
auto burnEffect = std::make_shared<GameplayEffect>();
burnEffect->name = "Burn";
burnEffect->policy = EffectPolicy::Duration;
burnEffect->duration = 5.0f;
burnEffect->modifiers =
{
{ AttributeType::CurrentHp, -5, ModifierOp::Add }
};
fireball->effects.push_back(burnEffect);
GAS 核心流程
优缺点
| 优点 | 缺点 |
|---|---|
| 数据驱动,技能热更新 | 学习曲线陡峭 |
| 逻辑与数据分离 | 调试复杂(多层嵌套Effect) |
| Tag系统灵活组合 | 设计过度抽象的风险 |
| 优秀的Buff/状态管理 | 小项目过度工程化 |
| 社区已验证(Fortnite/帕鲁) | Effect间交互逻辑复杂 |
| UE原生支持(GAS Plugin) | 仅在UE生态成熟 |
与ECS/Component的关系
GAS可以看作 Component 模式的进阶应用,用标签(Tag)驱动数值变化和状态管理,适合MMO/ARPG等技能机制复杂的项目。
6. MVC(模型-视图-控制器)
概述
MVC 将应用程序分为三个核心部分:Model(数据与业务逻辑)、View(界面展示)、Controller(输入处理与协调)。
架构图
C++ 实现
class Observer;
// ============ Model ============
class PlayerModel
{
private:
int hp;
int maxHp;
int mana;
std::vector<Observer*> observers;
public:
PlayerModel() : hp(100), maxHp(100), mana(50) {}
void TakeDamage(int damage)
{
hp = std::max(0, hp - damage);
NotifyObservers();
}
void Heal(int amount)
{
hp = std::min(maxHp, hp + amount);
NotifyObservers();
}
int GetHp() const { return hp; }
int GetMaxHp() const { return maxHp; }
void Attach(Observer* obs) { observers.push_back(obs); }
void NotifyObservers()
{
for (auto* obs : observers) obs->Update();
}
};
// ============ View ============
class HUDView : public Observer
{
private:
PlayerModel* model;
UIWidget* hpBar;
public:
HUDView(PlayerModel* m) : model(m)
{
hpBar = new UIProgressBar(100, 20);
}
void Update() override
{
float hpPercent = (float)model->GetHp() / (float)model->GetMaxHp();
hpBar->SetProgress(hpPercent);
}
void Render() { hpBar->Draw(); }
};
// ============ Controller ============
class GameController
{
private:
PlayerModel* model;
HUDView* view;
public:
GameController(PlayerModel* m, HUDView* v) : model(m), view(v)
{
model->Attach(view);
}
void HandleInput(InputEvent event)
{
switch (event.type)
{
case InputType::KEY_F:
model->Heal(25);
break;
}
}
};
优缺点
| 优点 | 缺点 |
|---|---|
| 关注点分离清晰 | 视图与模型仍有耦合 |
| 可同时开发多部分 | 控制器可能变得臃肿 |
| 便于测试(Model独立) | 简单UI过度设计 |
| 广泛应用,资料丰富 | 视图更新机制复杂 |
7. MVP(模型-视图-展示器)
概述
MVP 是 MVC 的变体,由 Presenter 完全接管视图逻辑,View 接口化,Model 与 View 完全解耦。
架构对比
Presenter 核心实现
struct ItemData
{
std::string name;
int slotIndex;
int quantity;
bool isValid = false;
bool isUsable = false;
std::string GetDescription() const
{
return name + " x" + std::to_string(quantity);
}
};
class InventoryModel
{
private:
std::vector<ItemData> items;
public:
InventoryModel() : items(20)
{
for (int i = 0; i < 20; ++i) items[i].slotIndex = i;
}
ItemData GetItem(int slot) const
{
if (slot >= 0 && slot < (int)items.size() && items[slot].isValid)
return items[slot];
return ItemData{};
}
std::vector<ItemData> GetAllItems() const { return items; }
void RemoveItem(int slot)
{
if (slot >= 0 && slot < (int)items.size())
items[slot] = ItemData{};
}
};
// View 接口
class IInventoryView
{
public:
virtual ~IInventoryView() = default;
virtual void ShowItem(int slot, const ItemData& item) = 0;
virtual void ClearSlot(int slot) = 0;
virtual void HighlightSlot(int slot) = 0;
virtual void ShowTooltip(const std::string& text) = 0;
virtual void RefreshAll(const std::vector<ItemData>& items) = 0;
};
// Presenter:完全控制视图逻辑
class InventoryPresenter
{
private:
IInventoryView* view;
InventoryModel* model;
public:
void OnItemClicked(int slot)
{
ItemData item = model->GetItem(slot);
if (item.isValid) {
view->HighlightSlot(slot);
view->ShowTooltip(item.GetDescription());
}
}
void OnItemUsed(int slot)
{
if (model->GetItem(slot).isUsable)
{
model->RemoveItem(slot);
RefreshView();
}
}
private:
void RefreshView()
{
view->RefreshAll(model->GetAllItems());
}
};
优缺点
| 优点 | 缺点 |
|---|---|
| View完全与Model解耦 | Presenter变得庞大 |
| View易于替换和测试 | 接口数量多 |
| 测试性极佳(Mock View) | 简单场景过度抽象 |
8. MVVM(模型-视图-视图模型)
概述
MVVM 通过**数据绑定(Data Binding)**将 View 与 ViewModel 自动同步,ViewModel 暴露可观察的属性和命令。
架构图
ViewModel 实现
class ObservableObject
{
protected:
void OnPropertyChanged(const std::string& propName)
{
auto it = propertyListeners.find(propName);
if (it != propertyListeners.end())
{
for (auto& callback : it->second) callback();
}
}
public:
void BindProperty(const std::string& propName, std::function<void()> callback)
{
propertyListeners[propName].push_back(std::move(callback));
}
std::unordered_map<std::string, std::vector<std::function<void()>>> propertyListeners;
};
struct PlayerStatsModel
{
int baseHp = 100;
int currentHp = 100;
int maxHp = 100;
float mana = 50;
struct Equipment { std::string name; int hpBonus; };
std::vector<Equipment> equipment;
};
class PlayerViewModel : public ObservableObject
{
private:
PlayerStatsModel* model;
public:
std::string DisplayedHp;
std::string DisplayedMaxHp;
std::string DisplayedMana;
float HpPercent;
bool IsAlive;
std::function<void()> UseHealthPotion;
std::function<void(int)> EquipItem;
PlayerViewModel(PlayerStatsModel* m) : model(m)
{
UseHealthPotion = [this]()
{
model->currentHp = std::min(model->currentHp + 50, model->maxHp);
RefreshStats();
};
RefreshStats();
}
void RefreshStats()
{
int totalCurrentHp = model->currentHp;
int totalMaxHp = model->maxHp;
for (auto& eq : model->equipment) totalMaxHp += eq.hpBonus;
DisplayedHp = std::to_string(totalCurrentHp);
DisplayedMaxHp = std::to_string(totalMaxHp);
HpPercent = totalMaxHp > 0 ? (float)totalCurrentHp / (float)totalMaxHp : 0.0f;
IsAlive = totalCurrentHp > 0;
OnPropertyChanged("DisplayedHp");
OnPropertyChanged("DisplayedMaxHp");
OnPropertyChanged("HpPercent");
}
};
数据绑定
class UIBinder
{
public:
static void BindText(UILabel* label, PlayerViewModel* vm)
{
vm->BindProperty("DisplayedHp", [label, vm]() {
label->SetText(vm->DisplayedHp);
});
}
static void BindProgress(UIProgressBar* bar, PlayerViewModel* vm)
{
vm->BindProperty("HpPercent", [bar, vm]()
{
bar->SetProgress(vm->HpPercent);
});
}
};
优缺点
| 优点 | 缺点 |
|---|---|
| 双向数据绑定自动同步 | 数据绑定调试困难 |
| View与逻辑完全解耦 | 过度绑定导致性能问题 |
| 适合复杂UI交互 | 学习曲线较高 |
| 易于单元测试 | 内存泄漏风险(忘记解绑) |
游戏UI架构的实际情况
很多新人会以为"游戏UI一定用MVVM",实际上并非如此。
| 引擎/框架 | 官方推荐 | 项目实际 |
|---|---|---|
| UE UMG | MVVM(UE5.2 Experimental,UE5.3+逐渐成熟) | 大量项目用Widget+Controller,更接近MVP |
| Unity uGUI | 无限制 | MVC / MVP / MVVM 皆有 |
| Cocos Creator | 无限制 | 多为MVC变体 |
| 自研引擎 | 视团队而定 | 通常是混合体 |
实际工程中,MVC、MVP、MVVM往往是混合使用的,没有绝对界限。大型3A项目中自研UI框架的比例也不低(如GTA、巫师、战神等),并不一定使用MVVM。
9. Observer(观察者模式)与Event(事件系统)
概述
Observer模式和事件驱动架构是游戏系统间解耦通信的基础。UE中的Delegate/MulticastDelegate、各种事件总线都基于此。
观察者模式
C++ 实现
// ============ Observer 基类 ============
class Observer
{
public:
virtual ~Observer() = default;
virtual void OnNotify(const std::string& event, void* data) = 0;
virtual void Update() {}
};
// ============ Subject / 事件源 ============
class Subject
{
private:
std::vector<Observer*> observers;
public:
void Attach(Observer* obs) { observers.push_back(obs); }
void Detach(Observer* obs)
{
observers.erase(
std::remove(observers.begin(), observers.end(), obs),
observers.end());
}
void Notify(const std::string& event, void* data = nullptr)
{
for (auto* obs : observers)
{
obs->OnNotify(event, data);
}
}
};
// ============ UE风格:Delegate ============
template<typename... Args>
class MulticastDelegate
{
private:
std::vector<std::function<void(Args...)>> listeners;
public:
void AddListener(std::function<void(Args...)> callback)
{
listeners.push_back(std::move(callback));
}
void Broadcast(Args... args)
{
for (auto& listener : listeners)
{
listener(args...);
}
}
};
// 使用
MulticastDelegate<int> OnDamageTaken;
OnDamageTaken.AddListener([](int dmg)
{
// 更新血条
});
OnDamageTaken.AddListener([](int dmg)
{
// 播放受伤音效
});
OnDamageTaken.Broadcast(50);
事件驱动架构(Event Bus)
enum class EventType
{
DamageTaken, HealthChanged, PlayerDied,
EnemyKilled, ItemCollected, QuestUpdated,
GamePaused, GameSaved, LevelLoaded
};
struct Event
{
EventType type;
void* data = nullptr;
};
// ============ 事件总线(双缓冲队列) ============
class EventBus
{
private:
using EventHandler = std::function<void(const Event&)>;
std::unordered_map<EventType, std::vector<EventHandler>> listeners;
std::queue<Event> eventQueue;
std::queue<Event> pendingQueue;
public:
void Subscribe(EventType type, EventHandler handler)
{
listeners[type].push_back(handler);
}
void Publish(const Event& event)
{
auto it = listeners.find(event.type);
if (it != listeners.end())
{
for (auto& handler : it->second) handler(event);
}
}
void QueueEvent(const Event& event)
{
pendingQueue.push(event);
}
void DispatchQueuedEvents()
{
std::swap(eventQueue, pendingQueue);
while (!pendingQueue.empty())
{
pendingQueue.pop();
}
while (!eventQueue.empty())
{
Publish(eventQueue.front());
eventQueue.pop();
}
}
};
事件风暴(Event Storm)问题
事件驱动的主要性能问题不在于虚函数调用,而是:
- Cache Miss - 事件处理函数分散在不同内存位置
- 间接调用 - 函数指针/虚函数影响分支预测
- 事件风暴 - 单个事件触发链式反应,事件链路无限增长
优缺点
| 优点 | 缺点 |
|---|---|
| 系统间完全解耦 | 事件追踪困难 |
| 易于扩展新系统 | 循环事件风险 |
| 代码组织清晰 | 事件风暴(级联爆炸) |
| 支持异步处理 | 全局状态管理复杂 |
| 灵活的事件组合 | 调试困难(调用链不透明) |
10. FSM(有限状态机)
概述
FSM(Finite State Machine)是游戏AI和行为控制最经典的模式,实体在有限个状态间切换,每个状态有进入、更新、退出逻辑。
⚠️ 重要:FSM更适合作为局部行为控制器,而非整个AI系统。实际商业游戏中,FSM常与Behavior Tree、HFSM、Utility AI等组合使用。
状态图
状态转换表
enum class State
{
Idle, Chase, Attack, Flee, Patrol, Search, Alert
};
enum class Condition
{
EnemyDetected, InAttackRange, TargetLost,
TargetDead, LowHealth, SafeDistance
};
struct Transition
{
State from;
State to;
Condition condition;
};
std::vector<Transition> enemyTransitions =
{
{State::Idle, State::Chase, Condition::EnemyDetected},
{State::Chase, State::Attack, Condition::InAttackRange},
{State::Chase, State::Idle, Condition::TargetLost},
{State::Attack, State::Idle, Condition::TargetDead},
{State::Attack, State::Flee, Condition::LowHealth},
{State::Flee, State::Idle, Condition::SafeDistance},
};
优缺点
| 优点 | 缺点 |
|---|---|
| 简单直观,易于实现 | 状态爆炸(复杂行为) |
| 行为可预测 | 状态间耦合 |
| 调试容易(可见状态) | 难以表达并行状态 |
| 性能开销小 | 代码重复(共享逻辑) |
11. HFSM(分层有限状态机)
概述
HFSM(Hierarchical FSM)通过将状态组织成层次结构解决FSM的状态爆炸问题,子状态继承父状态的行为,支持嵌套和事件穿透。
层次结构
分层状态实现
class HierarchicalState
{
protected:
HierarchicalState* parentState = nullptr;
std::vector<std::unique_ptr<HierarchicalState>> children;
HierarchicalState* currentChild = nullptr;
std::string stateName;
public:
virtual ~HierarchicalState() = default;
virtual void Enter()
{
if (!children.empty() && !currentChild)
{
SetChildState(children[0].get());
}
}
virtual void Update(float dt)
{
if (currentChild) currentChild->Update(dt);
}
virtual void Exit()
{
if (currentChild)
{
currentChild->Exit();
currentChild = nullptr;
}
}
virtual bool HandleEvent(const GameEvent& event)
{
if (currentChild && currentChild->HandleEvent(event))
return true;
return false;
}
void SetChildState(HierarchicalState* child)
{
assert(std::find_if(children.begin(), children.end(),
[child](const auto& p) { return p.get() == child; })
!= children.end());
if (currentChild)
{
currentChild->Exit();
}
currentChild = child;
if (currentChild)
{
currentChild->Enter();
}
}
};
FSM vs HFSM 对比
优缺点
| 优点 | 缺点 |
|---|---|
| 减少状态数量 | 实现复杂度高 |
| 代码复用(父子共享) | 调试困难(嵌套层次) |
| 行为组织清晰 | 层次设计需要经验 |
| 易于扩展 | 状态穿透逻辑复杂 |
12. Behavior Tree(行为树)
概述
Behavior Tree(行为树)是现代商业游戏中最常见的高层AI决策架构之一,尤其常见于角色驱动型游戏(ACT、ARPG、TPS、FPS)。通常与FSM、HFSM等状态机结合使用。UE、Unity、Cocos等引擎均原生支持。
架构对比
一般商业项目中,Behavior Tree 与 FSM 最为常见,HFSM、Utility AI、GOAP通常作为补充方案。两者通常是结合使用的。
核心节点类型
行为树结构
C++ 实现
class Blackboard
{
private:
std::unordered_map<std::string, std::any> data;
public:
template<typename T>
void Set(const std::string& key, T value) { data[key] = value; }
template<typename T>
T Get(const std::string& key) const
{
return std::any_cast<T>(data.at(key));
}
};
// ============ 节点基类 ============
enum class Status { Success, Failure, Running };
class BTNode
{
public:
virtual ~BTNode() = default;
virtual Status Tick(Blackboard& bb, float dt) = 0;
};
// ============ 叶子节点 ============
class ConditionNode : public BTNode
{
private:
std::function<bool(Blackboard&)> condition;
public:
ConditionNode(std::function<bool(Blackboard&)> fn) : condition(std::move(fn)) {}
Status Tick(Blackboard& bb, float dt) override
{
return condition(bb) ? Status::Success : Status::Failure;
}
};
class ActionNode : public BTNode
{
private:
std::function<Status(Blackboard&, float)> action;
public:
ActionNode(std::function<Status(Blackboard&, float)> fn) : action(std::move(fn)) {}
Status Tick(Blackboard& bb, float dt) override
{
return action(bb, dt);
}
};
class Selector : public BTNode
{
private:
std::vector<std::unique_ptr<BTNode>> children;
public:
void AddChild(std::unique_ptr<BTNode> child)
{
children.push_back(std::move(child));
}
Status Tick(Blackboard& bb, float dt) override
{
for (size_t i = 0; i < children.size(); ++i) {
Status s = children[i]->Tick(bb, dt);
if (s != Status::Failure) return s;
}
return Status::Failure;
}
};
class Sequence : public BTNode
{
private:
std::vector<std::unique_ptr<BTNode>> children;
public:
void AddChild(std::unique_ptr<BTNode> child)
{
children.push_back(std::move(child));
}
Status Tick(Blackboard& bb, float dt) override
{
for (size_t i = 0; i < children.size(); ++i)
{
Status s = children[i]->Tick(bb, dt);
if (s != Status::Success) return s;
}
return Status::Success;
}
};
// ============ 装饰器 ============
class Inverter : public BTNode
{
private:
std::unique_ptr<BTNode> child;
public:
Status Tick(Blackboard& bb, float dt) override
{
Status s = child->Tick(bb, dt);
if (s == Status::Success) return Status::Failure;
if (s == Status::Failure) return Status::Success;
return Status::Running;
}
};
// ============ 行为树执行器 ============
class BehaviorTreeRunner
{
private:
std::unique_ptr<BTNode> root;
public:
BehaviorTreeRunner(std::unique_ptr<BTNode> r) : root(std::move(r)) {}
void Tick(Blackboard& bb, float dt)
{
if (root) root->Tick(bb, dt);
}
};
// ============ 构建行为树 ============
BehaviorTreeRunner BuildEnemyBT(Blackboard& bb)
{
auto root = std::make_unique<Selector>();
// 攻击分支
auto attackSeq = std::make_unique<Sequence>();
attackSeq->AddChild(std::make_unique<ConditionNode>(
[](Blackboard& b) { return b.Get<bool>("has_target"); }
));
attackSeq->AddChild(std::make_unique<ConditionNode>(
[](Blackboard& b) { return b.Get<float>("distance") < 5.0f; }
));
attackSeq->AddChild(std::make_unique<ActionNode>(
[](Blackboard& b, float) -> Status
{
// 执行攻击
return Status::Success;
}
));
// 追击分支
auto chaseSeq = std::make_unique<Sequence>();
chaseSeq->AddChild(std::make_unique<ConditionNode>(
[](Blackboard& b) { return b.Get<bool>("has_target"); }
));
chaseSeq->AddChild(std::make_unique<ActionNode>(
[](Blackboard& b, float dt) -> Status
{
// 追击目标
return Status::Running;
}
));
// 巡逻分支
auto patrolSeq = std::make_unique<Sequence>();
patrolSeq->AddChild(std::make_unique<ActionNode>(
[](Blackboard& b, float dt) -> Status
{
// 巡逻
return Status::Running;
}
));
root->AddChild(std::move(attackSeq));
root->AddChild(std::move(chaseSeq));
root->AddChild(std::move(patrolSeq));
return BehaviorTreeRunner(std::move(root));
}
Behavior Tree vs FSM
| 维度 | FSM | Behavior Tree |
|---|---|---|
| 状态管理 | 显式状态 | 隐式(节点状态) |
| 扩展性 | 状态爆炸 | 轻松添加分支 |
| 可读性 | 中等 | 可视化极佳 |
| 复用性 | 低 | 高(子树复用) |
| 调试 | 容易 | 可视化调试 |
| UE支持 | 动画状态机 | Behavior Tree + EQS |
优缺点
| 优点 | 缺点 |
|---|---|
| 可视化编辑,直觉性强 | 树结构可能过于复杂 |
| 模块化,子树可复用 | Running状态管理复杂 |
| 条件与动作分离 | 不适合高度动态规划 |
| UE/Unity原生支持 | 调试父子节点关系 |
| 适合复杂AI行为 | 内存占用相对较高 |
13. GOAP(目标导向行为规划)
概述
GOAP(Goal-Oriented Action Planning)是一种基于规划的AI架构,AI Agent 根据当前世界状态和目标,动态规划一系列动作来达成目标。
经典代表作:《FEAR》(F.E.A.R.)的AI系统。
架构图
核心数据结构
struct WorldStateBool
{
std::unordered_map<std::string, bool> bools;
};
struct WorldStateNumeric
{
std::unordered_map<std::string, float> values;
};
class GoapAction
{
public:
std::string name;
float cost;
WorldStateBool preconditions;
WorldStateBool effects;
bool inProgress = false;
float elapsedTime = 0;
virtual ~GoapAction() = default;
bool IsUsable(const WorldStateBool& state) const
{
for (auto& [key, value] : preconditions.bools)
{
auto it = state.bools.find(key);
if (it == state.bools.end() || it->second != value)
return false;
}
return true;
}
void ApplyEffects(WorldStateBool& state) const
{
for (auto& [key, value] : effects.bools)
{
state.bools[key] = value;
}
}
virtual bool Perform() = 0;
virtual float GetDuration() const { return 1.0f; }
};
规划器(A*)
class GoapPlanner
{
public:
std::vector<std::shared_ptr<GoapAction>> Plan(
const WorldStateBool& startState,
const Goal& goal,
const std::vector<std::shared_ptr<GoapAction>>& availableActions)
{
// A* 搜索最优动作序列
return {};
}
};
FSM vs GOAP 对比
优缺点
| 优点 | 缺点 |
|---|---|
| 高度灵活的动态行为 | 规划计算开销大 |
| 无需手动设计状态转换 | 复杂目标设计困难 |
| 适应性强(应对意外情况) | 调试困难 |
| 可复用动作组件 | 实时性要求高时可能卡顿 |
14. Utility AI(效用AI)
概述
Utility AI(效用AI)基于评分系统而非状态转换。AI Agent为每个行为计算一个效用值(Utility Score),选择最高分的行动执行。
公开资料中常见案例包括:《模拟人生》系列、《文明》系列等。注意《全面战争》系列实际上是Utility AI、Rule-Based与FSM的混合体。
核心思想
C++ 实现
class Curve
{
private:
std::function<float(float)> function;
public:
static Curve Linear()
{
return Curve{[](float x) { return std::clamp(x, 0.0f, 1.0f); }};
}
static Curve Logistic(float steepness = 4.0f)
{
return Curve{[steepness](float x)
{
return 1.0f / (1.0f + std::exp(-steepness * (x - 0.5f)));
}};
}
static Curve Exponential(float power = 2.0f)
{
return Curve{[power](float x)
{
return std::pow(std::clamp(x, 0.0f, 1.0f), power);
}};
}
float Evaluate(float input) const { return function(input); }
};
struct Consideration
{
std::function<float(Blackboard&)> inputGetter;
Curve curve;float weight;
float Score(Blackboard& bb) const
{
float rawInput = inputGetter(bb);
float mapped = curve.Evaluate(rawInput);
return mapped * weight;
}
};
struct UtilityAction
{
std::string name;
std::vector<Consideration> considerations;
float CalculateScore(Blackboard& bb) const
{
float score = 1.0f;
for (auto& c : considerations)
{
score *= c.Score(bb);
}
return score;
}
};
class UtilityAIAgent
{
private:
std::vector<UtilityAction> actions;
Blackboard& blackboard;
float evaluationInterval = 0.5f;
float timer = 0;
public:
void AddAction(UtilityAction action)
{
actions.push_back(std::move(action));
}
UtilityAction* SelectBestAction(float dt)
{
timer += dt;
if (timer < evaluationInterval) return nullptr;
timer = 0;
UtilityAction* bestAction = nullptr;
float bestScore = 0;
for (auto& action : actions)
{
float score = action.CalculateScore(blackboard);
if (score > bestScore)
{
bestScore = score;
bestAction = &action;
}
}
return bestAction;
}
};
void SetupAI(UtilityAIAgent& agent, Blackboard& bb) {UtilityAction attack;
attack.name = "Attack";
attack.considerations =
{
Consideration
{
[](Blackboard& b) { return 1.0f - b.Get<float>("distance") / 100.0f; },
Curve::Logistic(), 1.0f
},
Consideration
{
[](Blackboard& b) { return b.Get<float>("hp") / 100.0f; },
Curve::Linear(), 1.0f
},
Consideration
{
[](Blackboard& b) { return b.Get<int>("ammo") / 30.0f; },
Curve::Exponential(2.0f), 1.5f
}
};
UtilityAction flee;
flee.name = "Flee";
flee.considerations =
{
Consideration
{
[](Blackboard& b) { return 1.0f - b.Get<float>("hp") / 100.0f; },
Curve::Exponential(3.0f), 2.0f
}
};
agent.AddAction(std::move(attack));
agent.AddAction(std::move(flee));
}
FSM vs Utility AI
优缺点
| 优点 | 缺点 |
|---|---|
| 自然平滑的行为 | 调参困难(曲线调试) |
| 无硬编码状态转换 | 评分公式复杂 |
| 易于微调(修改曲线) | 难以预测行为 |
| 适合复杂决策 | 大量行为频繁评估时会产生额外CPU开销 |
| 《模拟人生》验证 | 极端情况难控制 |
15. 架构对比总结
分层架构体系
选择指南
综合对比表
| 架构 | 核心思想 | 适用场景 | 性能 | 复杂度 | 扩展性 |
|---|---|---|---|---|---|
| OOP | 继承+封装+多态 | 中小型、原型 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
| Component | 组合功能 | UE/Unity开发 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| DOP | 数据布局优化 | 大规模物理/粒子 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| ECS | 数据-逻辑分离 | 大型游戏、万人同屏 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Ability System | 数据驱动技能 | MMO/ARPG/MOBA | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| MVC | 三层分离 | UI、编辑器 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| MVP | 接口解耦 | 可测试UI | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| MVVM | 数据绑定 | 复杂UI | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Observer/Event | 发布-订阅 | 跨系统通信 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| FSM | 状态+转换 | 局部控制、动画 | ⭐⭐⭐⭐⭐ | ⭐ | ⭐ |
| HFSM | 层次化状态 | 复杂状态切换 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| Behavior Tree | 树节点组合 | 主流AI | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| GOAP | 动态规划 | 开放世界NPC | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Utility AI | 评分决策 | 策略/模拟游戏 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
商业游戏AI使用案例
⚠️ 不同品类游戏AI架构差异极大,不存在统一排名。以下仅列出有公开技术资料确认的案例。
| 游戏 | AI架构 | 来源 |
|---|---|---|
| FEAR | GOAP | GDC演讲(经典案例) |
| 模拟人生 | Utility AI | 官方文档 |
| 最后生还者 | HFSM + Behavior Tree | GDC演讲 |
实际项目推荐
// 1. 独立游戏 / 原型
class Enemy
{
HealthComponent* health;
MovementComponent* movement;
FiniteStateMachine ai;
};
// 2. 中大型商业项目
class GameWorld
{
std::vector<Actor*> actors;
BehaviorTreeRunner ai;
EventBus eventBus;
AbilitySystemComponent abilitySystem;
UIManager ui;
};
// 3. 3A级大型游戏
class TripleAGame
{
EntityComponentSystem ecs;
DataOrientedPipeline dop;
GameplayAbilitySystem gas;
BehaviorTreeSystem behaviorAI;
GoapSystem goap;
UtilitySystem utility;
EventBus eventBus;
std::unique_ptr<IUISystem> ui;
};
16. Unreal Engine 架构映射
概述
以下将前文介绍的架构模式映射到Unreal Engine的对应系统,帮助UE开发者快速定位和使用。
架构映射表
| 概念 | UE对应 | 说明 |
|---|---|---|
| OOP | UObject 体系 |
UE的根基,所有对象继承UObject,支持GC、序列化、反射 |
| Component | ActorComponent / UActorComponent |
每个Actor可挂载多个Component实现功能组合 |
| Observer | Delegate / MulticastDelegate |
单播/多播委托,支持动态绑定 |
| Event | GameplayMessageSubsystem |
UE5的Gameplay消息系统,模块间解耦通信 |
| FSM | Animation Blueprint(状态机) |
动画蓝图本质上是FSM,每个状态对应一个动画混合 |
| HFSM | StateTree(UE5.1+) |
UE5引入的层次化状态机,面向AI行为编排 |
| Behavior Tree | Behavior Tree + Blackboard + EQS |
UE原生BT系统,搭配EQS做环境查询,是官方主力AI方案 |
| GOAP | 无官方实现 | UE社区有GOAP插件,或需自研(基于A*规划) |
| Utility AI | 无官方实现 | UE社区有Utility AI插件,或需自研(评分曲线系统) |
| ECS | Mass Entity |
UE5的Mass框架,面向超大规模实体(万人同屏) |
| DOP | Mass + Niagara |
Mass的数据布局(Archetype/Chunk)、Niagara的粒子计算 |
| Ability System | GameplayAbilitySystem(GAS) |
UE官方技能系统插件,支持技能/Buff/Tag/属性 |
| MVVM | MVVM Plugin(UE5.2 Experimental,UE5.3+逐渐成熟) |
UE官方MVVM框架,此前大量项目自建MVP风格 |
| MVC/MVP | Widget + Controller |
大量UE4/UE5项目的UI架构风格,非官方强制 |
Mass ECS 架构简图
GAS 架构简图
StateTree vs Behavior Tree 对比
| 维度 | Behavior Tree | StateTree(UE5.1+) |
|---|---|---|
| 本质 | 树节点组合(类似决策树) | 层次化状态机(HFSM) |
| 状态管理 | 隐式(节点Running/Success/Failure) | 显式(状态间转换) |
| 适用 | 复杂AI行为决策 | 角色行为切换、战斗状态管理 |
| 事件 | 每帧Tick驱动 | 事件驱动+Tick混用 |
| 并行能力 | 需Parallel节点 | 支持同状态下多Task协同执行 |
| UE版本 | UE4+/UE5全支持 | UE5.1+ |
在UE5项目中,Behavior Tree + StateTree 可组合使用:BT负责高层决策,StateTree负责底层状态切换。两者并非替代关系。
UE项目架构推荐
// 1. 常规UE5项目(中小型)
class AMyCharacter : public ACharacter
{
UHealthComponent* Health;
UInventoryComponent* Inventory;
UBehaviorTree* BehaviorTree;
UBlackboardComponent* Blackboard;
UAbilitySystemComponent* AbilitySystem;
UAnimInstance* AnimInstance;
};
// 2. UE5大型项目(万人同屏场景)
class AMassGameMode : public AGameModeBase
{
UMassEntitySubsystem* MassEntity;
UBehaviorTreeComponent* BehaviorTree;
UAbilitySystemComponent* AbilitySystem;
UMVVMViewModelCollectionObject* ViewModels;
UGameplayMessageSubsystem* MessageSystem;
};
结语
游戏架构设计没有银弹,每个模式都有其适用场景:
核心原则
- 简单优先:能用FSM解决的问题不要上GOAP
- 数据驱动:性能问题需要数据说话,过早优化是万恶之源
- 为扩展留空间:架构要有弹性,但不要过度设计
- 团队匹配:团队熟悉度 > 架构先进性
- 混合为王:实际项目往往是多种模式的组合
分层思维
基础层: OOP + Component + Event (地基)
性能层: DOP + ECS/Mass (加速)
能力系统层: Ability System / GAS (技能)
UI层: MVC + MVP + MVVM (交互)
AI层: BT + FSM + Utility (智能)
“架构不是一步到位的,而是在迭代中演化的。”
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)