patterncppMinor
Master engine class for a Pong game
Viewed 0 times
enginepongmastergameforclass
Problem
Question: Is having a master class bad practice? I am making a simple pong game, but I'm writing the code as if I were making for something that might be for something more complicated I want to create in the future. Also, am I not doing it in a good manner?
What I am doing: I have a class, in this case "engine", which basically holds everything and runs all of its referenced objects logic inside of its own functions. All of the other objects are then linked to each other by holding the data of the "world or engine" object and use it as a linker to other objects that it can interact with.
NOTE: The sfml media library was used with this project.
note: if you need the ball definitions i'll post them
```
#include
#include
#include
#include
class paddle;
class ball;
class enemy;
class player;
class engine{
ball *gameBall;
enemy *enemyPaddle;
player *playerPaddle;
Clock gameClock;
RenderWindow &refWindow;
int gameSpeed;
Event windowEvent;
void eventDraw();
void eventUpdate();
void handleWindow();
public:
engine( RenderWindow &rendy);
~engine();
bool start();
Vector2f getWindowSize();
void drawPart(Drawable &art);
Time getGameClock(){ return gameClock.getElapsedTime(); }
};
class ball{
private:
CircleShape myShape;
engine& world;
int radius;
Color color;
Vector2f position, velocity;
short signed int dirX, dirY;
short signed int getDirection();
void wallBounce();
public:
ball( engine& gameEngine);
void draw();
CircleShape getCircle(){ return myShape; }
void pop();
void update();
};
int main()
{
RenderWindow window(VideoMode(640, 480), "Pong");
engine gameEngine( window );
return (int)gameEngine.start();
}
// Class Prototyes
// Engine
engine::engine(RenderWindow &rendy):refWindow(rendy){
gameBall = new ball(*this);
enemyPaddle = new enemy;
playerPaddle = new player;
gameC
What I am doing: I have a class, in this case "engine", which basically holds everything and runs all of its referenced objects logic inside of its own functions. All of the other objects are then linked to each other by holding the data of the "world or engine" object and use it as a linker to other objects that it can interact with.
NOTE: The sfml media library was used with this project.
note: if you need the ball definitions i'll post them
```
#include
#include
#include
#include
class paddle;
class ball;
class enemy;
class player;
class engine{
ball *gameBall;
enemy *enemyPaddle;
player *playerPaddle;
Clock gameClock;
RenderWindow &refWindow;
int gameSpeed;
Event windowEvent;
void eventDraw();
void eventUpdate();
void handleWindow();
public:
engine( RenderWindow &rendy);
~engine();
bool start();
Vector2f getWindowSize();
void drawPart(Drawable &art);
Time getGameClock(){ return gameClock.getElapsedTime(); }
};
class ball{
private:
CircleShape myShape;
engine& world;
int radius;
Color color;
Vector2f position, velocity;
short signed int dirX, dirY;
short signed int getDirection();
void wallBounce();
public:
ball( engine& gameEngine);
void draw();
CircleShape getCircle(){ return myShape; }
void pop();
void update();
};
int main()
{
RenderWindow window(VideoMode(640, 480), "Pong");
engine gameEngine( window );
return (int)gameEngine.start();
}
// Class Prototyes
// Engine
engine::engine(RenderWindow &rendy):refWindow(rendy){
gameBall = new ball(*this);
enemyPaddle = new enemy;
playerPaddle = new player;
gameC
Solution
A "master class" is a very close relative to a singleton or a global. It can easily be a design which violates the Dependency Injection principle, and leaves you with non-modular code. In this case your engine is also violating the Single Responsibility principle, as it's doing a lot of unrelated tasks: it's handling windows, providing the game's main driver, moving the ball, drawing the screen, and hosting all kinds of different data.
Try this task: write a unit test that exercises just the engine::handleWindow() routine without needing to create a real ball, enemy, or player. It's hard, because your constructor builds all of those objects.
You've already got a start. For example, you can easily write a unit test that tests engine::eventDraw without creating a real RenderWindow, because you can pass a mock RenderWindow on the engine constructor. You're using dependency injection.
As you're going to have a singleton in main (and every program does at some level), I recommend you try to keep that singleton as thin as possible.
It's not that your existing code isn't going to work, but it's going to be a problem to maintain, especially as you extend it to add functionality. Where does scorekeeping come in? Player preferences? High score table? Head-to-head play with two people? The more you want to add to this, the more you're going to need to change engine, and the less confident you're going to be that you aren't breaking something else.
Try this task: write a unit test that exercises just the engine::handleWindow() routine without needing to create a real ball, enemy, or player. It's hard, because your constructor builds all of those objects.
You've already got a start. For example, you can easily write a unit test that tests engine::eventDraw without creating a real RenderWindow, because you can pass a mock RenderWindow on the engine constructor. You're using dependency injection.
As you're going to have a singleton in main (and every program does at some level), I recommend you try to keep that singleton as thin as possible.
It's not that your existing code isn't going to work, but it's going to be a problem to maintain, especially as you extend it to add functionality. Where does scorekeeping come in? Player preferences? High score table? Head-to-head play with two people? The more you want to add to this, the more you're going to need to change engine, and the less confident you're going to be that you aren't breaking something else.
Context
StackExchange Code Review Q#36935, answer score: 5
Revisions (0)
No revisions yet.