Creators – Week 17

This week we:

  • Added sound to our game
  • Made our missiles explode when they hit an obstacle
  • Changed our lighting, environment materials and skybox
  • Made our ship go into a special invulnerable mode just after hitting an object

A lot of progress! Let’s get into it.

Audio Files

We sourced three audio files:

  • A musical track to play as our game theme
  • The sound of a missile being fired
  • The sound of an explosion

There are lots of places to find royalty free music and sound online. Freesound.org is one. We placed them in an folder in the project called Audio.

Game Audio

For the game audio, we added an empty game object at the top of our scene called [Audio] and added an AudioSource component to it, setting the clip to our game theme and making sure that Play on Awake and Loop were both set to true.

Shooting

To have the sound of a missile shooting we added an AudioSource to our Player object and set the clip to our shooting sound and set both Play on Awake and Loop to false. In our ShipController.cs we added a new private property:

private AudioSource _audioSource;

which we then assigned automatically in the Start() function:

  void Start()
  {
    _minTimeBetweenShots = 1.0f / FireRate;
    _audioSource = GetComponent<AudioSource>();
  }

GetComponent<T>() looks for a component of the requested type (here AudioSource) on the current GameObject and returns it.

Finally, in Shoot(), we added the following:

    if (_audioSource != null)
      _audioSource.Play();

Destroy On Contact

We wrote a script to destroy something if it hits something else. This is it:

using UnityEngine;

public class DestroyOnContact : MonoBehaviour
{
  public GameObject DestroyPrefab;

  private void OnTriggerEnter(Collider other)
  {
    if (DestroyPrefab != null)
    {
      Instantiate(DestroyPrefab, transform.position,
                                 transform.rotation,
                                 other.transform);
    }

    Destroy(gameObject);
  }
}

The code simply calls Destroy(gameObject) when contact is detected. It also has an optional GameObject called DestroyPrefab. If this is supplied, it will be created at this items current position and rotation, but it will be parented to the thing that was hit, meaning if that thing is moving, then the DestroyPrefab will continue to move with it.

Destroy After Seconds

Another simple script that destroys the attached GameObject after a given number of seconds.

using UnityEngine;

public class DestroyAfterSeconds : MonoBehaviour
{
  public float TimeToLive = 1.0f;

  // Start is called before the first frame update
  void Start()
  {
    Destroy(gameObject, TimeToLive);
  }
}

The Destroy() function already has an optional delay argument, so this is very easy to write.

Explosion Prefab

We created our Explosion prefab last week. It was just a quad with a script to keep it always pointing directly at the camera.

To that we added a DestroyAfterSeconds component with a Time To Live of one second and an AudioSource component where the clip was set to our explosion sound, Play on Awake was set to true and Loop was set to false.

Updates to the Missile Component

The original missile was very small, so we scaled the model part to (3, 3, 3). We then added a BoxCollider, a kinematic RigidBody and a DestroyOnContact component. For the DestroyOnContact component, we set the Destroy Prefab property to our Explosion prefab.

Skybox, Lighting and Colours

We imported a image of stars into our Textures folder. In the Material folder we created a new Material called StarsSkybox. We changed the Shader to Skybox/Panoramic and assigned our stars image to the Spherical (HDR) slot. We also changed Image Type to 180 degrees.

To assign this skybox to our scene, we used the Window|Rendering|Lighting menu to open the Lighting dialog and set the skybox material at the top of the Environment tab.

We changed the colours of our Environment_main and Environment_details0 materials to #BF4C00 and #EC9100 respectively. We then applied these materials to all our Obstacle prefabs as well.

Finally we increased the intensity of our Directional Light object from 1 to 1.5.

Making Ship Go Invulnerable After Hitting an Object

We want our ship to go into a special invulnerable mode after hitting an obstacle. Specifically we want it to:

  • Change appearance to be partally transparent
  • Still be able to move, but not be able to shoot
  • Be invulnerable to collisions
  • Return to normal after two seconds

To achieve this we had to first duplicate the Ship_body and Ship_details materials as Ship_body_transp and Ship_details_transp respectively. On both of these new materials we set the Rendering Mode to Transparent and edited the Albedo to change the Alpha (transparency) value from 255 (solid) to 127 (half transparent).

We then created a duplicate of the Ship model under the Player game object and called it Ship Transparent, we changed it’s materials to the transparent ones and set it inactive by default.

In ShipController.cs we added several new public and private properties:

  public GameObject StandardShip;
  public GameObject InvulnerableShip;

  private bool _shootingDisabled = false;

  private Collider _collider;

We added code in Start() to set _collider:

_collider = GetComponent<Collider>();

In Update() we added code to check if we’re allowed to shoot:

    // Shooting
    if (_shootingDisabled == false &&
        _controls.Ship.Shoot.WasPerformedThisFrame())
    {
      Shoot();
    }

Finally we added three more related functions:

private void SetMode(bool isInvulnerable)
  {
    // Set the ship models on/off
    StandardShip.SetActive(!isInvulnerable);
    InvulnerableShip.SetActive(isInvulnerable);

    // Set shooting on/off
    _shootingDisabled = isInvulnerable;

    // Set contact on/off
    _collider.enabled = !isInvulnerable;
  }

  public void SetModeNormal()
  {
    SetMode(false);
  }

  public void SetModeInvulnerable()
  {
    SetMode(true);

    Invoke("SetModeNormal", 2.0f);
  }

The function SetMode() does all the work of switching modes from normal to invulnerable. The two functions SetModeNormal() and SetModeInvulnerable() just call it except that SetModeInvulnerable() also puts in delayed call to SetModeNormal() after two seconds. This means after we go invulnerable, we’ll automatically be vulnerable again after two seconds.

Finally, we just needed to call this in OnTriggerEnter():

  private void OnTriggerEnter(Collider other)
  {
    SetModeInvulnerable();
  }

Getting the Code

All the code we’re made this year is on our GitHub. It can be found here. If you don’t have the latest version of our code before any session, use the green Code button on that page to get the “Download ZIP” option which will give you a full copy of all code we’ll be writing this year.

Leave a comment