Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity3D playing sound when Player collides with an object with a specific tag

I using Unity 2019.2.14f1 to create a simple 3D game.

In that game, I want to play a sound anytime my Player collides with a gameObject with a specific tag.

The MainCamera has an Audio Listener and I am using Cinemachine Free Look, that is following my avatar, inside the ThridPersonController (I am using the one that comes on Standard Assets - but I have hidden Ethan and added my own character/avatar).

The gameObject with the tag that I want to destroy has an Audio Source:

Audio Source on the GameObject with the specific tag


In order to make the sound playing on the collision, I started by creating an empty gameObject to serve as the AudioManager, and added a new component (C# script) to it:

using UnityEngine.Audio;
using System;
using UnityEngine;

public class AudioManager : MonoBehaviour
{

    public Sound[] sounds;

    // Start is called before the first frame update
    void Awake()
    {
        foreach (Sound s in sounds)
        {
            s.source = gameObject.AddComponent<AudioSource>();
            s.source.clip = s.clip;

            s.source.volume = s.volume;
            s.source.pitch = s.pitch;
        }
    }

    // Update is called once per frame
    public void Play (string name)
    {
        Sound s = Array.Find(sounds, sound => sound.name == name);
        s.source.Play();
    }
}

And created the script Sound.cs:

using UnityEngine.Audio;
using UnityEngine;

[System.Serializable]
public class Sound
{
    public string name;

    public AudioClip clip;

    [Range(0f, 1f)]
    public float volume;
    [Range(.1f, 3f)]
    public float pitch;

    [HideInInspector]
    public AudioSource source;
}

After that, in the Unity UI, I went to the Inspector in the gameObject AudioManager, and added a new element in the script that I named: CatchingPresent.

AudioManager - Sound that I want to play when the player collides with an object.

On the Third Person Character script, in order to destroy a gameObject (with a specific tag) when colliding with it, I have added the following:

void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.CompareTag("Present"))
            {
                Destroy(other.gameObject);
                count = count - 1;
                SetCountText();

            }
        }

It is working properly as that specific object is disappearing on collision. Now, in order to play the sound "CatchingPresent" anytime the Player collides with the object with the tag, in this case, Present, I have tried adding the following to the if in the OnCollisionEnter:

  • FindObjectOfType<AudioManager>().Play("CatchingPresent");

But I get the error:

The type or namespace name 'AudioManager' could not be found (are you missing a using directive or an assembly reference?)

  • AudioManager.instance.Play("CatchingPresent");

But I get the error:

The name 'AudioManager' does not exist in the current context

As all the compiler errors need to be fixed before entering the Playmode, any guidance on how to make the sound playing after a collision between the player and the gameObject with the tag Present is appreciated.


Edit 1: Assuming that it is helpful, here it goes the full ThirdPersonUserControl.cs:

using System;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Characters.ThirdPerson
{
    [RequireComponent(typeof (ThirdPersonCharacter))]
    public class ThirdPersonUserControl : MonoBehaviour
    {

        public Text countText;
        public Text winText;

        private int count;
        private ThirdPersonCharacter m_Character; // A reference to the ThirdPersonCharacter on the object
        private Transform m_Cam;                  // A reference to the main camera in the scenes transform
        private Vector3 m_CamForward;             // The current forward direction of the camera
        private Vector3 m_Move;
        private bool m_Jump;                      // the world-relative desired move direction, calculated from the camForward and user input.


        private void Start()
        {

            count = 20;
            SetCountText();
            winText.text = "";

            // get the transform of the main camera
            if (Camera.main != null)
            {
                m_Cam = Camera.main.transform;
            }
            else
            {
                Debug.LogWarning(
                    "Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls.", gameObject);
                // we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them!
            }

            // get the third person character ( this should never be null due to require component )
            m_Character = GetComponent<ThirdPersonCharacter>();
        }


        private void Update()
        {
            if (!m_Jump)
            {
                m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
            }
        }


        // Fixed update is called in sync with physics
        private void FixedUpdate()
        {
            // read inputs
            float h = CrossPlatformInputManager.GetAxis("Horizontal");
            float v = CrossPlatformInputManager.GetAxis("Vertical");
            bool crouch = Input.GetKey(KeyCode.C);

            // calculate move direction to pass to character
            if (m_Cam != null)
            {
                // calculate camera relative direction to move:
                m_CamForward = Vector3.Scale(m_Cam.forward, new Vector3(1, 0, 1)).normalized;
                m_Move = v*m_CamForward + h*m_Cam.right;
            }
            else
            {
                // we use world-relative directions in the case of no main camera
                m_Move = v*Vector3.forward + h*Vector3.right;
            }
#if !MOBILE_INPUT
            // walk speed multiplier
            if (Input.GetKey(KeyCode.LeftShift)) m_Move *= 0.5f;
#endif

            // pass all parameters to the character control script
            m_Character.Move(m_Move, crouch, m_Jump);
            m_Jump = false;
        }

        void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.CompareTag("Present"))
            {
                Destroy(other.gameObject);
                count = count - 1;
                SetCountText();

                //FindObjectOfType<AudioManager>().Play("CatchingPresent");
                AudioManager.instance.Play("CatchingPresent");
            }
        }

        void SetCountText()
        {
            countText.text = "Missing: " + count.ToString();
            if (count == 0)
            {
                winText.text = "You saved Christmas!";
            }
        }
    }
}

Edit 2: Hierarchy in Unity:

Hierarchy in Unity

like image 320
Gonçalo Peres Avatar asked Nov 15 '22 20:11

Gonçalo Peres


1 Answers

Reformulated the approach that I was following and solved the problem by simply adding an Audio Source to the ThirdPersonController (with the AudioClip that I wanted to call) and added GetComponent<AudioSource>().Play(); to the if statement as it follows:

void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.CompareTag("Present"))
            {
                Destroy(other.gameObject);
                count = count - 1;
                SetCountText();
                GetComponent<AudioSource>().Play();
            }
        }
like image 71
Gonçalo Peres Avatar answered Dec 22 '22 02:12

Gonçalo Peres