Greyboxing a top-down space shooter in Unity

GameDev Dustin
8 min readJan 5, 2022

--

Today we will start greyboxing a top-down space shooter prototype in the Unity game engine.

We’ll cover creating a player object, a laser (projectile) object, movement, and firing in this article.

Once you’ve created a new Unity project, go ahead and create a few folders under the “Assets” folder.

The first folder should be named “Materials”, the second “Prefabs”, the third “Scenes” (if not automatically created), and the fourth “Scripts”.

To do so, simply right click the “Assets” folder in the project window, then hover over “Create” at the top, and click “Folder” at the top of the sub-menu which appears.

Name the folder appropriately, rinse and repeat for the remaining folders.

Creating the player game object

In the game Hierarchy window, right click, hover over “3D Object”, and click “Cube”.

Go ahead and set the “Position” values in the Inspector window for our “Player” game object to 0,0,0 for the x,y,z fields.

If you do not see this in the Inspector window, make sure to click the “Player” game object in the Hierarchy window first.

Now we have our first greybox for our prototype game.

Just to clearly identify and differentiate game objects in our scene, go ahead and change the color of this cube to something that represents the player in your mind.

I went with a simple light blue.

To do so, we’ll first create a player material.

We’ll save this in our “Materials” folder, so right click on the “Materials” folder in the Project window, hover over “Create”, and click “Material” from the submenu that appears.

Rename this material to player_mat.

The reason we add the “_mat” is because once you create larger and more complex projects, you’ll find that it is easier to search and differentiate materials for various game objects when they are appropriately named.

While we have just one player material in this example, note that in a finished project there will be normal maps, height maps, albedo maps, etc.

If they are all named “player” without naming conventions such as adding “_mat”, you would have to sort through several identically named objects, image files, script files, etc to find the one you need.

File naming conventions simplify that issue ahead of time.

Now, simply drag the created “player_mat” onto either the “Player” game object in the Hierarchy window, or specifically onto the Material for the game object “Player” in the inspector window.

Make sure you have the player game object selected first if doing the latter.

Now our grey box, is whatever color you made it and just by seeing this game object’s color we know it represents the player.

Having several enemy grey boxes and a player grey box among other things can get pretty confusing pretty fast!

Let’s set the camera location to 0,1,-10.

Since most objects in our scene will be somewhere near 0,0,0, we want to pull the camera back out to make these easier to see in the game view.

On the Camera component below the Transform component we just modified for the Main Camera, set the Background to “Solid Color” and choose black or something similar from the color picker.

Adding behavior to our Player game object

It would be awfully boring to stop here.

All that would happen when you run the game is the scene would load, showing nothing but a cube sitting still.

Go ahead, hit the Play button at the top of the Unity editor.
Boring, right?

Let’s create the player script so that our game actually does something.

Right click the “Scripts” folder in our Project window, hover over “Create”, and click “C# Script”.

Rename the file to “Player”.

Now double click the “Player” script we just created and Visual Studio will open the file.

Go ahead and select all the auto generated text, then delete it.

Copy all of the text for the player script below and paste it into Visual Studio.

Save the file in Visual Studio, switch back to your Unity application and Unity will automatically update/import the script.

Player Script:

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Player : MonoBehaviour{[SerializeField]private float _playerSpeed =  7.36f;[SerializeField]private GameObject _laserPrefab;[SerializeField]private float _laserFireRate = 0.2f;private float _nextLaserFireTimeStamp = -1f;// Start is called before the first frame updatevoid Start(){//Set start position of playertransform.position = new Vector3(0, -3, 0);}// Update is called once per framevoid Update(){CalcMovement();//Fire laser at appropriate fire rateif (Input.GetButton("Fire1") && Time.time > _nextLaserFireTimeStamp){FireLaser();}}void CalcMovement(){float horizontalInput = Input.GetAxis("Horizontal");float verticalInput = Input.GetAxis("Vertical");Vector3 direction = new Vector3(horizontalInput, verticalInput, 0);//Move player based on user inputif (transform.position.x < 9f && transform.position.x > -9f){ // In horizontal boundsif (transform.position.y < 5.5f && transform.position.y > -3.8f)  // In vertical bounds{//Move playertransform.Translate(direction * _playerSpeed * Time.deltaTime);}else  // Out of vertical bounds{if (transform.position.y > 0f) {transform.position = new Vector3(transform.position.x, 5.499f, transform.position.z);}else {transform.position = new Vector3(transform.position.x, -3.799f, transform.position.z);}}}else  // Out of horizontal bounds{//Reset to boundaryif (transform.position.x > 0f) {transform.position = new Vector3(8.999f, transform.position.y, transform.position.z);}else {transform.position = new Vector3(-8.999f, transform.position.y, transform.position.z);}}}void FireLaser(){_nextLaserFireTimeStamp = Time.time + _laserFireRate;Instantiate(_laserPrefab, transform.position + new Vector3(0, 0.8f, 0), Quaternion.identity);}}

For the “Player” script to have any effect on the Player game object, we need to add the script as a component to the Player game object.

Simply drag and drop the “Player” script from the “Project” window onto the “Player” game object in the “Hierarchy” window.

Make sure that the “Player” game object is highlighted in the Hierarchy window, then scroll down as needed in the “Inspector” window.

You should see something similar to the following:

Now Unity knows that this script belongs to this game object and will run the associated code when the game object is created in the case of the Start method in our script, and every frame while the game object exists in the case of our Update method.

Since we’ve copy pasted the finished code for the player script, it will not run correctly at this time.

That is because our player script references a game object that does not exist yet, the “Laser” game object.

We want our player to shoot projectiles, so let’s go ahead and create the Laser game object and associated script.

Creating the Laser game object

Set the “Scale” of this game object to 0.2,0.2,0.2.

In Unity terms, a scale of 1 = 1 meter in the 3D game space.

That’s not overly relevant to our game, as we just want to size things relative to one another.

Just like we did before with the player game object, go ahead and create a material called “laser_mat” and apply it to the “Laser” game object.

I suggest using the color red, but use whatever makes sense to you is fine.

Now create a script in the “Scripts” folder and name it “Laser”.

Now double click the “Laser” script we just created and Visual Studio will open the file.

Go ahead and select all the auto generated text, then delete it.

Copy all of the text for the laser script below and paste it into Visual Studio.

Save the file in Visual Studio, switch back to your Unity application and Unity will automatically update/import the script.

Laser Script:

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Laser : MonoBehaviour{[SerializeField]private float _speed = 8f;[SerializeField]private Vector3 _direction = new Vector3(0, 1, 0);// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){//translate laser uptransform.Translate(_direction * _speed * Time.deltaTime);if (transform.position.y > 6.8) { Destroy(this.gameObject); }}}

Drag the “Laser” script from the project window onto the “Laser” game object in the Hierarchy window like we did for the Player game object earlier.

Now the Laser script is attached to the Laser game object.

Creating a prefab

There is one major difference between the Laser and Player game objects for our game.

While we always want to see the player game object in our scene, we only want to see the laser game object when the player fires it.

We simply cannot leave the Laser game object in the “Hierarchy” window, at least not in view.

Left click the “Laser” game object in the “Hierarchy” window and drag it down into the “Prefabs” folder of the “Project” window.

Go ahead and do the same thing for the “Player” game object.

This way if we accidentally delete the player game object from the scene, we can simply drag the prefab back into the Hierarchy window.

Notice that in the “Hierarchy” window, both game objects are new in blue text.

Any game object with blue text in the Hierarchy window is an instance linked to a prefab.

Delete the laser game object from the “Hierarchy” window by right clicking on it and selecting “delete”.

In the next article, we will go over the code in our scripts!

}

--

--

No responses yet