如何 efficiently/properly 为等距游戏存储 类 (单个超类的所有子类型)的地图?

How to efficiently/properly store a map of varying classes (all subtypes of a single superclass) for an isometric game?

在过去的几周里,我一直在尝试在业余时间开发一个等距的、基于图块的大亨风格的制作游戏(实际上只是为了看看我是否有能力)并且我 运行 面对我正在努力应对的设计挑战。我已经使用 Tile class(保存在 Map class 中)成功地实现了地砖并绘制它们等等,但我现在希望能够在地砖上添加对象。

我已经能够使用相当笨拙的调试 class 创建和渲染对象(如 table),包含在地图 class 中作为 std::map<int, Object>并为对象提供 X/Y 坐标,以便地图可以将它们呈现在正确的位置。所有这一切,虽然可能不是最好的方法,但在我尝试 subclass 对象以赋予它们不同的功能之前一直有效。

我曾(错误地)假设我能够为地图上的所有对象提供某种异构容器,我可以在游戏期间循环遍历它和 运行 对象类型特定的逻辑环形。我还没有完全确定游戏的范围,所以目前我只是给不同的对象不同的成员变量——比如一个有容量的容器对象,一个有能量等级的加热器对象,等等。我的第一个测试是能够将项目放置在地图上,然后能够查询容器对象的所有容量的总和 - 只是为了确保它在继续下一步之前有效.

我一直在尝试使用 OpenTTD 和一些 Habbo Hotel 模拟器等开源项目来解决所有这些问题,但无济于事。我很想听听其他人认为解决这个问题的最佳方法是什么。

我已经尝试 dynamic_cast 在我的地图中使用指针,但从我看到的其他答案来看,这似乎不是一个特别好的方法。我是否应该创建一个相同类型的对象池,然后在游戏循环期间遍历每个池以使事情变得更简单?

std::map<int, std::unique_ptr<Object>>

可能就是您所需要的。如果你的 Object API 是干净的,你不应该需要 dynamic_casts。例如你应该可以使用:

for(auto x : objects)
{
    x->draw();
    x->simulate();
}

标准解决方案是将它们存储为指向具体对象的基 class 的指针。

如果你有

class IObject
{
public:
    virtual void render() const = 0;
    virtual ~IObject(){}
};

你可以

int main()
{
    using IObjectUP = std::unique_ptr<IObject>;
    std::map<int, IObjectUP> m;

    // some concrete objects get created

    for (const auto& [_, o] : m)
        o->render();
}

std::unique_ptr 的使用假定所有权。如果其他人拥有您可以使用 std::shared_ptrstd::weak_ptrstd::reference_wrapper 的对象。

还有一件事。 std::vector 是默认容器。如果 std::map 没有充分的理由,请使用 std::vector.

你有几个选择。

第一个是std::any/boost::any (before C++17)。如果您的对象完全没有共同点,这将很有用。

另一种选择是使用通用接口:

class Object {
    public:
       virtual void func() {};

};

并从该接口继承:

class A : public Object {
    public:
        void func() {/*my overload*/}
};

这样,您就可以将它们存储在这样的容器中:

Object* obj = new A;
std::map<int, Object*> myMap;

myMap[0] = obj;

并像这样得到它:

myMap[0]->func(); // get the overloaded version

当然,您需要 delete obj 当您以这种方式完成后:

delete obj;

需要注意的是,如果你delete时它仍然设置为obj,这将使myMap[0]失效。这是我不一定推荐这样做的原因之一(std::any 如果你可以使用它会更好),但如果你想使用它就在那里。

当然,你总是可以使用智能指针代替,如@.