我正在尝试实现某种“仅仅为我”的游戏引擎,问题的情节如下:
假设我有一个可渲染实体的抽象接口,例如IRenderable
。
它的声明如下:
interface IRenderable {
// (...)
// Suppose that Backend is some abstract backend used
// for rendering, and it's implementation is not important
virtual void Render(Backend& backend) = 0;
};
我现在正在做的事情就像宣布像
这样的不同类class Ball : public IRenderable {
virtual void Render(Backend& backend) {
// Rendering implementation, that is specific for
// the Ball object
// (...)
}
};
然后一切都很好。我可以轻松地执行std::vector<IRenderable*> items
之类的操作,在此向量中推送new Ball()
之类的项目,然后拨打与foreach (IRenderable* in items) { item->Render(backend); }
类似的电话
好吧,我想这是'多态'的方式,但是如果我想在我的游戏中拥有不同类型的对象并且能够操纵它们的状态,那么每个对象都可以通过它自己的界面进行操作呢?
我可以做类似
的事情struct GameState {
Ball ball;
Bonus bonus;
// (...)
};
然后通过自己的方法轻松更改对象状态,例如ball.Move(...)
或bonus.Activate(...)
,其中Move(...)
仅适用于Ball
和Activate(...)
- 只有Bonus
个实例。
但在这种情况下,我失去了写foreach IRenderable*
的机会,因为我将这些球和奖金存储为派生的实例,而不是基类。在这种情况下,渲染过程变得像
ball.Render(backend);
bonus.Render(backend);
// (...)
并且它很糟糕,因为我们实际上以这种方式失去了多态性(没有实际需要使Render
函数虚拟等等。
另一种方法意味着通过dynamic_cast
调用向下转换或使用typeid
来调用你想要操作的对象的类型,这对我来说更糟糕,这也打破了这种“多态”的想法。
所以,我的问题是 - 是否有某种(可能)替代方法可以做我想做的事情,或者我的当前模式可以以某种方式进行修改,以便我实际存储IRenderable*
对于我的游戏对象(以便我可以在每个对象上调用虚拟Render
方法),同时保留轻松更改这些对象状态的能力?
也许我从一开始就做了一些绝对错误的事情,如果有的话,请指出:)
提前致谢!
答案 0 :(得分:3)
将不同对象存储为类成员的事实不应妨碍您在IRenderable*
向量中存储指针。
struct GameState {
Ball ball;
Bonus bonus;
vector<IRenderable*> m_items;
GameState() // constructor
{
m_items.push_back(&ball);
m_items.push_back(&bonus);
}
};
这样你也不必担心释放m_items
中的指针。当GameState
被销毁时,它们将被自动销毁。
另外,你的foreach语法很时髦。
答案 1 :(得分:2)
您的游戏引擎中应该有真正独立的子系统。一个用于渲染,另一个用于游戏逻辑。您的图形子系统应该有一个指向IRenderable对象的指针列表。您的游戏逻辑子系统应该有自己的对象列表和另一个界面。
现在您可以轻松拥有具有状态但无法呈现的实体等等。您甚至可能有一个单独的音频子系统。这也应该有助于保持代码清洁和模块化。
答案 2 :(得分:1)
我不是c ++程序员,但希望人造代码会有所帮助......
Class Renderable具有Render
功能Class Movable继承自Renderable,还具有x,y,z等属性以及Move
等功能Class Ball继承自Movable
现在你的游戏状态可以有一个可渲染对象列表,当渲染时,它可以循环遍历它们。
其他操作,例如世界时钟的刻度,可能会循环查找作为Moveable实例的对象并告诉他们更新。
如果您的奖金是可渲染的(我无法从您的问题中确定),那么它可以将Collectable子类化为子类Moveable。