0

我正在尝试编写经典的蛇游戏。我有逻辑工作(吃饭,成长移动等)。现在我想添加一些漂亮的图形。到目前为止,我用这段代码制作了一些丑陋的图形:(伪代码)

void drawWorld(const std::vector<Tileable*> world_map) {
    for each Tileable {
         get position of Tileable
         get color of Tileable
         draw rectangle at position with color
    }
}

Tileable 类表示 Snakes 地图上的对象 -> 苹果、墙壁甚至是蛇本身。它存储对象的位置,当蛇与对象等碰撞时会发生什么-> 逻辑。

如果苹果是圆形而不是矩形会更好吗?

所以我想用方法 .draw() 和派生类 DrawableSnake、DrawableApple、DrawableWall、DrawableWhatever 添加类 Drawable,每个类都有自己的 draw() 方法。问题是将 Tielable 子类从集合 world_map 转换为 Drawable 的适当子类,以具有如下内容:

void drawWorld(const std::vector<Tileable*> world_map) {
    for each Tileable {
         get drawable from tileable
         drawable.draw()
    }
}

我正在考虑使用带有 RTTI 的工厂之类的东西:(伪代码)

Drawable convertToDrawable(Tileable* tileable){
     if tileable is Apple return DrawableApple
     if tileable is Wall return DrawableWall
     etc.
}

有没有更好的方法来做到这一点,而不使用 RTTI?

4

1 回答 1

2

这是设计游戏引擎时的常见问题。解决此问题的一种方法是迁移到基于实体组件的系统。

苹果、墙壁和蛇都属于同一类——“实体”。对于每个实体,您将附加一个组件列表。在您的情况下,“ComponentDrawable”可能是一个组件,而“ComponentTileable”可能是另一个。当您创建实体时,您使用绘制该特定实体所需的数据初始化 ComponentDrawable。

您需要一种从实体中获取特定类型组件的方法。一个简单的系统可以让每个实体都有一个组件指针数组。每个组件类型在该数组中都有一个唯一的索引。数组中的空槽将具有 NULL 值。

template<typename T> T* getComponent( Entity *entity ) {
    entity.component_array[T::index]
}

然后,您修改后的伪代码示例将最终看起来像这样:

void drawWorld(const std::vector<Entity*> world_map) {
    for each entity in world_map {
         ComponentDrawable *drawable = getComponent<ComponentDrawable>( entity )
         if( drawable )
             drawable->draw()
    }
}

有些人喜欢将功能保留在组件之外,只将它们用作数据的载体。如果您想走这条路,那么数据驱动系统可以使用来自 ComponentDrawable 的数据来绘制每个实体的正确表示。

于 2012-08-21T00:53:15.810 回答