我正在尝试编写经典贪吃蛇游戏。我有逻辑工作(吃饭、成长、移动等)。现在我想添加一些漂亮的图形。到目前为止,我用这段代码制作了一些丑陋的图形: (伪代码)
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 map 上的对象 -> 苹果、墙壁甚至蛇本身。它存储对象位置,当蛇与对象碰撞时会发生什么 -> 逻辑。
但是
如果苹果是圆形而不是矩形会不会很好?
所以我想添加带有方法 .draw() 的类 Drawable 和派生类 DrawableSnake、DrawableApple、DrawableWall、DrawableWhatever,每个类都有自己的 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 的更好的方法来做到这一点?
最佳答案
这是设计游戏引擎的常见问题。解决此问题的一种方法是转向基于实体组件的系统。
苹果、墙和蛇都属于同一类——“实体”。对于每个实体,您将附加一个组件列表。在您的情况下,“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 的数据来绘制每个实体的正确表示。
关于c++ - 添加可绘制对象层以将逻辑与图形分开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12044903/