patreon

 

 

Welcome to the Asteroids arcade game project built in Unity. In this step-by-step guide, we will make a reasonably authentic clone of the classic arcade game. If you never had the joy of playing Asteroids then why not go and learn a little about it. Asteroids came out in 1979 and what made it so special for me was the rapid fire. After Space Invaders which forced the player to make each and every shot count, the freedom to hammer the fire button and see a stream of pixels pour out the nose of my triangle-shaped space ship was a genuine thrill.

About this project

Skill level 1
Time to complete 90 minutes

New concepts

  1. Organizing the project’s assets
  2. Structuring scripts
  3. Using a game controller object and script
  4. Putting everything together to make a full, playable game

Let’s get started by creating a new project. Start Unity and create a new project called Asteroids. Be sure to select the 2D option.

Importing and organizing the assets

As we will have around a dozen scripts, sprites, sounds, prefabs, and materials, it is wise to be a little bit more organized than we were in previous tutorials. What we will do is make a folder for keeping each type of asset. In the Project window, right-click and select Create | Folder. Name the folder Sprites. You can probably guess what will go in here. Next, create four more folders in the same way. Name them, Physics Materials, Prefabs, Scripts and Sounds. When you’re done, your Project window should look the same as mine.

Unity Project window organized with folders

Unity Project window organized with folders

The Asteroids game takes place in space (duh) and has a completely black screen. Change the scene to have a black background by left-clicking the Main Camera object in the Hierarchy window and selecting a black color after clicking in the Background property in the Inspector window. The Game window will now be blank and black.

Download the four graphics shown next. One for each of a large asteroid, small asteroid, bullet, and ship.

The Asteroids spaceship graphic

The bullet graphic/pixel

The large asteroid graphic (not shown to scale). Any slight resemblance to a continent is entirely coincidental.

 

The small asteroid graphic

Right-click in the Project window and select Import New Asset…, choose the large asteroid image. Do the same for the rest of the images. To tidy up the Project window, drag each of the four sprites into the Sprites folder. If you expand the Sprites folder then the Project window will look like this.

Sprites neatly organized in the Sprites folder

Sprites neatly organized in the Sprites folder

One at a time, drags each of the four sprites into the Hierarchy window. In the Scene window, space the game objects out using move mode (W) from each other, so we can more easily do some work on them. Mine look like this next image but yours don’t have to be exactly the same.

Asteroids game objects in the Unity Scene window

Asteroids game objects in the Unity Scene window

We will come back to these game objects soon. Now we will add the three sound effects shown next. You can download each sound effect by right-clicking the text link and choosing the appropriate option for your Web browser. You can also click the play icons for each to hear what they sound like.

asteroids-destroy

asteroids-ship-explode

asteroids-ship-shoot

When you have downloaded the sounds, import them into the project by right-clicking in the Project window and selecting Import New Asset…. When you have imported all three, arrange them tidily in the Sounds folder. We have now imported everything we need.

Adding all the Rigidbody 2D and Polygon Collider 2D components

All the game objects will be moved around the screen during gameplay, so they will each need a Rigidbody 2D component. In the Hierarchy window, click on each of the bullet, large asteroid, ship, and small asteroid, in turn, and in the Inspector window add the component by clicking the Add Component button and selecting Physics 2D | Rigidbody 2D.

Each of the game objects will need to collide with other game objects. To achieve this we will use a Polygon Collider 2D on each of them. In the Hierarchy window, click on each of the bullet, large asteroid, ship, and small asteroid, in turn, and in the Inspector window add the component by clicking the Add Component button and selecting Physics 2D | Polygon Collider 2D.

For the ship game object, perform the extra step of checking the Is Trigger checkbox.

Each of the Polygon Collider 2D components will need to be edited manually to wrap the exact shape of each game object. The next image shows what the end result of each of them will look like. If you are unsure how to achieve this then take a look at the Lights, sound, and a bit more collision project. In that project, we edited an Edge Collider 2D. The technique is the same for a Polygon Collider 2D. The only difference is the Polygon Collider 2D joins up with itself at the end. Here is the end result. Note that the images are not exactly to scale with each other. For example, the bullet is significantly zoomed-in.

asteroids-polygon-collider-2d-wrapped-around-game-objects

Note that Unity is sometimes a bit inconsistent when adding Polygon Collider 2D components. The first time I built this game the small asteroid was wrapped perfectly, automatically by Unity but the large asteroid wasn’t. The second time, Unity made me do the small asteroid manually but double-wrapped both the inside and outside of the large asteroid, automatically. As long as your colliders end up looking roughly like those in the image above, everything should work just fine.

The last thing we will do in this section of the tutorial is to add a Physics Material 2D to the two asteroid objects. In the original Asteroids game, the asteroids floated through each other. It seems a shame if we are using an advanced tool like Unity, not to have a bit of fun with bouncing asteroids. In the Project window, right-click and select Create | Physics 2D Material. Name the new material Asteroids Material. In the Inspector window, set its Bounciness to 1 and its Friction to .4. To keep the project tidy, drag the new Asteroids Material into the Physics Materials folder we created at the start of the project.

Select the large asteroid object in the Hierarchy window then drag & drop Asteroids Material from the Project window to the Material field on the Polygon Collider 2D component, in the Inspector window. Repeat this step for the small asteroid object.

Try running the game and all four objects will slide off the bottom of the screen.

We need an Euclidean Torus

We need a Euclidean Torus

Let’s try and recreate the same behavior as the original Asteroids game with a Euclidean Torus.

Implementing a simple Euclidean Torus

In the original arcade game, when objects moved off the left they would come back on the right and vice versa. If they went off the bottom they would come back on the top, etc. This is the Euclidean Torus effect. Our implementation will not be as good as the original but it should be good enough to give the game the same sense of late seventies magic. My trousers have gone all flared. AH, my jumper!

Right-click in the Project window and select Create | C# Script. Name the script Euclidean Torus. Drag the script into the Scripts folder to keep things tidy. Now, double-click the EuclideanTorus script to open it in MonoDevelop. Edit the code in the EuclideanTorus script to be exactly the same as this next code.

The code simply checks if the position of the game object it is attached to has left the screen on either the left, right, top or bottom. If it has then it places it back on the opposite side. The values 9, -9, 6 and -6 are in Unity units. The values can be ascertained by moving a game object in the Scene window and then observing the Transform component in the Inspector window.

On each of the bullet, large asteroid, ship, and small asteroid, in turn, select the object in the Hierarchy window then in the Inspector window click Add Component | Scripts | Euclidean Torus. All four of the game objects will now respond to the Euclidean Torus script. Run the game and watch the perpetual falling. All the objects continually go off the bottom and then reappear back on the top, each pass getting faster and faster.

To disable this “falling” behavior which was only left in for demonstration purposes, select each object in turn, in the Hierarchy window, and set the Gravity Scale field to 0, in the Inspector window. If you run the game again, all the objects will float nicely in space.

Coding the ship, bullet, asteroids, and game controller

This part of the tutorial took a bit of thought. The reason for this is that we need to code/add a script to each of the four game objects as well as a new GameController object. The code that we will write for each will often be dependent upon the code from one or more of the other scripts/objects. We could spend hours, jumping from object to object and script to script, making sure that we add dependent code as it is required or- I could just get you to copy & paste the whole lot and then talk about it afterward. I opted for the second approach. As a result, don’t try and run the game until we are finished with this section, it probably won’t work. Also, your scripts will show some errors until we are done.

Adding the GameController object and making the prefabs

In order for the scripts we will soon write, to be able to identify different types of objects in our game we need to add a tag to each of the game objects, including the Game Controller.

Select each of the four objects in turn, in the Hierarchy window and add the following tags to the following objects. If you need help adding tags, take a look at the Collisions and destroying objects in Unity project that does this step by step.

  1. Object: large asteroid – Tag: Large Asteroid
  2. Object: small asteroid – Tag: Small Asteroid
  3. Object: ship – Tag: Ship
  4. Object: bullet – Tag: Bullet

We will assign a tag to the Game Controller object in just a minute after we create it.

Creating the Game Controller

Before we dive into the code, we need a game controller object that will coordinate everything. Right-click in the Hierarchy window and select Create Empty. Name the new object Game Controller and make sure you did not accidentally make it a child of another class. If you did by mistake just left-click and drag it away to separate it. Now add a tag to the new object. Name the tag GameController. Note that unlike the other tags it has no spaces.

Making prefabs from game objects

It is obvious that we will need more than one of each asteroid type and more than one bullet. Drag each of the large asteroid, small asteroid, and bullet objects and drop them into the Prefabs folder in the Project window. We have made a reusable prefab out of the game objects. We don’t need the game objects anymore. Just double-check in the Prefabs folder that the last step was successful and you have three prefabs there, then delete small asteroid, large asteroid, and bullet, from the Hierarchy window.

Save the entire scene with File | Save Scene as… Name the scene as, scene.

This is what the Project and Hierarchy windows should look like.

 

hierarchy-and-scene-view-at-this-stage

Let’s get coding.

Coding the GameController script

Create a new C# script as we did before and call it GameController. Double-click on it in the Project window to open it in MonoDevelop. Edit the code to be exactly the same as this next code.

This is the longest and most complex of all the scripts but it is not actually complex when you split it up into chunks. First of all, note the int variables declared at the start. Next, notice the four Text objects and their names.

The Start method loads the hi score when the game first starts. If you want to understand more about loading and saving, see the Unity UI and data persistence project. The Start method then calls the BeginGame method that we will talk about soon.

The Update method simply checks to see if the player has pressed the Escape key and if he has, quits the game.

The BeginGame method sets all the variables to how they need to be at the start of a game. The score is zero, lives is 2, etc. Then in the BeginGame method, the Text objects have their text properties set using the variables we just discussed. This has the effect of resetting the HUD to how it should be at the start of the game. The last line of code in BeginGame is the call to the SpawnAsteroids method.

The SpawnAsteroids method works out how many asteroids is required this wave then loops through a for loop spawning them at random positions using the Random.Range method.

Next, we have the IncrementScore method. Note the method is public so it can be called by a reference to GameController. We will see this in action soon. Inside the IncrementScore method, the score is incremented(duh) the text in the HUD is updated and a check is done to see if a new high score has been reached. If a new high score has been reached the hi score is saved. The method then checks if the number of remaining asteroids is zero, and if so, increments the wave and calls SpawnAsteroids.

The DecrementLives method does just that, decrements lives and then checks if the player has lost their last life. If the player has no lives remaining the game is immediately restarted by calling BeginGame. Again, notice this method is public.

The DecrementAsteroids function does what the name suggests and nothing more.

The SplitAsteroids method basically adds two to the number of asteroids. Read the comments in the code if you need more information.

Finally, for the GameController script, we have the DestroyAsteroids method which is called when a new game is started. Otherwise, each time the player lost their last life the game would restart with four new asteroids plus any left over from their last game. The method works by using the tags of the asteroids to gather them all in an array and then loop through destroying them, one at a time.

Coding the BulletController script

Create a new C# script as we did before and call it BulletController. Double-click on it in the Project window to open it in MonoDevelop. Edit the code to be exactly the same as this next code.

This is the simplest of all the scripts. It only has a Start method. In it we call the Destroy method. This sounds odd at first. If you check the second parameter, however, you can see we are telling the bullet to destroy itself after one second. This is just right for the life of a bullet in an Asteroids game. The second and final line of the code applies a force of 400 in whatever direction the bullet is facing( transform.up). This will make sense when you see how we spawn the bullets from the ShipController script.

Coding the AsteroidController script

Create a new C# script as we did before and call it AsteroidController. Double-click on it in the Project window to open it in MonoDevelop. Edit the code to be exactly the same as this next code.

The  Start method of the AsteroidController script does two things. First, it gets a reference to the GameController object so it can call some of its methods. Secondly, it adds some movement( AddForce) and turns ( angularVelocity) to the object.

The OnCollisionEnter2D method handles what happens when the Asteroid collides with something. The Unity physics engine handles all the bouncing with other asteroids, all we have to do is handle colliding with a bullet. Therefore the first thing the code does is check if the object involved with the collision has a tag of Bullet. If it does then the bullet is destroyed. The if/ else block that follows handles two cases. If the asteroid is a large asteroid then three small asteroids are randomly spawned. Notice that the SplitAsteroid method is called using the GameController reference. If the asteroid was small it is destroyed and the DecrementAsteoids method is called. Finally, a sound effect is played, the score is incremented and the asteroid is destroyed.

Coding the ShipController script

Create a new C# script as we did before and call it ShipController. Double-click on it in the Project window to open it in MonoDevelop. Edit the code to be exactly the same as this next code.

In this final script, notice again we have a reference to the GameController object, just as we did in the AsteroidController script. The FixedUpdate method tracks the position of th WASD keys and applies rotation and force (thrust)as required. The final line of code in the FixedUpdate method checks if the mouse button has been clicked. If it has the ShootBullet method is called.

The ShootBullet method instantiates a bullet from the prefab and sets its position and rotation. Notice that the rotation is set to that of the ship. When the Start method in the BulletController script runs it will already be facing the correct direction. Finally, a sound effect is played.

 Adding scripts to the appropriate game objects

Unity is really versatile and we can add the appropriate scripts to the related prefabs and game objects easily. In the Project window, drag and drop the AsteroidController script onto the large asteroid prefab. Also, drag and drop the AsteroidController script onto the small asteroid prefab. If you are skeptical, select the large asteroid prefab and confirm in the Inspector window that the appropriate script component has been added.

Drag and drop the BulletController script onto the bullet prefab. Now drag and drop the ShipController script onto the ship object in the Hierarchy window. Lastly, drag and drop the GameController script onto the Game Controller object in the Hierarchy window.

Adding references to the public variables from all the scripts

Each time we added a public reference to an object we need to associate it with a sound effect, prefab, game object or GUI object. We haven’t made the HUD with  GUI objects yet but we can associate all the rest.

Select the GameController object in the Hierarchy window. Drag the large asteroid prefab onto the Asteroid field, as shown next.

drag-drop-game-controller-references

Next, select the ship object in the Hierarchy window. Drag and drop the bullet prefab to the Bullet field. Drag and drop the asteroids-ship-shoot sound to the Shoot field. Drag and drop the asteroids-ship-explode sound to the Crash field. When you’re done it should look like this.

drag-drop-ship-controller-references

In the Project window, select the large asteroid prefab. Drag and drop the small asteroid prefab to the Small Asteroid field. Drag and drop the asteroids-destroy sound to the Destroy field. When you’re done it will look like this next image.

drag-drop-large-asteroid-controller-references

Finally, for this section, select the small asteroid prefab. Drag and drop the small asteroid prefab to the Small Asteroid field. Drag and drop the asteroids-destroy sound to the Destroy field. When you’re done it will look like the previous image. This is just as we did for the large asteroid prefab. A small asteroid will never actually spawn another small asteroid but it needs a reference as it is referred to in the AsteroidController script that controls it.

At this point, if you took the trouble to “comment out” // all references to Text objects in the GameController script, you could actually play the game. It won’t take long, however, to add the HUD.

Adding a HUD to show the score, hi-score, wave number, and lives remaining

In this part of the project, we will quickly add a Canvas and four Text objects. We will configure them to provide the player with a HUD showing their score, lives remaining, current wave number and the high score. We can then give the GameController script a reference to each Text object and they will be kept up to date as the game is played. We will then be finished with our Asteroids game.

In the Hierarchy window, right-click and select UI | Canvas. Make sure the Canvas object is selected. Right-click the Canvas object and select UI | Text. You will now have a Text object called Text as a child of the Canvas object. Rename text to score.

Right-click the Canvas object again and select UI | Text. You will now have another Text object as a child of the Canvas object. Rename the new Text object to lives.

Right-click the Canvas object again and select UI | Text. You will now have another Text object as a child of the Canvas object. Rename the new Text object to wave.

We need one more Text object. Right-click the Canvas object again and select UI | Text. You will now have another Text object as a child of the Canvas object. Rename the new Text object to hi score.

A common mistake with the previous few steps is to accidentally make a Text object the child of another Text object, instead of a child of Canvas. Check your Hierarchy window looks like this next image. If it doesn’t just rearrange it by dragging and dropping.

unity-canvas-with-child-text-objects

Now let’s configure the Canvas object. Make sure the Canvas object is selected in the Hierarchy window. Now, in the Inspector window configure the following properties.

  • Render Mode to Screen Space – Camera
  • Drag Main Camera from the Hierarchy window to the Render Camera field in the Inspector window
  • UI Scale Mode to Scale With Screen Size

We will now go through the Text objects, one at a time to configure them. I will explain the first one in detail so you can see how it’s done, the others will then be straightforward. Make sure that score is selected in the Hierarchy window. The first thing we need to do is define its anchor point. When Unity scales the screen the anchor point is used to work out the new position of the text. We will anchor the score to the top left. Here is how. In the Rect Transform component, click on the icon highlighted in the next image.

You can now select the top-left position by clicking the option highlighted in the next image.


Finally, for the score object, set the Text field to SCORE, set the Font Size to 20 and the Color to white.

Now, configure lives by setting the anchor point to the top-left, the Text to LIVES, the Font Size to 20 and the Color to white. Do the same for wave by setting the anchor point to top-left, the Text to WAVE, the Font Size to 20, and the Color to white.

To configure the final Text object, hi-score, set the anchor point to top-right, the Text to HISCORE, the Font Size to 20, and the Color to white.

The second to last step in the whole game is to manually move the Text objects into position so they look neat. You can switch to move mode by pressing the W key. Move the Text objects one at a time so they look roughly like this next image.

canvas-and-text-objects-arranged-with-anchor-points

The last step is to add a reference for each of our Text objects, to the GameController script on the Game Controller object. Make sure the Game Controller object is selected in the Hierarchy window. From the Hierarchy window, drag to the Inspector window the following:

The score object to Score Text field

The lives object to Lives Text field

The wave object to Wave Text field

The hiscore object to Hiscore Text field

The Game Controller(Script)  component should now look like this next image.

adding-text-references-togame-controller-script

You can now run the game. If you want to build the game and play it on your operating system, full-screen, select File | Build and Run. Here is a picture of my project running in the Unity editor.

asteroids-in-unity-completed-project

Any problems leave me a message and I will try and help. Also, let me know what project you would be interested in seeing next. Something simple but a decent step up from this one.

patreon