在运行时创建Command对象

MasterReDWinD

我正在尝试为游戏引擎编写一个控制台,这将允许我键入命令来执行任务,例如更改地图,生成敌人等。

我一直在尝试使用Command模式(遵循来自gameprogrammingpatterns.com的示例)。有关我当前代码结构的概述,请参见下文。

parseCommand处理string来自用户的,在提取命令名和参数(目前仅使用空白分离)。下一步是我遇到的困难。我需要创建Command*某种调用方式execute,但是我只有string命令名称。

if我的parseCommand函数中可能有很多语句,例如:

if (cmdName == "spawn")
   return new SpawnEnemyCommand();

或者,我可以在Console类中存储指向每个命令的指针,例如Command *spawnNewEnemy = new SpawnNewEnemy();,然后在parseCommanddo中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_mapstd::map),可以为对象设计带有动态注册表的工厂std::stringCommandCommand

首先,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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类常见问题

如何在运行时使用LambdaMetaFactory创建代理对象?

来自分类Dev

在运行时动态创建类

来自分类Dev

使对象在运行时不可变

来自分类Dev

OpenGLES-在运行时创建对象

来自分类Dev

在运行时创建的访问控制

来自分类Dev

在运行时从Scala源代码创建可序列化的对象

来自分类Dev

在运行时过程性地创建和命名对象

来自分类Dev

在运行时快速创建函数

来自分类Dev

在运行时创建Tasklet

来自分类Dev

DevExpress WebChartControl在运行时创建

来自分类Dev

在运行时创建字段

来自分类Dev

在运行时更改注入的对象

来自分类Dev

在运行时无法投射对象

来自分类Dev

在运行时创建DEEP不可变对象

来自分类Dev

在运行时创建Spock测试

来自分类Dev

在运行时从动态加载的dll创建对象列表

来自分类Dev

在运行时创建对象?

来自分类Dev

在运行时替换QWidget对象

来自分类Dev

django在运行时创建信号

来自分类Dev

Android-使用Dagger在运行时创建对象

来自分类Dev

在运行时创建对象并使用它们

来自分类Dev

在运行时添加对象?

来自分类Dev

使对象在运行时不可访问

来自分类Dev

在运行时创建的对象上的双击事件-Delphi

来自分类Dev

在运行时创建UI元素

来自分类Dev

在运行时创建并填充 ImageList

来自分类Dev

Javascript:在运行时创建函数

来自分类Dev

选择在运行时创建的组件

来自分类Dev

在运行时创建字典