我正在尝试为游戏引擎编写一个控制台,这将允许我键入命令来执行任务,例如更改地图,生成敌人等。
我一直在尝试使用Command模式(遵循来自gameprogrammingpatterns.com的示例)。有关我当前代码结构的概述,请参见下文。
parseCommand
处理string
来自用户的,在提取命令名和参数(目前仅使用空白分离)。下一步是我遇到的困难。我需要创建Command*
某种调用方式execute
,但是我只有string
命令的名称。
if
我的parseCommand
函数中可能有很多语句,例如:
if (cmdName == "spawn")
return new SpawnEnemyCommand();
或者,我可以在Console
类中存储指向每个命令的指针,例如Command *spawnNewEnemy = new SpawnNewEnemy();
,然后在parseCommand
do中if (cmdName == "spawn") spawnNewEnemy->execute();
。第二个选择似乎是gameprogrammingpatterns本书的工作方式。
如果最终得到数百个控制台命令,这些选项似乎都不实用。我已经研究了关于此模式的所有文章和帖子,但这无助于为我澄清情况。
如何Command
从内部干净地实例化正确的对象parseCommand
?
命令界面基类:
class Command {
public:
virtual ~Command() { }
virtual void execute() = 0;
};
接口实现示例:
class SpawnEnemyCommand : public Command {
public:
void execute() {
// method calls to perform command go here
}
};
控制台类头:
class Console {
public:
Command* parseCommand(std::string);
bool validateCommand(std::string, std::vector<std::string>);
};
通过依靠将命令标识符(即对象)映射到对象的字典(例如std::unordered_map
或std::map
),可以为对象设计带有动态注册表的工厂。std::string
Command
Command
首先,Command
通过包含另一个虚拟成员函数扩展clone()
,该函数允许我们实现原型模式:
class Command {
public:
// ...
virtual std::unique_ptr<Command> clone() const = 0;
};
该clone()
虚成员函数做什么它的名字所暗示的:它克隆的对象。也就是说,SpawnEnemyCommand
将以Command::clone()
以下方式覆盖:
class SpawnEnemyCommand : public Command {
public:
// ...
std::unique_ptr<Command> clone() const override {
// simply create a copy of itself
return std::make_unique<SpawnEnemyCommand>(*this);
}
};
这样,您的命令对象可以通过界面进行多态复制Command
-即,您无需知道要复制的命令的具体类型。复制Command
对象所需要做的就是调用其clone()
虚拟成员函数。例如,以下函数将Command
传递的参数作为参数复制,而不管底层的具体类型如何:
std::unique_ptr<Command> CopyCommand(const Command& cmd) {
return cmd.clone();
}
考虑到这一点,您准备为命令对象设计工厂,该工厂CommandFactory
支持动态注册命令对象:
class CommandFactory {
public:
void registerCommand(std::string id, std::unique_ptr<Command>);
std::unique_ptr<Command> createCommand(std::string id) const;
private:
std::unordered_map<std::string, std::unique_ptr<Command>> registry_;
};
一切归结为一个std::unordered_map<std::string, std::unique_ptr<Command>>
数据成员。通过命令标识符索引该数据成员,该命令标识符为std::string
,我们检索一个Command
对象–这是我们将用于克隆的原型对象。
该registerCommand()
成员函数添加Command
原型到注册表:
void CommandFactory::registerCommand(std::string cmdId, std::unique_ptr<Command> cmd) {
registry_[cmdId] = std::move(cmd);
}
的createCommand()
成员函数的克隆Command
对应于请求命令标识符原型:
std::unique_ptr<Command> CommandFactory::createCommand(std::string cmdId) const {
auto const it = registry_.find(cmdId);
if (it == registry_.end())
return nullptr; // no such a command in the registry
auto const& cmdPtr = it->second;
return cmdPtr->clone();
}
作为示例程序:
auto main() -> int {
CommandFactory factory;
factory.registerCommand("spawn", std::make_unique<SpawnEnemyCommand>());
// ...
auto cmdPtr = factory.createCommand("spawn");
cmdPtr->execute();
}
您还可以扩展该工厂,以添加对动态注销已注册Command
原型的支持。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句