Guest post by
: Games programmer, CS student and Microsoft Student Partner at UCL
Microsoft Student Partners ran an introductory workshop to game development with C# and Unity at UCL. The workshop was a great success and we covered a lot of important topics, but due to time constraints we weren’t able to finish the game we were planning to make at the event. For the benefit of attendees who wanted to complete the game in full (as well as for the many who wanted to attend but weren’t able), we’ve decided to post this web tutorial covering how to make the game from start to finish.
The game we want to make is an updated 2.5D version of the 1977 game Combat for the Atari 2600 (pictured below). Similarly to that classic, our game is a two-player top-down shooter game, where your objective is to shoot and eventually destroy your opponent’s tank.
Section 1 – Setting up our game scene
We begin by creating an empty Unity project, giving it a descriptive name (“SuperTanks” seems appropriate). Once Unity has finished loading an empty scene, import our special MSP Unity StarterPack (which you can freely download from
). You can import custom asset packs by clicking on
Assets -> Import Package -> Custom Package…
in Unity’s menu bar at the top of the screen.
From here, open the newly imported “Prefabs” folder and drag the
prefab into your scene hierarchy.
Remember to save your Unity scene with an appropriate name (“Level1”) either through
File -> Save Scenes
or by pressing CTRL+S (it’s a good habit to get into pressing these at frequent intervals to make sure you don’t lose any progress).
From here, we want to create the primary floor of our level mesh. Insert a plane into your scene by clicking on
GameObject -> 3D Object -> Plane
. Ensure your newly created plane is centred at position (0, 0, 0), which should be directly below the tank, as pictured below.
Navigate to the
folder and find the “GroundMat” material. Drag and drop it onto your newly created Plane object to apply a simple brown dirt texture to it.
Next, we want to resize our plane to create a play space of a similar size to that of Atari Combat. Select your Plane object in the Hierarchy and change its scale values to (12, 1, 7). For organisational purposes, let’s also rename our plane object to “Ground”.
With our new Ground object set up, we’ll position our camera so that it captures this entire play space.
object in the Hierarchy and move it so that it is above the Ground and Tank objects, facing downwards. If you’re adjusting values manually, you can set the Main Camera’s position to (0, 63, -25), and its rotation to (70, 0, 0). Your scene should look similar to that pictured below:
Next, let’s start to think about how we want our Tank to behave. Since our Tank is going to be a solid, physical object in our game, we are going to want to add both a
to it. Simply select your Tank object and click on the
button at the bottom right of the screen in the Inspector view, find the
components and add them.
As a simple introduction to movement and input, we’ve included a
script as a part of the MSP Unity starter package. Navigate to the
folder and drag the
file onto your Tank object. Provided you’ve set up the Tank’s other components correctly, you should now find that by building and running your game (pressing the
icon at the top middle of Unity), you can move your tank around the play space with the W-A-S-D keys.
Once you’ve had a play with moving your Tank around your scene, remember to apply your changes to the
prefab, so that every other Tank copy we make in the future will have the same components that we just added applied to it. (With your Tank object selected, find the Prefab options in the top of the Inspector view on the right side of the screen, and click on Apply.
With your changes applied to the Tank prefab, you can now experiment around with inserting another tank and setting the value of
component) to 2. The script will now respond to input from the UP-DOWN-LEFT-RIGHT arrow keys on your keyboard instead, allowing for two-player movement. (We will have a more detailed look at multiplayer integration later, so you can delete your second Tank object once you’re done testing out this basic movement.)
Section 2 – Firing missiles
One core piece of functionality we want in our game is for our Tank to be able to fire missiles – so let’s write a script that does just that. With your Tank object selected, click on
in the lower right of the Inspector view, and select
. Name your new script appropriately (I will call mine
) and press
Create and Add
. Double-click on your newly created script and it should open up in Visual Studio (or your IDE of choice).
The empty script will contain two empty functions –
(which is called once when our object first enters the scene), and
(which is called every single frame of the game). Since we want to fire our missiles in response to user input (which can happen at any point), we want to add our functionality into the
Before we implement our missile firing, however, let’s declare a few important variables that we’re going to need. At the top of your script, declare a public
variable called “playerNumber” (with a default value of 1), and a public
If you now switch back into Unity, you should find that these two variables now have become editable fields inside our
component that we can access our change from inside our Unity editor.
Now that we have a way to influence our scripts from inside Unity, go back inside the
folder and drag the
prefab into the empty
field on our Tank’s MissileGun component.
We now have access to our
object inside of our script, so let’s begin thinking about the conditions for shooting them. We want to spawn our missiles in response to input from the player, so let’s take a look at which buttons we have available to read from inside Unity.
Inside your Unity window, click on
Edit -> Project Settings -> Input
to open up Unity’s Input Manager (it should appear on the right-hand side of the screen). Here you can see a list of all the buttons that are defined in Unity by default. Notice the “Fire1” and “Fire2” buttons; we will configure these to be the button for firing missiles for our Player 1 and Player 2 respectively.
field for each input button denotes which keyboard key Unity checks for to determine whether the button in question was pressed. In order to make the game easiest to play for two players on a single keyboard, let’s change
for the “Fire2” button to “right ctrl”.
With this simple change applied, go back into Visual Studio (or your IDE of choice). We want to spawn our missile in response to the player pressing either the “Fire1” or “Fire2” buttons, so we will make the following changes to our
Here we’re making use of Unity’s handy
function, which takes in a
reference, a position and a rotation value as parameters, and inserts that GameObject into our scene. Since we want to spawn our missile prefab, we pass in our
variable as the first argument. The
variables refer to the current position and rotation of our Tank object, so we pass those in as well.
function takes in the name of a Unity button and returns true if the user pressed that button during the current frame. By concatenating the string “Fire” with our
variable, we make Unity check for either “Fire1” (the left CTRL key) or “Fire2” (the right CTRL key) depending on what whether we’ve set
to 1 or 2.
Go back into Unity and press the Play button to play around with the current state of our game.
You should find that you can now spawn a trail of missiles in your Tank’s path with repeated presses of the CTRL key. Not exactly the behaviour we were going for, but we’re getting closer.
Let’s start moving closer to what we want by editing our
prefab. Drag the prefab from inside the Prefabs folder into your scene to create a new
instance. Just like our Tank, we want our missiles to be affected by Unity’s physics engine, so let’s add a
component to our Missile instance.
We also want our missiles to collide with other objects in our scene, so let’s add a
component to it as well. You may find that Unity’s default size and position for this Capsule Collider don’t exactly match the shape of the missile, so edit the properties of this component until they do. (My settings are Center: (0, 0, 0), Radius: 0.3, Height: 2.5 and Direction: Z-axis).
your changes to the Missile prefab when you’re done editing its components!
With these changes applied, you can do some more playtesting. You may notice that after making our missiles into physical, collidable objects, they cause our Tank to twirl around and bounce up and down around the scene. We’ll want to make a few adjustments to make sure this doesn’t happen.
Select your Tank object and find its
component. Under the
option, tick the boxes for
in X and Z. This will ensure that our Tank only rotates around the Y-axis (which is what we want it do in response to user input).
Next, let’s make a few adjustments so that our missiles spawn from a position just in front of the tank’s cannon instead of in the middle of it.
Right click on your Tank object in the Hierarchy view and select
. This will insert an empty
into your scene that is “childed” to the Tank – which means that its position and rotation will always be relative to that of the Tank (so that when the Tank moves around the scene, this child object will move alongside it).
Rename this empty GameObject with an appropriate name (such as “Fire Transform”), and move it to a location in front of the Tank where you want missiles to spawn from (I’ve set mine to position (0, 2, 5)).
From here, let’s get hold of a reference to our new
object from inside our
script. Open your script again and declare a new public variable of type
Just as before, if you now go back into Unity, you will find that a new empty field (
) should appear in your Tank’s
component. Take our newly created Fire Transform object and drag it into this empty field.
Back inside our
script, let’s change our call to
so that our missiles are spawned at the position of our
object rather than our tank’s position:
Again, remember to apply your changes to the Tank prefab! If you now have a play with the game, you will see that our missiles behave much closer to how we want them to.
The astute reader will still notice that our missiles aren’t flying off into the air the way we would expect them to. Let’s change that by applying a force to them right after they’ve been spawned.
Let’s start by declaring another public
variable that defines the magnitude of the force we’ll be applying at the top of our script (I’ve set mine to a default value of 2000):
Now we can apply this force to our missiles in the following way:
Here we’re temporarily storing a reference to our newly spawned missile object inside the
variable, then using the
function to retrieve its Rigidbody component. Finally, we call Unity’s
function on the missile’s Rigidbody.
Because a force has both magnitude and direction, we have to pass in a vector object into this function. The handy
variable always contains a unit vector that points in our Tank’s “forward” direction, which is the direction we want our missiles to move in. We scale this vector with our
variable in order to fire them off with the appropriate magnitude.
Test your game to confirm that your missiles are now finally blasting off into the air in a semi-realistic fashion.
As a final touch to our missile-firing functionality, let’s add a sound effect to play when our missiles spawn. Find your
prefab again and add an
component to it. Navigate to the
folder, and drag the
file into the empty
field on the
Section 3 – Explosion Physics
We now have some satisfying missile-firing mechanics going, but our missiles are still just colliding against the floor and grinding to a halt like any other object when they fall. We would much prefer to have them explode instead.
If you’ve had a peek in the Prefabs folder, you will see that you’ve already been provided with an
prefab. This prefab contains a collection of flashy-looking particle effects that we’ll want to spawn when our missiles collide with something.
prefab, create and add a new script with an appropriate name for what we’re about to do (such as “MissileExplosion”), and open it up in your IDE. Just as we’ve done before, let’s declare a public
variable at the top of our script to hold a reference to our Explosion prefab.
prefab into the field that corresponds to this new variable.
Now let’s Instantiate a copy of this Explosion prefab every time our Missile collides with something. We’re going to accomplish this using the Unity function
, which will be automatically called on any object with a Collider component the moment it collides against another object.
script, simply start typing
, and Visual Studio should automatically give you the appropriate auto-complete option for the function we’re looking for (just hit TAB or RETURN on your keyboard to confirm your choice). If for whatever reason your IDE doesn’t provide you with this auto-complete help, just copy the function definition below into your
Now, inside the
function, we want to spawn our Explosion prefab, and then remove our missile from our scene. We’ll accomplish this by adding the following lines to the function:
Like earlier, we’re Instantiating our
at our current position. The variable
, though cryptic-looking, simply means that our explosion will spawn with no rotation applied to it. (We prefer not to pass in our Missile’s rotation here, as that would spawn our explosion effect rotated at weird angles depending on the orientation of our Missile.)
Once our explosion has spawned, we remove our missile from the scene by calling the aptly named
function, passing in the
variable, which holds a reference to the object this script is attached to (our Missile, in this case).
You can give your game another test-run now to confirm that our explosion effects are spawning as expected.
From here let’s back up our newly added explosion effects with some actual physics. After we’ve spawned our explosion prefab, we want to apply an appropriate explosion force to all objects that happen to be close by.
We can accomplish this with another convenient built-in function called
. This function will create a virtual sphere around any point in space and return a list of all the Collider components that fall inside its radius.
To implement this, let’s start by declaring one
variable to define the radius of our explosion (I’ve set mine to a default value of 5), and another to define the magnitude of the explosion force we want to apply to all surrounding objects (which I’ve set to a default value of 1000).
Next, we’ll insert a call to
right after we’ve spawned our explosion effects, passing in the current position of our missile and the radius we want our explosion to have:
From here, let’s go through each of the Collider components that were inside the virtual sphere (using a
loop) and apply an explosion force to them using the Unity function
. Recall that in order to add a force to an object, we need to first get its Rigidbody component, so let’s do the following:
Here we temporarily store each object’s Rigidbody component inside the
variable. We also have to make sure the object we’re trying to push actually has a Rigidbody component attached – this is why we insert the check for
targetBody == null
to the next iteration of the loop if no Rigidbody was found.
function takes in a value for the magnitude of our explosion force, as well as the position and desired radius of our explosion. From there, Unity will automatically calculate the appropriate force to apply to the object depending on how far away from the centre of the explosion it is.
If you’ve made it this far, congratulate yourself by giving your game another test-run. You can now insert another Tank prefab into your scene (remember to set the value of
on the PlayerMovement and the MissileGun components to 2 for this second Tank!) and test that the explosion physics are working as they should. In its current state, you already have a rather enjoyable game of king-of-the-hill, as you can push your fellow Player off of the play space with a well-placed missile.
As a final touch to our explosion mechanics, let’s add another sound effect to play when our missiles explode. Find your Explosion prefab and add an
to it. Inside the Sounds folder, find the
file and drag it into the empty
Section 4 – Setting up a win condition
Our current physics simulation is good fun, but doesn’t exactly resemble Atari Combat in its mechanics. Let’s set up a health system for keeping track of how many times each Tank has been hit, and for ending the game when one Tank has taken too many hits in a row.
Select either your Tank prefab or one of your Tank objects in the scene (if you’re editing a Tank instance, remember to apply your changes to the prefab when you’re done!), and create a new script. (I’ll call mine simply “Health”). Open your new script in your IDE.
To start with, declare a public
variable to determine how much health a Tank has at the beginning of the game (I’ve set mine to a default value of 5). From here, we’ll declare another private
to keep track of how much health our tank currently has at any given point in the game.
function (which you’ll recall is called by Unity on every script when that object first enters the scene), we’ll set
to the value of
, so that our Tanks start out with a maximum health value when the game begins.
From there we’ll want to set up a way for other components to interact with our
script to make our tanks lose health. We can accomplish this by creating a new public function that decrements the value of
every time it’s called:
We can now call this new
function from anywhere in order to decrease the health of one of our Tanks.
Of course, we’ll want to have a mechanism in place to end the game once one of our Tanks’ health drops to zero. Let’s create another simple
function that we call whenever this happens. Inside
, we can simply destroy our Tank’s GameObject for the time being to indicate that the game is over.
We now have features in place to make our Tanks take damage, but we’re not actually using them anywhere. We want our Tanks to take damage whenever they are hit by a Missile’s explosion, so let’s return to our
script and add this extra functionality.
function, we’re already going through every object that is within range of our explosion, so let’s insert another few lines here to apply damage to any object in range that also has a Health component:
Notice that we can use Unity’s
function to access even our own user-defined components, such as Health. Just as we did before applying forces to nearby Rigidbodies, we also have to make sure to check whether or not the object we’re looking at actually has a
component before we call the
We now have a suitable win condition in place! You may find it a bit difficult to kill your fellow player without knocking them off the playing field first, however. Let’s sort that out by adding some walls around our play space.
You can add walls by simply inserting a few cubes into your scene (
GameObject -> 3D Object -> Cube
from the menu at the top of Unity), resizing, rotating and moving them to the edge of the play space accordingly. If you navigate to the
folder, you can find the
, which you can drag and drop onto your Cubes to give them a rusty metal look.
I set up my level’s walls in the following way: After inserting a Cube and applying the
to it, I scaled it to (5, 5, 75) and moved it to the left edge of the play space. I then duplicated the cube (right click on it in the Hierarchy and select
) and moved the copy to the right edge. I then made another duplicate, set its scale to (5, 5, 125) rotated it 90 degrees in Y and moved it to the top edge. Finally, I duplicated this wall one last time and moved it to the bottom edge.
Now that we have all of the components we want on our Tanks in place, let’s also apply a different Material to our second Tank so they are clearly differentiated. With your second tank selected in the Hierarchy, find its
component and expand the
array option. Inside the
and drag it into the first element of the second Tank’s
Section 5 – User Interface
The only thing that remains for us to do to recreate Atari Combat in modern form is to display each player’s current score on some sort of on-screen HUD. We’ll accomplish this using a UI Text element.
Insert a UI Text object by clicking on
GameObject -> UI -> Text
. You’ll notice that doing this inserted not only a new object called
into your scene, but also a
. If you double-click on the
object in the Hierarchy to zoom in on it, you may be startled to find that it is actually a giant rectangle that sits somewhere far removed from the rest of our level. As it turns out, there is a natural explanation for this.
object, which is the parent object of all UI objects in Unity, actually exists in a different “space” from all of our other objects. Our Tanks, walls, Ground and Missiles exist in what’s known as “World Space” – the virtual 3D coordinate system of our game. The
and all the objects childed to it, meanwhile, exist in 2D “Screen Space”. Screen Space coordinates are determined by the size of the player’s screen, and objects that use it will by default always render on top of all other objects.
To start with, select your newly created
object and edit its
component. Select the
property and set it to white.
You can now confirm that the
object does in fact appear on top of everything else by switching to
(or by pressing the
button and running the game).
Let’s make some more changes to our
object. Select Unity’s
tool in the top left-hand side of Unity (or by pressing the T key on your keyboard).
Using this tool, move the Text object to the top left of the Canvas. Rename this object to “Player 1 Score”. From here, find its
component again and set its
, and its
to 26. Fill in the
field with placeholder numbers to represent Player 1’s score (I’ll just use “999999999”).
Player 1 Score
object and rename it “Player 2 Score”. Move
Player 2 Score
to the top right corner of the Canvas, and edit its
property to be
. You should end up with a Canvas that looks like the following:
With that, we have an on-screen HUD in place for displaying our players’ scores. Of course, our text elements are still completely static and will not change during play. Let’s do something about that.
object in the Hierarchy and add a new script to it with a descriptive name (I’ll call mine “ScoreManager”). Open it up in your IDE.
As we saw when editing our Text objects, the component responsible for what text to display on the screen was the aptly named
component, so these are the components we want to be editing inside our script. Unfortunately, Unity doesn’t grant us access to these components by default, so we’ll have to include the following line at the very top of our
line will import all of the components associated with UI. Having addressed that, let’s start our script by declaring two public variables of type
(I will call mine “player1ScoreText” and “player2ScoreText”).
Similar to what we’ve done before, populate these new public variables by dragging the
Player 1 Score
Player 2 Score
objects into the corresponding empty fields on the Canvas in Unity.
We can now edit what text to display inside our
objects anywhere we want inside our script. Let’s start by setting both of them to display “0” when inside our
Notice that in order to change the text that displays on each
component, we have to assign a different string to its
property. (The term “text” has been heavily overloaded here, so if you’re confused, just take care to copy the above two lines carefully until you get the desired effect.)
If we now Play our game, we’ll see that our
objects indeed start off by displaying “0” when the game runs.
All that remains now is for us to change what these elements display in response to a Tank getting hit by a missile. In order to accomplish that, we’ll have to declare another two private
variables to keep track of each player’s score. We’ll set both of these to a default value of 0 to represent each of our players’ score at the start of the game.
From here, let’s think about how we would want outside components to interact with our
to increase a player’s score. A player’s score should go up if they managed to hit their fellow player with a well-placed missile. The easiest way for us to detect when this has happened would be inside our
script whenever the
function is called.
With this in mind, let’s create a public function inside our
script that takes in the number of the player that just took damage and increments the value of the other player’s score. (I’m going to call this function “OnPlayerDamaged”.)
Finally, we want to make sure we’re updating our
elements to display each player’s new score as soon as it changes:
Note that the
property expects to be assigned a
value, which is why we have to apply the
function to the
variables before we assign them to the Text elements.
All we have to do now is insert a call to this new function inside our
script. Before we do that, however, we need to declare another public
variable inside of
so we can keep track of which player took damage.
We’re also going to need a way to access our
script from inside of
We can do this in the same way that we did before, by declaring a public
variable and simply dragging it into the empty field.
This time, however, because we know that there will only be one
in our scene at any time, we can make use of another handy Unity function instead –
function will search through our current scene and return the first object it finds of a certain type, which is why it’s enough for us to declare a private
variable to hold the reference we need.
Finally, let’s insert the appropriate call to
inside of our
And with that – congratulations! You now have a fully working version of Atari Combat, updated for the modern era. Make sure to playtest your game to make sure everything is working as it should. (Remember to set the correct
value for each Tank’s
It’s now up to you how you want to design your level. Personally, I will do my best to recreate the classic design of the Combat level pictured at the beginning of this tutorial by moving and shaping a set of cubes:
Thank you for sticking through with this tutorial until the end and for persevering through with making a complete game! Whether or not you made it out to our workshop in person or not, I hope you’ve picked up on a number of key concepts about making games in Unity and C#.
If you’re looking to improve or expand upon the game from here, there are certainly many directions you could take it. Let me offer a few suggestions off the top of my head:
· You’ll notice we have a couple of unused sound effects inside our
folder. Can you think of a suitable place to insert these in the game? What actions should trigger them to start or stop playing?
· Is it really fair that a player can damage him- or herself with their own missile and give their opponent points? What changes could you implement to make sure that only an opponent’s missile can damage a given Tank?
· Typically games will have some functionality in place to prevent a player from taking damage too quickly in a row by making them invincible for a second or two after they take damage – how could you go about implementing this?
· What if we want to play another round immediately without closing down our game and re-opening it? What mechanisms would have to be in place, and which variables would have to be reset in order for a “Play Again” button to work as expected?