Critique My Implementation Of Pong?

Started by
17 comments, last by DishSoap 9 years, 4 months ago

Hi everyone!

I am a semi-experienced programmer but a very novice game programmer. To learn I have been building a simple implementation of pong, after it is done I plan to move onto some other simple game implementation. I was wondering if anyone wanted to critique my work? I realize it is probably very bad, so don't worry about hurting my feelings :). My hope is to build a few simple game implementations and replace piece by piece the OpenGL wrapper and math library I am using so I can learn more about those subjects. I just wanted to hear some thoughts from some of you guys.

https://github.com/AnthonyBrunasso/pong3D

All the source is in Pong3D/*. If you follow the readme you can run it if you so desire. The Visual Studio files are included in the repo. Game rules/score tracking have not been implemented yet. Just simple back and forth super exhilarating pong action!

Thanks and Happy Thanksgiving(to those who celebrate)

Advertisement

While, I cannot see your code because I do not use C++. I can say good code generally materialized from bad code. At least you are learning a whole lot by combing game development and general programming!

Hrm, I am also going to critique your file structure while trying to not change your design decisions too much:

  • You have non-game specific code in your pong implementation please separate 'engine' code out into it's own module or library
  • Separate your header and source files into different folders (include and source)
  • Remove dlls from your source folders and put them in their own external library folder
  • Shader, material, texture and other resources should be in their own resources folder
  • A Paddle shouldn't handle it's input, take that out into a PaddleController class so you can easily add AI to your paddle.
  • Remove boiler plate code from main and turn it into a Game class, inherit from that when making Pong
  • Remove all magic number values from code and put them in json or xml files that describe things like game specific data (Paddle initial positions) and engine data (window size, title etc)

Once you do this a better critique can be done.

Engineering Manager at Deloitte Australia

Seems good to me, maybe a little straight to the point: you have lots of gl* calls in various files, when them probably stay better in a single "glwrapper" thing, and the same for glfw calls (input!).

Functional, but a bigger project will deserves a bit of refactor.

Good job anyway!

This all really good stuff guys. thank you for your time.

Hrm, I am also going to critique your file structure while trying to not change your design decisions too much:

  • You have non-game specific code in your pong implementation please separate 'engine' code out into it's own module or library
  • Separate your header and source files into different folders (include and source)
  • Remove dlls from your source folders and put them in their own external library folder
  • Shader, material, texture and other resources should be in their own resources folder
  • A Paddle shouldn't handle it's input, take that out into a PaddleController class so you can easily add AI to your paddle.
  • Remove boiler plate code from main and turn it into a Game class, inherit from that when making Pong
  • Remove all magic number values from code and put them in json or xml files that describe things like game specific data (Paddle initial positions) and engine data (window size, title etc)

Once you do this a better critique can be done.

I worked on a lot of these points tonight, It's almost ready to push. My next push, hopefully tomorrow, will be a complete reorganization of file structure, I have refactored engine code into a new project and made subdirectories include/src in both the pong and engine projects.

The PaddleController/Game Class and file based values will definitely get my attention after my next commit. These are all really good points I should have considered from the beginning. I will need to find a decent JSON library for c++ or wrap a simple config reader into the engine. Anything is better than my magic numbers.

Seems good to me, maybe a little straight to the point: you have lots of gl* calls in various files, when them probably stay better in a single "glwrapper" thing, and the same for glfw calls (input!).

Functional, but a bigger project will deserves a bit of refactor.

Good job anyway!

Thanks! I will definitely look into a wrapper for a lot of my gl/glfw code.

* You are including unnecessary files in headers and are not using forward declarations.

* Some of your shaders are version 330 and some are 410.

Aether3D Game Engine: https://github.com/bioglaze/aether3d

Blog: http://twiren.kapsi.fi/blog.html

Control

* You are including unnecessary files in headers and are not using forward declarations.

* Some of your shaders are version 330 and some are 410.

I didn't even notice the shader version mismatch, haha. This is surely a quick fix as I have so few shaders and I will throw it in with my next commit.

You first point is interesting and shows that I'm pretty novice at C++ as well. I've never even considered doing that but I can see why that would be far better practice. Picking through all my headers and questioning whether the include can be moved to the cpp will definitely go on my to do list.

Thanks a lot!

You have non-game specific code in your pong implementation please separate 'engine' code out into it's own module or library

Seems like a complete waste of time as well as overengineering for the sake of "ideal" correctness.

Separate your header and source files into different folders (include and source)

For a game? Why? He's not writing a library here, who is going to be including these headers besides the game itself?

A Paddle shouldn't handle it's input, take that out into a PaddleController class so you can easily add AI to your paddle.

Does he WANT to add AI?

Remove boiler plate code from main and turn it into a Game class, inherit from that when making Pong

While I agree about moving code out of main I don't really get where the assumption would be that he should make a game class and then inherit from it. He could just as easily have a "Game" class by itself.

Remove all magic number values from code and put them in json or xml files that describe things like game specific data (Paddle initial positions) and engine data (window size, title etc)

Removing magic numbers, sure. He could just as easily make them constants and should make that decision based on his usage, not simply throwing a bunch of random and possibly useless settings in an xml or json file and then getting library code together to load it and parse settings.

If theres one thing that wastes just as much time as bad code its overengineering code just because its the "pretty" thing to do.

A few things I noticed:

- It looks weird that the ball has BoundClose and BounceNear parameters. I'd let the ball move anywhere and check outside the Ball's Update method if it's a point for any of the players.

- It also looks weird that in the Ball's Update method you send both Paddles, it's like you put all the collision detection inside the Ball class. I'd take that out into something that checks for collisions, and add methods in Paddle and Ball classes to react to collisions.

- I can't find anything about timing, it looks like you update and draw everything as soon as you can. Implementing a way to limit the the frame rate is usually a must for games, so the game fells the same in any computer you play. You basically check how much time has passed since your last iteration of the gameloop, send that value into all the "Update" methods (and do everything considering that time) and wait some milliseconds before executing the next iteration. Later you can add fixed updates for physics too.

- Speaking about Update methods, if you send the same thing every time consider setting those things as attributes once instead. It's also uncommon that your WorldObject doesn't have an Update method and the derived classes have different Update methods. It's not bad, but in almost every engine and game I worked in the base game object has an Update(float deltaTime) method. This also makes it easier to update the game objects in games that the object count is dynamic. Now you have the paddles and the ball and update each one in a line, but imagine a Breakout game, where you also have a different number of blocks in each level.

- In WorldObject you have some empty constructors, is that OK?

- The "Movable" class has a name that sounds like an Interface, but it has some code. Couldn't that code be part of WorldObject? Or some WorldObjects don't move? I only see that Paddle and Ball are.

You have non-game specific code in your pong implementation please separate 'engine' code out into it's own module or library

Seems like a complete waste of time as well as overengineering for the sake of "ideal" correctness.

Separate your header and source files into different folders (include and source)

For a game? Why? He's not writing a library here, who is going to be including these headers besides the game itself?

A Paddle shouldn't handle it's input, take that out into a PaddleController class so you can easily add AI to your paddle.

Does he WANT to add AI?

Remove boiler plate code from main and turn it into a Game class, inherit from that when making Pong

While I agree about moving code out of main I don't really get where the assumption would be that he should make a game class and then inherit from it. He could just as easily have a "Game" class by itself.

Remove all magic number values from code and put them in json or xml files that describe things like game specific data (Paddle initial positions) and engine data (window size, title etc)

Removing magic numbers, sure. He could just as easily make them constants and should make that decision based on his usage, not simply throwing a bunch of random and possibly useless settings in an xml or json file and then getting library code together to load it and parse settings.

If theres one thing that wastes just as much time as bad code its overengineering code just because its the "pretty" thing to do.

Over engineering? It's simply making it easier for a reader to see what is actually game code and what isn't, seeing as he isn't the only person reading the code it isn't a complete waste of time. Good structure is rarely a waste of time, even in small projects.

For the same reason above, so people reading it can directly go to src or inc for whatever they want to look at. I didn't say he was writing a library. I don't know why you wouldn't do this 'for a game'.

Well, AI is just an example what if he wants to add a networked controller so another application could control a paddle via some port? It's all about SRP and makes it well designed, it is also maybe 10 minutes of work.

I was just following his other design patterns (i.e movable which things inherit from) and I think it fits.

Sure, constants would work, but require a recompilation every time, why aren't his shaders, materials etc constants as well? Again following what he already had in his game.

You want to see over-engineered?

  • Factories for everything, remove public constructors
  • Separate rendering and logic
  • Normalise all namespaces and add missing namespaces, make sure they have proper and long names.
  • Use premake or cmake (Preferably both) for agnostic compiler \ IDE project setup
  • Separate engine and game into different git repositories making use of sub-module
  • Add an asset database for handling resources (config files, materials, mesh etc)
  • Engine should definitely be it's own library(rather than just some code) and be seperated into core, math, render, physics, input, network, UI and game (WorldObject and Game class)
  • Input should be more generic and be loaded through a config file for ease of changing actions
  • Write a C interface for everything
  • Add a plugin system for mods (Allow use of hot-loaded dlls and scripts for at least 4 languages, make use of SWIG)
  • Capture metrics of players and send back to database using pig, hadoop and map reduce.

(Please continue this list)

Engineering Manager at Deloitte Australia

This topic is closed to new replies.

Advertisement