43
\$\begingroup\$

I am very new to game development, but not to programming.

I am (again) playing around with a Pong type game using JavaScript's canvas element.

I have created a Paddle object which has the following properties...

  • width
  • height
  • x
  • y
  • colour

I also have a Pong object which has properties such as...

  • width
  • height
  • backgroundColour
  • draw().

The draw() method currently is resetting the canvas and that is where a question came up.

Should the Paddle object have a draw() method responsible for its drawing, or should the draw() of the Pong object be responsible for drawing its actors (I assume that is the correct term, please correct me if I'm incorrect).

I figured that it would be advantagous for the Paddle to draw itself, as I instantiate two objects, Player and Enemy. If it were not in the Pong's draw(), I'd need to write similar code twice.

What is the best practice here?

Thanks.

\$\endgroup\$
1

5 Answers 5

52
\$\begingroup\$

Having actors draw themselves is not a good design, for two main reasons:

1) it violates the single responsibility principle, as those actors presumably had another job to do before you shoved render code into them.

2) it makes extension difficult; if every actor type implements its own drawing, and you need to change the way you draw in general, you may have to modify a lot of code. Avoiding overuse of inheritance can alleviate this to some extent, but not completely.

It's better for your renderer to be handling the drawing. After all, that's what it means to be a renderer. The renderer's draw method should take a "render description" object, which contains everything you need to render a thing. References to (probably shared) geometry data, instance-specific transformations or material properties such as color, et cetera. It then draws that, and doesn't care what that render description is supposed to "be."

Your actors can then hold on to a render description they create themselves. Since actors are typically logic processing types, they can push state changes to the render description as needed -- for example, when an actor takes damage it could set the color of its render description to red to indicate this.

Then you can simply iterate every visible actor, enqeue their render descriptions into the renderer, and let it do its thing (basically; you could generalize this even further).

\$\endgroup\$
4
  • 15
    \$\begingroup\$ +1 for "renderer drawing code," but -1 for single responsibility principle, which has done programmers more harm than good. It's got the right idea (separation of concerns), but the way it's stated ("every class should have only one responsibility, and/or only one reason to change") is simply wrong. \$\endgroup\$ Jun 25, 2011 at 5:46
  • 3
    \$\begingroup\$ -1 for 1), as BlueRaja pointed out, this principle is idealist, but not practical. -1 for 2) because it doesn't make extension significantly more difficult. If you have to change your entire rendering engine, you're going to have a lot more code to change than what little you have in your actor code. I would much prefer actor.draw(renderer,x,y) than renderer.draw(actor.getAttribs(),x,y). \$\endgroup\$
    – corsiKa
    Jun 25, 2011 at 6:18
  • 3
    \$\begingroup\$ Good answer! Well "You shall not violate the single responsibility principle" is not inside my decalogue, but is still a good principle to take into account \$\endgroup\$
    – FxIII
    Jun 25, 2011 at 22:31
  • \$\begingroup\$ @glowcoder Thats not the point, you can maintain actor.draw(), which is defined as { renderer.draw(mesh, attribs, transform); }. In OpenGL, I maintain a struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; } more or less for my renderer. That way the renderer doesn't care what the data represents, it just processes it. Based on this information, I can then also decide whether to sort the order of the draw calls to reduce overall GPU calls. \$\endgroup\$ Jul 1, 2011 at 2:58
18
\$\begingroup\$

The Visitor Pattern can be useful here.

What you can do is have a Renderer interface that knows how to draw each object and a "draw yourself" method in each actor that determines which (specific) renderer method to call, e.g.

interface Renderer {
    void drawPaddle(Player owner, Rectangle position);
    // Note: the Renderer chooses the Color based on which player the paddle belongs to

    // Also drawBackground, drawBall etc.
}

interface Actor {
    void draw(Renderer renderer);
}

class Paddle implements Actor {
    void draw(Renderer renderer) {
        renderer.drawPaddle(this.owner, this.getBounds());
    }
}

This way it is still easy to port to another graphics library or framework (I once ported a game from Swing/Java2D to LWJGL and was very glad I had used this pattern instead of passing a Graphics2D around.)

There is another advantage: The renderer can be tested separately from any actor code

\$\endgroup\$
2
\$\begingroup\$

In your example you'd want to have the Pong objects implement draw() and render themselves.

Though you won't notice any significant gains in a project of this size, generally separating game logic and their visual representation (rendering) is a worthwhile activity.

By this I mean you'd have your game objects that can be update()'d but they have no idea of how they're rendered, they're concerned only with the simulation.

Then you'd have a PongRenderer() class that has a reference to a Pong object, and it then takes charge of rendering the Pong() class, this could involve rendering the Paddles, or having a PaddleRenderer class to take care of it.

The separation of concerns in this case is a fairly natural one meaning your classes can be less bloated, and it's easier to modify how things are rendered, it no longer has to follow the hierarchy that your simulation does.

\$\endgroup\$
-1
\$\begingroup\$

If you were to do it in the Pong's draw(), you wouldnt' need to duplicate the code -- simply call the Paddle's draw() function for each of your paddles. So in your Pong's draw() you'd have

humanPaddle.draw();
compPaddle.draw();
\$\endgroup\$
0
-1
\$\begingroup\$

Every object should contain its own draw function which should be called by the game update code or draw code . Like

class X
{
  public void Draw( )
  {
     // Do something 
  } 
}

class Y
{
  public void Draw( )
   { // Do Something 
   } 
}

class Game
{
  X objX;
  Y objY;

  @Override
  public void OnDraw( )
  {
      objX.Draw( );
      objY.Draw( ); 
  } 
}

This is not a code but just for showing , how drawing objects should be done.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ This is not "How drawing should be done" but a single way of doing it. As mentioned in previous answers, this method has some flaws and few benefits, whilst other patterns have significant benefits and flexibilities. \$\endgroup\$
    – Troyseph
    Dec 4, 2015 at 9:56
  • \$\begingroup\$ I appreciate but since a simple example was to be given of the various ways of drawing actors in the scene , i mentioned this way. \$\endgroup\$
    – user43609
    Dec 4, 2015 at 17:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .