Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / audio

Day 87 of 100 Days of VR: Endless Flyer – Adding Magnet Audio Effects

0.00/5 (No votes)
26 Feb 2019CPOL4 min read 4.3K  
How to add magnet audio effects

Welcome back to day 87 and part 3 of adding the Magnet Power Up. In the last post, we finally created the magnet effect that allowed the coin to hover towards you.

However, there’s one problem: how do we know if the magnet power is gone? We don’t, there’s no indication at all! In today’s post, we’re going to:

  1. Add an audio cue that will play when our power-up is available once we finish this, we will move on to add 2 more power-ups and we will move on to implement something else in our game!

Step 1: Adding an Audio Cue

Step 1.1: Finding the Audio

The first thing we need to do is find a magnet sound that we might want to use. For this, I went back to freesounds.org.

I had to dig around, but I eventually found something that I thought would work well as a magnet sound effect.

It’s called Square Buzz.

Image 1

The sound effect is 12 seconds long, which won’t be long enough for our background sound. So instead, what we’re going to do is that we’re going to make this run on a loop.

However, if you look at the audio in the image, we can see that the audio gets quieter near the end.

To fix this, we need to cut it. I don’t have any sound editing software so I decided to see if I can find an online solution.

Luckily for us, such a solution exists! I went to a site called mp3cut.net.

To use it, you simply must upload your audio file and then you can choose the part of the song to cut off.

Image 2

Because we’re looping the music, we must make sure that the audio can transition from the end to the beginning.

To accomplish this, I chose to start playing the sound when it is quieter and end it when it’s becoming quieter.

Specifically, my start time is: 0:00.4 and my end time is 0:10.9.

For this tutorial, it doesn’t matter too much. If you don’t want to go through the process, you can find the audio in the CubeFlyer Github repo in the Music folder. The mp3 file is called Magnet.

  1. Drag the MP3 file into our project hierarchy (if it’s not called Magnet, rename it Magnet)

Now we have the music file, it’s time to add it to our game.

Step 1.2: Play the Power Up Music

Now that we have the power-up music, it’s time to use it, we need to play the sound effect.

Normally, I thought a good place to put it would have been the Magnet, but a problem with that is that if our magnet disappears, so does our sound, so we can’t do that (plus as we move away from it, the sound goes away too).

So instead I decided on a power-up, let’s add it to the player.

Specifically, in the PlaneCollider.

Here’s the script:

C#
using UnityEngine;

public class PlaneCollider : MonoBehaviour 
{
	public GameObject PlaneObject;
    public GameObject Explosion;
    public AudioClip MagnetSFX;

    private SoundManager _soundManager;

    void Start()
    {
        _soundManager = GetComponent<SoundManager>();
    }

    void OnTriggerEnter(Collider other)
    {
		print(other + " name " + other.name);
		switch (other.tag) {
			case "Coin":
				CoinCollision(other);
				break;
            case "Magnet":
                MagnetCollision(other);
                break;
			default:
				CheckUnTaggedCollision(other);
				break;
		}
    }

	// Collides with the coin, we get the script that controls 
	// the logic for the coin and call collect so it will
	// know what to do after we collide into it.
	private void CoinCollision(Collider other) {
		Coin coin = other.GetComponent<Coin>();
		coin.Collect();
		GameManager.Instance.CollectCoin();
	}

    // Collides with the magnet, we add the power up to our list of power-ups
    // and let the power-up destroy itself from the game.
    private void MagnetCollision(Collider other)
    {
        PlayerManager.Instance.AddPowerUp(PlayerManager.PowerUpType.Magnet);
        Magnet magnet = other.GetComponent<Magnet>();
        _soundManager.PlayBackgroundClip(MagnetSFX);
        magnet.Collect();
    }

    // Check the collided object if it doesn't have a tag to see if it's
    // something we're also looking for.
    private void CheckUnTaggedCollision(Collider other) {
		if (other.name.Contains("Cube")) {
			EnemyCollision();
		}
	}

    /// Destroy the player and set the current state to the dead state.
    private void EnemyCollision()
    {
        Instantiate(Explosion, PlaneObject.transform.position, Quaternion.identity);
        Destroy(PlaneObject);
        PlayerManager.Instance.GameOver();
        GameUIManager.Instance.GameOver(gameObject);
        CameraManager.Instance.GameOver();
    }
}

Looking at the Fields

Like what we’ve probably already seen before, we’re adding our Audio to our script.

  • public AudioClip MagnetSFX – The music clip for our Magnet effect
  • private SoundManager _soundManager – The class we wrote to help us play our sound effects (we need to add it to our game object later)

Walking Through the Code

We already have the system to detect game objects we collided against, we just need to write some code to detect our magnet and then play the sound effect.

  1. In Start(), we create an instance of our _soundManager by grabbing it from our Game Object.
  2. In MagnetCollision(), we use our _soundManager and play a backgroundClip with our Magnet sound. If you recall, the background clip will keep playing the power-up sound effect until we tell it to stop. We’ll do this later.

Setting Up the Script

We need to do a couple of things to get the script to work:

  1. Add Magnet to the Magnet SFX slot in our PlaneCollider.
  2. Add the SoundManager script to our Player component.

Step 1.3: Stop the Power-Up Music

Now that we have our power-up background music playing, the next thing that we need to do is to know when to stop our background music.

Our background music is directly tied to how long our power-up is playing, specifically, if our power-up goes away, so does our sound effect!

What manages our power-ups? The PlayerManager script! We’re just going to make a small change:

C#
using UnityEngine;
using System.Collections.Generic;

public class PlayerManager : MonoBehaviour
{
    public static PlayerManager Instance;
    public enum PlayerState { Alive, Dead }
    public GameObject Player;
    public GameObject MagnetCollider;


    public enum PowerUpType { Magnet }
    private Dictionary<PowerUpType, PowerUp> powerUpDictionary;
    private float powerUpDuration = 30f;
    private List<PowerUpType> itemsToRemove;

    public PlayerState CurrentState
    {
        // I chose to be explicit, but we could also have done:
        // get; private set;
        // read more: https://stackoverflow.com/questions/3847832/understanding-private-setters
        get { return _currentState; }
        private set { _currentState = value; }
    }

    private PlayerState _currentState;

    void Start ()
	{
	    if (Instance != null)
	    {
	        // If Instance already exists, we should get rid of this game object
	        // and use the original game object that set Instance   
	        Destroy(gameObject);
	        return;
	    }

	    // If Instance doesn't exist, we initialize the Player Manager
	    Init();
	}

    void Update()
    {
        foreach (KeyValuePair<PowerUpType, PowerUp> entry in powerUpDictionary)
        {
            entry.Value.Duration -= Time.deltaTime;

            // We can't remove an item from a dictionary if we're iterating through it.
            // Instead we have to keep track of it in a list and then remove the items from the
            // dictionary later.
            if (entry.Value.Duration <= 0)
            {
                itemsToRemove.Add(entry.Key);
            }
        }

        // Go through all of the power-ups that need to be removed and remove it from the 
        // dictionary.
        foreach (PowerUpType powerUpType in itemsToRemove)
        {
            switch (powerUpType)
            {
                case PowerUpType.Magnet:
                    Transform magnetCollider = Player.transform.Find("Magnet Collider(Clone)");
                    print(magnetCollider);
                    Destroy(magnetCollider.gameObject);
                    magnetCollider = null;
                    break;

            }
            powerUpDictionary.Remove(powerUpType);
        }

        // We've removed everything, let's clear our list.
        itemsToRemove.Clear();

        // If we no longer have any power-ups active, let's stop playing our background music
        if (powerUpDictionary.Count == 0)
        {
            Player.GetComponent<SoundManager>().StopBackgroundClip();
        }
    }

    private void Init()
    {
        Instance = this;
        CurrentState = PlayerState.Alive;

        // Create an empty dictionary and list, otherwise they'll be null later when we
        // try to access them and crash.
        powerUpDictionary = new Dictionary<PowerUpType, PowerUp>();
        itemsToRemove = new List<PowerUpType>();
    }

    /// <summary>
    /// Sets the PlayerManager to be in the game over state.
    /// </summary>

    public void GameOver()
    {
        CurrentState = PlayerState.Dead;
    }

    public void AddPowerUp(PowerUpType powerUpType)
    {
        switch (powerUpType)
        {
            case PowerUpType.Magnet:
                // if we already have the MagnetCollider, don't add it again.
                if (powerUpDictionary.ContainsKey(powerUpType))
                {
                    break;
                }
                // We add the Magnet Collider to our player.
                Instantiate(MagnetCollider, Player.transform.position, 
                            Quaternion.identity, Player.transform);
                break;
        }
        // An interesting part of this is that if we get another power up that if we
        // get a duplicate power up, we will replace it with the new one.
        powerUpDictionary[powerUpType] = new PowerUp(powerUpDuration);
    }

    /// <summary>
    /// See if the player currently have the power up that we pass in.
    /// </summary>


    public bool ContainsPowerUp(PowerUpType powerUpType)
    {
        return powerUpDictionary.ContainsKey(powerUpType);
    }
}

Walking through the Code

  1. All we’re doing extra here is adding an extra if statement at the end of Update(), we just check to see if we have any power-ups in our list and if we don’t, we’ll stop our background music.

One caveat here is that because this is in Update(), we’ll actually be stopping our background every frame. Luckily, if we take a peek at StopBackgroundClip(), we’ll see that we first check to see if any audio clip is even playing, thus averting the problem.

End Day 87

That’s it! Now when we pick up the magnet effect, our magnet sound will play on repeat until the power-up expires.

Having sound is great, but we’re not going to end just there. In the next article, we’re going to look at adding a visual particle effect that shows that we have a magnet effect.

Stay tuned for the next article!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)