4

I have a small responsibility separation issue that I hope someone can clarify. I have a small model composed by 2 classes: GameBoard and GamePiece, and the obvious relationship is that a GameBoard can have several GamePieces.

In the application I'm implementing, GameBoard and GamePiece contain data related to rendering in the screen (Update/Draw methods, Textures, etc) as well as their logic (gameboard number of squares, pieceType, etc). Updating/Drawing the GameBoard causes to update/draw the pieces as well. However, in order to keep the single responsibility principle, I decided to separate the logic from the rendering. But I have some troubles to implement it adequately.

I came up to a couple of solutions and I'm not sure which one is the best:

1- Create GameBoardRenderer and GamePieceRenderer classes (who would store Textures, updating and drawing), and every instance these Renderer classes would be related to one GameBoard or GamePiece respectively. The problem I see is that it forces me to keep a dual relationship between GameBoard and GamePiece, and GameBoardRenderer and GamePieceRenderer, and ensure that it is always consistent.

2- Create GameBoardRenderer and GamePieceRenderer, but make them inherit from GameBoard and GamePiece respectively, bringing all the rendering stuff to those classes, while keeping the association at the GameBoard and GamePiece classes. The problem is that when I call the Update/Draw method of GameBoard, I won't be able to call the GamePieceRenderer Update and Draw method (as no relationship will be available).

What should I do? Is there any better solution?

Thank you very much.

2

By the sound of it, this looks like a case where the Visitor patterns comes in handy.

Within this pattern, the GameBoard and GamePiece classes contain all the game-related logic, but no rendering logic. Instead, the rendering logic for both the GameBoard and GamePiece classes is located in a GameRenerer class.

When the board needs to be rendered, a GameRenderer instance is created and passed to the GameBoard::Draw method. The GameBoard class then tells the GameRenderer class to draw a board (passing itself to provide all the relevant information) and calls the Draw method of all the GamePieces on the board, again passing the GameRenderer instance.

  • After reading about the Visitor pattern, I've seen: Use the Visitor pattern when... • You have a class hierarchy that is effectively sealed. • There are many distinct operations to perform on it. • The operations are orthogonal to the core purpose of the types in the hierarchy. • You need the flexibility to define new operations over time. Seems like my sealed hierarchy would be the GameBoard and GamePiece, and my extension methods the update and draw. I will try to implement this way and come with the results. Thanks – David Jiménez Martínez Dec 8 '13 at 17:08
  • Where do textures go when Visitor is used? I've thought visitors are usually stateless. – Basilevs Jan 7 '14 at 21:09
  • @Basilevs: I am not up to date with the role of textures, but my gut feeling tells me they should go in the GameRenderer Visitor. There is no reason why Visitor classes can't have state. – Bart van Ingen Schenau Jan 8 '14 at 7:11
0

I had almost the exact same problem when I started using XNA. I'm still playing around with patterns to solve it, though :)

The latest thing I tried involves borrowing from MVVM. In XNA/Monogame land, you can inherit from a GameComponent class and register that component with the update/rendering engine (I may be getting the terms wrong here, but the general idea is correct).

Here's how I've broken things down:

  • GameComponents registered with the update/rendering engine are analogous to my MVVM Views
  • GameComponents not registered with the update/rendering engire, but managed by registered GameComponents are analogous to my MVVM ViewModels
  • Actual Model classes are injected into my GameComponents to controls the state of my GamePiece/GameBoard/etc. These model classes are completely unaware of the update or rendering mechanics. I would write my unit tests against these.

This kind of setup means I only register a handful of GameComponents with the engine (the views). Those GameComponents are then -in a sense- bound to other GameComponents (the viewModels) which are responsible for triggering updates in the system state and managing any rendering control logic. And finally, these viewModel analogous GameComponents each contain a Model which is responsible for the state and logic of what is eventually drawn on screen. The key here is that the Model is completely decoupled from the update/rendering engine.

I've only just started applying this approach. I'm sure I'll find problems with it... but so far it has helped me refactor an old monolithic XNA game I wrote 5 or so years ago.

0

I think that:

  • it's the game loop's responsibility to know which objects are drawable/renderable. You should make a base class/interface which holds some kind of "render" or "draw" method, possibly accepting any necessary arguments that the game loop will pass when calling it (like the GL context object for OpenGL rendering, etc).

  • each of your render-capable objects should contain their own drawing code, as an implementation of the "render" method of the base interface/class which they should extend. You can further refine this by extracting common rendering code to the base class (if you chose that over a base interface) or to the game loop itself, i.e. for a sprite-based 2D game, the game loop could contain all the actual sprite objects, and the render-able objects only inform the game loop which sprite is theirs, and where it should be placed, and it's the game loop itself that runs the sprite-drawing code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.