我正在尝试编写经典的蛇游戏。我有逻辑工作(吃饭,成长动作等)。现在我想添加一些漂亮的图形。到目前为止,我使用此代码制作了一些丑陋的图形: (伪代码)
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
}
}
Class Tileable表示Snakes地图上的对象 - &gt;苹果,墙甚至蛇本身。它存储物体位置,当蛇与物体碰撞时会发生什么等等 - &gt;逻辑。
BUT
如果苹果是圈子而不是矩形,那么它会很好吗?
所以我想添加类Drawable与方法.draw()和派生类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?
答案 0 :(得分: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中的数据来绘制每个实体的正确表示。