In the past month and a week, I’ve spent part of my time working on a revamped version of Pong. I wanted to go back to the game, recreate it in C# to get my language skills better honed, and also make a better experience hopefully. This is my tale of how I achieved those goals.
I think most game development starts exactly where I did for this, and that’s world creation. Now Pong might not have a ‘world’ as people would traditionally understand for a video game, but if you consider the field of play as the ‘world’ or ‘game space’ as some designers prefer to say, then you’ll realise even something as simple as pong does indeed have one.
I knew the properties my ‘world’ would have, the borders would need a collider for the eventual ball to bounce off, there’d be a halfway line that was purely decorative and served no gameplay relevant purpose, and finally there’d need to be 2 goals – one for each player, this would take no physical manifestation but would still require to be there in the form of a collider that we’d later use as a ‘trigger’. That is the classic pong set-up, and setting it up really only took about 2 minutes to apply all the colliders and check the right boxes in the inspector so that gravity didn’t affect them, or so they wouldn’t rotate or move due to any force from the ball or paddles, etc.
At this point you can really go 2 ways, either make a ball or a simple player. I opted for the player first, that way when I made the ball I’d at least be able to play against a wall much like single-player tennis. Also the player is much easier to set up than the ball, the ball requires some communication with a ‘game manager’ for purposes I’ll get into later. The player rackets were given the standard box collider and rigidbody2D so that they could act as physical objects in the world and be moved via scripting. As for the scripting itself, all was really required was to move the player up and down dependant on key’s pressed, usually people use ‘If’ statements with Unity’s ‘KeyCode’ values, however Unity also has something called ‘Axes’ (X & Y, not Hatchet). There are many axes in Unity, both horizontal and vertical, but also firing, mouse controls, jumping etc. Since I only care about moving up and down I was able to use ‘Input.GetAxisRaw’, this allows me to use the axis value for whichever axis I need such as vertical. Then using ‘Rigidbody2D.velocity’, I was able to move the player up and down at will.
Next I needed a ball to bounce around, again the standard rigidbody2D & colliders were added but for a basic ball, it needs to be able to bounce perfectly, so the angle it bounces off a wall at, should be the same as it leaves. This can be a stumbling block because not every new developer will know about Unitys ‘Physics Materials’. Unity say that Physics Materials are used to adjust friction and bouncing effects of colliding objects, making one is as simple as left-clicking, and selecting Physics2D Material, then adjusting the values of friction and bounciness. I’ve chosen 1 as my bounce value and 0 as friction, a bounce value of 1 simply means that it won’t lose any energy (to put it in physics terms), which is a fancy way of saying it won’t slow down.
The ball now bounces around and works as a ball is expected to, however it doesn’t destroy when it’s in a goal, no score is incremented, no new ball instantiated, when bounced off a racket it doesn’t change it’s return path as it should, and it makes no noise. Here is where scripting becomes into play once more. It’s all quite simple, when the ball collides with a racket first we want to make sure it actually IS a racket, so searching to see if the collision was tagged or called racket/paddle will let the game know, from there determine if it was the left or right paddle, then just set its velocity to the exact same as before but with the X value flipped to be positive/negative. To make the game harder increase the speed before the function ends, and finally play an AudioSource that you can add in the inspector. To destroy the ball use the OnTrigger function and again determine the the ball IS in a goal, then determine left or right, after that increment the correct score by communicating with the game manager, and destroy the ball.
From this point it’s now necessary to introduce a Game Manager, all this is, is an empty game object with a script attached that will handle a lot of values that need to be kept track of. Primarily the Game Manager is normally used to keep track of score, deal with any object instantiation as that’s not really any other objects responsibility unless it’s a gun shooting a bullet say, and maybe draw the UI for you, but you can if you’d like make a different object for that, but you will need it to have a Game Manager object it can reference for drawing score values. My game manager is slightly more complicated purely because I’ve got 2 game modes, this was a very late addition though and can be added to a simple game of Pong in about 20 minutes with bug-catching.
All my Game Manager does is keep track of score, instantiate the ball where necessary and update the score values for the basic in-game UI. Here’s a small slide-show of 2 images showing you just the basic layout of my game manager, as can be seen it’s quite simple. The only thing I thought was an interesting discovery was setting the AIRacketScript’s ball value to actually being the instantiation of the ball, I wasn’t aware that could be done, but it does make tracking an object from creation extremely simple. Before I used that I was trying to find the ball sometimes before it was instantiated as it takes a little while or too long after and the AI would look slow and poorly made. There is admittedly no game loop, so there isn’t a score to be reached, this wasn’t done on purpose at first because I was testing the game and if a player/AI won, then it’d make testing infuriating with the stopping and starting. At the end though I figured it was up to the player to decide what to play to, 5/10/15/20? Admittedly this could have been an extension to the ‘Play’ Menu but I was running out of time at that point, it could be something to be added as an extension idea at a later date possibly.
After this point came my holiday that kept development on hold for a week (I wanted to enjoy some sun in Cambridge with my partner, it’s truly beautiful down there), however the to-do list wasn’t that long, all that was left was the AI and the Menu System, both tasks that I’ve spoken about at length on this site already. Since I’ve already spoken about them at quite some length (nearly 1000 words each I think), and since this post is already approaching the 1.5K mark I think it’s a good time to leave it there. If you’d like to read those posts there are several links on this page that will take you to them but here are some extras just in case:
This post has been a lot longer than my normal ones and also a little bit more digging into the technical parts of my code and statements used and logic created. For any new devs I hope you’re able to make your own game from the content here, be proud you made a game at the end because you’ve done something others dream of doing but never try. As for everyone else, I thank you for reading this far, I bid you to have an awesome day, and to also keep on designing!
Here’s a video of the game in action, much like with the other portfolio articles on games, I figured it’d be best to show an actual in time version of the game. It also allows for sound which the gifs I like to use unfortunately don’t encompass.