I am working on making a Pong clone as a practice project. I have a PongState class with members like Ball, Paddle, Board and Score. I want to structure my code so that each object doesn't have to know how to render itself, but a PaddleRenderer class will. I also want to create a PongStateRenderer class, which may use other classes like PaddleRenderer, as well.

How should I let PongStateRenderer know about the internals of PongState so that it can render it? The Ball object in PongState know's it's own position and size, does that mean Ball has to be a public member variable so that PongStateRenderer can also know the position, or is there a better way to do this without totally breaking encapsulation? Perhaps my architecture is totally wrong, and I should use a different method?

I'm working in C# as it says in the tag but a general answer that applies to many languages could also be helpful.

  • \$\begingroup\$ You are doibg exactly the opposite of what a nornal game would do. In those the renderer usually doesn't know how to render something, only the objects themselfs. \$\endgroup\$ – Bálint Oct 14 '16 at 19:07
  • \$\begingroup\$ You seem to be asking "how do I get object A to see values in object B using encapsulation", and to a lesser degree, "is this a bad program structure". This seems more like a programming question. The same questions may arise when dealing with, say, data structures for the purpose of displaying data in non-gaming software. As such, I would vote to move this to StackExchange. \$\endgroup\$ – Gnemlock Oct 14 '16 at 23:59

It sounds like you're just taking a baby step away from "objects render themselves" rather than moving all the way to an approach where something else renders the objects. When objects render themselves, every object (in this case a paddle, a ball, et cetera) has a draw method and some corresponding data. In your case you just appear to be moving that method and state into its own class, so you'd still have a PaddleRenderer and a BallRenderer and so on. I would argue this is inferior, as it doesn't really solve many of the problems associated with the "objects render themselves" approach.

Instead, I would encourage you to think more broadly: generally you can visually represent things in one of two broad classes: sprites or 3D meshes. Your renderer should know how to render sprites, and it should know how to render meshes. Let's say for simplicity everything in your game is represented and rendered as sprites. So you create a Sprite class that contains all the needed properties: references to textures, animation sequence information and current state, position, current sequence index, current frame index, et cetera.

Then you give your Paddle a Sprite*, and you give you Ball a Sprite*, and you configure the data on each sprite to be appropriate for the ball, or the paddle, or whatever else you want to put in the game. But the renderer just has this big homogeneous list of Sprite objects to render and that's all it concerns itself with.

Every tick of the game logic, you update the ball's position and the paddle positions and all of that. Once the logic tick completes, before you actually render, you can simply copy that position information into the appropriate sprite member before rendering. Likewise with any other state (for example maybe you update the sprite's tint color randomly every time the ball hits a paddle, for a psychedelic effect).

This approaches makes the "renderer" subordinate to the game logic, but that's reasonable. Generally in a game you'll have user input which directs the game logic, and then game logic which directs the rendering. Information (and responsibility) flows along those paths, but it generally does not flow in the other direction (the renderer usually does not influence the state of the game logic).

  • \$\begingroup\$ This. Remember that in game development, usually composition works much better than complex hierarchies of inheritance. \$\endgroup\$ – Gustavo Maciel Oct 14 '16 at 19:31

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.