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.
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.
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.
|
---|
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.
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.
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.
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.
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.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using UnityEngine; using System.Collections; public class EuclideanTorus : MonoBehaviour { // Update is called once per frame void Update () { // Teleport the game object if(transform.position.x > 9){ transform.position = new Vector3(-9, transform.position.y, 0); } else if(transform.position.x < -9){ transform.position = new Vector3(9, transform.position.y, 0); } else if(transform.position.y > 6){ transform.position = new Vector3(transform.position.x, -6, 0); } else if(transform.position.y < -6){ transform.position = new Vector3(transform.position.x, 6, 0); } } } |
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.
- Object: large asteroid – Tag: Large Asteroid
- Object: small asteroid – Tag: Small Asteroid
- Object: ship – Tag: Ship
- 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.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
using UnityEngine; using System.Collections; using UnityEngine.UI; public class GameController : MonoBehaviour { public GameObject asteroid; private int score; private int hiscore; private int asteroidsRemaining; private int lives; private int wave; private int increaseEachWave = 4; public Text scoreText; public Text livesText; public Text waveText; public Text hiscoreText; // Use this for initialization void Start () { hiscore = PlayerPrefs.GetInt ("hiscore", 0); BeginGame (); } // Update is called once per frame void Update () { // Quit if player presses escape if (Input.GetKey("escape")) Application.Quit(); } void BeginGame(){ score = 0; lives = 3; wave = 1; // Prepare the HUD scoreText.text = "SCORE:" + score; hiscoreText.text = "HISCORE: " + hiscore; livesText.text = "LIVES: " + lives; waveText.text = "WAVE: " + wave; SpawnAsteroids(); } void SpawnAsteroids(){ DestroyExistingAsteroids(); // Decide how many asteroids to spawn // If any asteroids left over from previous game, subtract them asteroidsRemaining = (wave * increaseEachWave); for (int i = 0; i < asteroidsRemaining; i++) { // Spawn an asteroid Instantiate(asteroid, new Vector3(Random.Range(-9.0f, 9.0f), Random.Range(-6.0f, 6.0f), 0), Quaternion.Euler(0,0,Random.Range(-0.0f, 359.0f))); } waveText.text = "WAVE: " + wave; } public void IncrementScore(){ score++; scoreText.text = "SCORE:" + score; if (score > hiscore) { hiscore = score; hiscoreText.text = "HISCORE: " + hiscore; // Save the new hiscore PlayerPrefs.SetInt ("hiscore", hiscore); } // Has player destroyed all asteroids? if (asteroidsRemaining < 1) { // Start next wave wave++; SpawnAsteroids(); } } public void DecrementLives(){ lives--; livesText.text = "LIVES: " + lives; // Has player run out of lives? if (lives < 1) { // Restart the game BeginGame(); } } public void DecrementAsteroids(){ asteroidsRemaining--; } public void SplitAsteroid(){ // Two extra asteroids // - big one // + 3 little ones // = 2 asteroidsRemaining+=2; } void DestroyExistingAsteroids(){ GameObject[] asteroids = GameObject.FindGameObjectsWithTag("Large Asteroid"); foreach (GameObject current in asteroids) { GameObject.Destroy (current); } GameObject[] asteroids2 = GameObject.FindGameObjectsWithTag("Small Asteroid"); foreach (GameObject current in asteroids2) { GameObject.Destroy (current); } } } |
1 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using UnityEngine; using System.Collections; public class BulletController : MonoBehaviour { // Use this for initialization void Start () { // Set the bullet to destroy itself after 1 seconds Destroy (gameObject, 1.0f); // Push the bullet in the direction it is facing GetComponent<Rigidbody2D>() .AddForce(transform.up * 400); } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
using UnityEngine; using System.Collections; public class AsteroidController : MonoBehaviour { public AudioClip destroy; public GameObject smallAsteroid; private GameController gameController; // Use this for initialization void Start () { // Get a reference to the game controller object and the script GameObject gameControllerObject = GameObject.FindWithTag ("GameController"); gameController = gameControllerObject.GetComponent <GameController>(); // Push the asteroid in the direction it is facing GetComponent<Rigidbody2D>() .AddForce(transform.up * Random.Range(-50.0f, 150.0f)); // Give a random angular velocity/rotation GetComponent<Rigidbody2D>() .angularVelocity = Random.Range(-0.0f, 90.0f); } void OnCollisionEnter2D(Collision2D c){ if (c.gameObject.tag.Equals("Bullet")) { // Destroy the bullet Destroy (c.gameObject); // If large asteroid spawn new ones if (tag.Equals ("Large Asteroid")) { // Spawn small asteroids Instantiate (smallAsteroid, new Vector3 (transform.position.x - .5f, transform.position.y - .5f, 0), Quaternion.Euler (0, 0, 90)); // Spawn small asteroids Instantiate (smallAsteroid, new Vector3 (transform.position.x + .5f, transform.position.y + .0f, 0), Quaternion.Euler (0, 0, 0)); // Spawn small asteroids Instantiate (smallAsteroid, new Vector3 (transform.position.x + .5f, transform.position.y - .5f, 0), Quaternion.Euler (0, 0, 270)); gameController.SplitAsteroid (); // +2 } else { // Just a small asteroid destroyed gameController.DecrementAsteroids(); } // Play a sound AudioSource.PlayClipAtPoint( destroy, Camera.main.transform.position); // Add to the score gameController.IncrementScore(); // Destroy the current asteroid Destroy (gameObject); } } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
using UnityEngine; using System.Collections; public class ShipController : MonoBehaviour { float rotationSpeed = 100.0f; float thrustForce = 3f; public AudioClip crash; public AudioClip shoot; public GameObject bullet; private GameController gameController; void Start(){ // Get a reference to the game controller object and the script GameObject gameControllerObject = GameObject.FindWithTag ("GameController"); gameController = gameControllerObject.GetComponent <GameController>(); } void FixedUpdate () { // Rotate the ship if necessary transform.Rotate(0, 0, -Input.GetAxis("Horizontal")* rotationSpeed * Time.deltaTime); // Thrust the ship if necessary GetComponent<Rigidbody2D>(). AddForce(transform.up * thrustForce * Input.GetAxis("Vertical")); // Has a bullet been fired if (Input.GetMouseButtonDown (0)) ShootBullet (); } void OnTriggerEnter2D(Collider2D c){ // Anything except a bullet is an asteroid if (c.gameObject.tag != "Bullet") { AudioSource.PlayClipAtPoint (crash, Camera.main.transform.position); // Move the ship to the centre of the screen transform.position = new Vector3 (0, 0, 0); // Remove all velocity from the ship GetComponent<Rigidbody2D> (). velocity = new Vector3 (0, 0, 0); gameController.DecrementLives (); } } void ShootBullet(){ // Spawn a bullet Instantiate(bullet, new Vector3(transform.position.x,transform.position.y, 0), transform.rotation); // Play a shoot sound AudioSource.PlayClipAtPoint (shoot, Camera.main.transform.position); } } |
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.
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.
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.
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.
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.
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.
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.
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.
Hey Im sorry for my english but i am not a native speaker….
I get alot of error’s in the asteroids controller script.
Mainly after the //play a sound bit…
The game teleports me in the middle of the screen after shooting.
And the bullets als deflect of the astrtoids.
I really don’t know the problem and I think its important for future coding.
Hi Kaine,
You will get errors in scripts until they are all coded and references have been added (near the end). Also, behaviour like bouncing/rebounding/falling will be weird as well. Be sure to complete the section “Adding all the Rigidbody 2D and Polygon Collider 2D components” to configure these behaviours as well.
I followed your tutorial and for some reason the asteroids dont seem to be spawning, everything else works and i have no errors
actually this is coming up in unity:
NullReferenceException: Object reference not set to an instance of an object
GameController.BeginGame () (at Assets/Scripts/GameController.cs:44)
GameController.Start () (at Assets/Scripts/GameController.cs:25)
Hi Chad, thanks for your question. This might be caused by not having associated the large asteroid prefab with the public GameObject Asteroid reference on the GameController script. Take a look back to the first few paragraphs in the Adding references to the public variables from all the scripts section.
Thank you i got it, appreciate it
Hi, I finished the tutorial but I am having some issues.
First of all the SCORE doesn’t update on screen, it just stays 0, but the HISCORE does update (if I destroy enough asteroids, of course). The second problem is with the bullets, they don’t seem to spawn every time I press the mouse button. It feels like they spawn irregularly even if I “spam” the button.
In addition there are some things I need clarified.
For example what does the “f” stand for in
float thrustForce = 3f;
or
Instantiate(smallAsteroid, new Vector3(transform.position.x – .5f, transform.position.y – .5f, 0), Quaternion.Euler(0, 0, 90));
I understand it’s some kind of a unit, but what exactly?
Then there is an issue with the Euclidean Torus effect. There seems to be an “invisible area” where you can’t see neither the asteroids nor the ship. I decided to play around with the numbers (seems like 1 corresponds to 1 square) and changed the -9 to -7, 9 to 7, 6 to 5 and -6 to -5 but I didn’t get the effect I was expecting. Instead of seeing a part of the asteroid on one side of the screen and the rest on the other side, the asteroid would just teleport altogether.
Also I would like to know how all this relates to pixels and resolutions. I assume and correct me if I am wrong, ideally we would be working with vector graphics for a game like this.
A few more things, say that I want to fire bullets with the space button on my keyboard along (or without) the mouse, how do I do that?
When we press escape I would like the game to be PAUSED and prompt with CONFIRM and CANCEL button and then we can use the mouse to click. An alternative would be when we press ESC to see QUIT in the middle and next to it a Y/N for yes or no respectively, which you select with the keyboard, left or right arrow, it underlines it and we confirm it with Enter.
There must be missing a left parentheses in the “Coding the AsteroidController script” part where it says
// Play a sound
AudioSource.PlayClipAtPoint
destroy, Camera.main.transform.position);
Sorry for the lengthy comment. Overall I think the tutorials are very cool. Lunar lander looks simple, not sure if it’s a step up. A racing game would be fun too. Thanks!
Hi Vince,
Thanks for your comment. I will try and help you fix these things.
Re the score not going up: Have you completed this step? 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 Text field.
Re the f syntax. The f stands for float it enables the compiler to distinguish between a float type variable and a double which has more precision but uses more memory too.
To react to the space key try:
if (Input.GetKeyDown ("space")) { // Your code here}
The Euclidean Torus numbers were estimated by dragging an empty object around the scene view and observing the location of the transform location. The values are in Unity units which are independent of pixels so that they work on different screen resolutions. You can think of Unity units as anything you like. Perhaps kilometres in a space sim or metres in a platform game. I think of them universally as “game world” units. The teleporting effect is a limitation of the code. To create the more authentic feel of the original Asteroids would take more work.
Handling paused is not very tough but involves a slightly lengthy explanation. The next game (a simple platformer) will use states and show how to do this.
Yes, there is a missing parenthesis. Many thanks, I just replaced it.
The text fields were correct but the line that updates the score in the GameController script was “commented”. I removed the “//” and now the score updates as it should.
I also added the space button but unfortunately the bullets don’t fire as I would like them to. Is there some limitation or some line that I have to “play” with? Basically I want every click to correspond to a bullet being fired. Perhaps even add the option to fire bullets as long as the button is pressed down.
I will be waiting for that next tutorial!
The code should be straightforward. Just instantiate a bullet on pressing the spacebar. Perhaps I am missing something. Like the commented out line of code. Thanks for pointing that out.
I tried to move the part of the code that instantiates a bullet to a “void Update ()” function,
instead of FixedUpdate() and now I can fire bullets as fast as my finger can!
Nice one Vince. Thanks for sharing.
I did the tutorial and it is working but when i shoot an asteroid, only the hiscore is changing and im not receiving any actual score.
Hi Tom,
Have you completed this step?
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 Text field
Hey there I did the tutorial and in the finish up when I press start nothing happens it’s just my player ship and I can move the ship and rotate, fire and the sound plays but no Asteroids spawn.
I decided to place a small asteroid and a large asteroid into the scene I just wanted to see if the score would work the asteroids wouldn’t destroy and the large one didn’t split no matter how many times I hit them and the sound played that indicated the ship had been struck and my score went up by 1 everytime i hit one of the asteroids
all im getting in the console is “Default GameObject Tag: GameController already registered” pls help
Sorry also getting Small Asteroid is not defined
Hi Dan,
It could be that the reference to the large asteroid prefab hasn’t been dragged to the GameController script and the small asteroid reference still needs connecting up to the large asteroid script. Hope this helps.
Hi John that worked and now Asteroids is running thanks for the help
Great. Thanks for commenting.
hey there a followed your tutorial but when a start the game my ship doesn’t collide with the asteroids it just passes through them is there anyway a can fix this?
Hi Sam,
The most likely causes are that you have not added the Polygon Collider 2D to the ship or the script which responds to the collisions.
I get the error that a rigid body is not attached to ship controller, I went back through the tutorial and didnt find the rememdy, any help would be appreciated, my game development knowledge ends at bad sprites….
Hi Kaleb,
Try checking the section just after you download the sound fx to see if that. Solves it.
Good luck,
John
Hello
Everything works fine, except that i cant seem to destroy the asteroids, the bullets just fly trough them and nothing happens.
Hi Ryan,
Can the ship collide with the asteroids? If yes, check you have a collider on the bullet. If no, check the collider on bullet and asteroid.
The ship gets destroyed by the asteroids as it should, i shall check the bullet collider
https://i.gyazo.com/426530fe52ff526e1d2ca1c980e58196.png Here is a screen shot of the bullets inspector window. is everything how it should look, i have only begun to use this program. So forgive me if i might seem a little dense
A couple of possibilities. I suggest trying them in this order:
Hope this helps.
Right, so my gravity works, my collisions work but only one asteroid spawns, and i cant add scripts to it if its a prefab?
Hi Zach,
This is the code that spawns the asteroids in the GameController class.
void SpawnAsteroids(){
DestroyExistingAsteroids();
// Decide how many asteroids to spawn
// If any asteroids left over from previous game, subtract them
asteroidsRemaining = (wave * increaseEachWave);
for (int i = 0; i < asteroidsRemaining; i++) { // Spawn an asteroid Instantiate(asteroid, new Vector3(Random.Range(-9.0f, 9.0f), Random.Range(-6.0f, 6.0f), 0), Quaternion.Euler(0,0,Random.Range(-0.0f, 359.0f))); } waveText.text = “WAVE: ” + wave; }
Now im getting an error saying Object reference not set to an instance of an object. Is this a code problem? i took the code word for word
The most likely solution is in this section “Adding references to the public variables from all the scripts”. This error indicates that you are using an object that is unitiialized. The section associates the various prefabs to be used to initialize the various objects.
so I followed the tutorial word for word and I am getting these two errors: NullReferenceException: Object reference not set to an instance of an object
AsteroidController.Start () (at Assets/Scripts/AsteroidController.cs:21)
and this one: NullReferenceException: Object reference not set to an instance of an object
ShipController.gamecontroller (UnityEngine.GameObject gameControllerObject) (at Assets/Scripts/ShipController.cs:29)
ShipController.Start () (at Assets/Scripts/ShipController.cs:23)
not sure what I did wrong but help would be appreciated also my little asteroids wont break and none of the score waves or hiscore update
Is it possible you missed a section? Perhaps this one:
“Adding references to the public variables from all the scripts”
Hi!
I have a problem with the ship. I can’t control it, it moves as it wants, it`s also immortal. I try to say that a collision with asteroids doesn`t harm him. What am I missing?
Have a look at the “Adding all the Rigidbody 2D and Polygon Collider 2D components” section for collisions. Also look at the following line of code in the ShipController class which thrusts the ship forwards.
// Thrust the ship if necessary().
GetComponent
AddForce(transform.up * thrustForce *
Input.GetAxis(“Vertical”));
I can only rotate it. Or should it be? I just don’t see the ability to control the ship in the code .
it keeps resetting the whole game when i shoot
i figured it out for some reason my bullets kill me and not the asteroids
Here are some guesses as to the cause.
Did you set the player collider to isTrigger?
Did you set the “Ship” tag and the “Bullet” tag? Otherwise they would trigger the if (c.gameObject.tag != “Bullet”) { code would trigger on anything untagged.
All the best,
John
It is all great except that, when I build a version it only shoots twice, while in the editor it has no problems
(note, I changed the button from the left mouse to spacebar)
even with your version it only shoots twice.
Do you have any advice?
Thanks in advance!
Caste
Hi there,
This is difficult to troubleshoot. I would guess the problem is more likely to be in the configuration of the prefabs, labels etc than in the script but I can’t point to a direct cause. Consider doing some of the earlier shorter tutorials and see if you have missed something. It is also possible that the latest version of Unity has changed something fundamental that I am unaware of.
Sorry I can’t give a definite anser.
I got most things working except i cant control the player, they fly up and disappear every time, the bullets stay once they have been shot and dont leave and finally i cant seem to control how i move my player.
Hmm not sure. Here are a few possibilities. Did you add a RigidBody to the bulet and make the prefab and did you add this code
public class BulletController : MonoBehaviour {
// Use this for initialization
void Start () {
// Set the bullet to destroy itself after 1 seconds
Destroy (gameObject, 1.0f);
// Push the bullet in the direction it is facing()
GetComponent
.AddForce(transform.up * 400);
}
}
And did you “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.”
Hopefully this might fis something.