我正在尝试构建一个我用 C++ 编写的游戏作为实体/组件系统(基本思想是我会有一组代表不同类型数据的“实体”类和一组“组件”表示给定实体可能具有的各种行为的类)。我想使用组件的虚拟基类来实现它。例如,我可以有一个 Character
实体:
class Character {
public:
int armor;
int health;
std::string name;
};
还有一个 Fighter
组件代表可以使用近战武器的东西:
class Fighter {
public:
int damage;
virtual Direction attack() = 0;
}
和一个 Mage
组件代表可以施法的东西
class Mage {
public:
std::vector<Spell> spellList;
virtual Spell cast() = 0;
}
使用多重继承来使用这些,我会
class ElvenMage : Character, Mage {
public:
ElvenMage() {
this->armor = 0;
this->health = 10;
this->name = "elven mage";
this->spellList = ...;
}
virtual Spell cast() {
// some AI logic to figure out which spell to cast
}
};
和
class Player : Character, Fighter, Mage {
public:
Player() {
this->armor = 5;
this->health = 20;
this->name = "Player";
}
virtual Direction attack() {
// some logic to handle player melee input
}
virtual Spell cast() {
// some logic to handle player spell casting input
}
};
要跟踪 map 上的所有当前字符,我可以做类似的事情
class Engine {
public:
std::vector<std::unique_ptr<Character>> characters;
我必须将它们直接存储为 Characters
(而不是 Fighters
或 Mages
),但我需要分别处理战士和法师(例如,遍历所有 Characters
,如果他们可以施法,他们就会施法,否则他们会使用近战武器攻击)。在实际的游戏逻辑中,我如何区分同时实现 Mage
的 Character
实例与同时实现 Character
的实例 斗士
?
是否有一种简单的方法可以完成我正在尝试做的事情,或者我应该完全重新考虑我的设计?
(注意:这不是实际代码;在现实世界中,我实际上会使用工厂或其他东西来创建 Sprite 或其他任何东西,而不是尝试将所有信息放入构造函数中,而且我可能会将逻辑不同,但它说明了我遇到的问题)。
最佳答案
您可以使用 visitor pattern在你的引擎中:
每个字符都将覆盖 Character
类的纯虚拟接受方法。
class Engine;
class Spell {};
class Direction {};
class Character {
public:
virtual void accept(Engine& engine) = 0;
};
class Fighter {
public:
virtual Direction attack() = 0;
};
class Mage {
public:
virtual Spell cast() = 0;
};
继承 Mage
和 Fighter
中的 Character
将包含更少的样板代码。如果你想坚持你的继承形式,你需要在每个字符中提供 accept
方法的重载,它只是调用 的
:visit
函数引擎
class ElvenMage : public Character, Mage {
public:
ElvenMage() {}
virtual Spell cast() {
std::cout << "Casting from ElvenMage"
<< "\n";
return Spell{};
}
void accept(Engine& visitor) override { visitor.visit(*this); }
};
class Player : public Character, Fighter, Mage {
public:
Player() {}
virtual Direction attack() {
std::cout << "Attacking from Player"
<< "\n";
return Direction{};
}
virtual Spell cast() {
std::cout << "Casting from Player"
<< "\n";
return Spell{};
}
void accept(Engine& visitor) override {
// cast to Player if it should attack instead of casting
visitor.visit(static_cast<Mage&>(*this));
}
};
visit
方法是魔法发生的地方:
class Engine {
std::vector<std::unique_ptr<Character>> characters;
void do_stuff_with_spell(Spell spell) {
// ...
}
void do_stuff_with_attack(Direction direction) {
// ...
}
public:
void visit(Mage& mage) { do_stuff_with_spell(mage.cast()); }
void visit(Player& player) { do_stuff_with_attack(player.attack()); }
};
请注意,我在上面的代码中存在循环依赖,应该在拆分声明和定义时解决。
关于c++ - 是否可以使用继承在 C++ 中实现 ECS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56660747/