另一个与设计相关的C ++问题

时间:2010-04-21 20:45:37

标签: c++ polymorphism virtual design-patterns

你好!

我试图在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(...)方法,这似乎一团糟我实际上希望在一个地方拥有对象的渲染过程,在另一个地方拥有“逻辑实现”。

有没有办法可以做到这一点(可能是替代模式或技巧或提示)或者这就是所有这些多态虚拟的东西在代码放置方面很糟糕?

2 个答案:

答案 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)

在这个特定示例中,我不确定是否需要将ResizeRender分开,因为Resize会对渲染图像产生直接影响。

我这样做的方法是让Entity s 包含 Renderable。例如。 Entity会有一个成员变量,它是要渲染的精灵。当实体变得可见时,它会将精灵交给渲染系统,并且基本上说“好好画每个帧直到我告诉你停止”,尽管渲染引擎会剔除屏幕外对象和其他疯狂。显然,渲染引擎可能会维护一个可渲染事物列表(如果你想从线条或粒子中分割精灵以提高渲染效率,那么它可能会保留一些列表),然后它就会通过那些不那么复杂的项目清单来维护它们。做抽奖。

这样,实体可以控制可渲染,它可以缩放或旋转它(即操纵它的渲染矩阵),但它不需要决定何时适合绘制它是否“活着”。但是,渲染引擎只知道如何绘制有问题的项目,并且不需要了解实体图形。