你好!
我试图在C ++编码模式中找到一些最佳解决方案,这是我的游戏引擎相关问题之一。
看看游戏对象声明(我删除了几乎所有与问题无关的内容)。
// Abstract representation of a game object
class Object :
public Entity,
IRenderable, ISerializable {
// Object parameters
// Other not really important stuff
public:
// @note Rendering template will never change while
// the object 'lives'
Object(RenderTemplate& render_template, /* params */) : /*...*/ { }
private:
// Object rendering template
RenderTemplate render_template;
public:
/**
* Default object render method
* Draws rendering template data at (X, Y) with (Width, Height) dimensions
*
* @note If no appropriate rendering method overload is specified
* for any derived class, this method is called
*
* @param Backend & b
* @return void
* @see
*/
virtual void Render(Backend& backend) const {
// Render sprite from object's
// rendering template structure
backend.RenderFromTemplate(
render_template,
x, y, width, height
);
}
};
这里还有 IRenderable 接口声明:
// Objects that can be rendered
interface IRenderable {
/**
* Abstract method to render current object
*
* @param Backend & b
* @return void
* @see
*/
virtual void Render(Backend& b) const = 0;
}
以及从Object
派生的真实对象样本(严格简化:)
// Ball object
class Ball : public Object {
// Ball params
public:
virtual void Render(Backend& b) const {
b.RenderEllipse(/*params*/);
}
};
我想得到的是能够拥有某种标准函数,如果没有适当的重载,它将为对象绘制精灵(这是Object::Render
)。
因此,可以使用没有Render(...)
方法的对象,如果尝试渲染它们,则会调用此默认的精灵渲染内容。而且,人们可以拥有专门的对象,这些对象定义了他们自己的渲染方式。
我认为,这种做事方式非常好,但我无法弄清楚 -
有没有办法从渲染实现中拆分对象的“普通”方法(如Resize(...)
或Rotate(...)
)实现?
因为如果一切都按照前面描述的方式完成,实现任何类型的对象的常见.cpp文件通常会混合Resize(...)
等方法实现和这个virtual Render(...)
方法,这似乎一团糟我实际上希望在一个地方拥有对象的渲染过程,在另一个地方拥有“逻辑实现”。
有没有办法可以做到这一点(可能是替代模式或技巧或提示)或者这就是所有这些多态和虚拟的东西在代码放置方面很糟糕?
答案 0 :(得分:2)
将IRenderable拉离Entity并仅在需要时从该接口继承。
然后使用访客:
struct rendering_visitor : visitor<Entity>, visitor<IRenderable>
{
void visit(Entity & e) { ... do default stuff ... }
void visit(IRenderable & renderable) { renderable.Render(); }
};
请参阅“Modern C ++ Design”以获得良好的访问者实现。您的可渲染物也需要可访问,您的实体也是如此。你已经有了一些高层次的建议,推荐的书没有谈到,但也不难理解。
还有其他方法可以实现访问者。随便挑选。
答案 1 :(得分:2)
在这个特定示例中,我不确定是否需要将Resize
与Render
分开,因为Resize
会对渲染图像产生直接影响。
我这样做的方法是让Entity
s 包含 Renderable
。例如。 Entity
会有一个成员变量,它是要渲染的精灵。当实体变得可见时,它会将精灵交给渲染系统,并且基本上说“好好画每个帧直到我告诉你停止”,尽管渲染引擎会剔除屏幕外对象和其他疯狂。显然,渲染引擎可能会维护一个可渲染事物列表(如果你想从线条或粒子中分割精灵以提高渲染效率,那么它可能会保留一些列表),然后它就会通过那些不那么复杂的项目清单来维护它们。做抽奖。
这样,实体可以控制可渲染,它可以缩放或旋转它(即操纵它的渲染矩阵),但它不需要决定何时适合绘制它是否“活着”。但是,渲染引擎只知道如何绘制有问题的项目,并且不需要了解实体图形。