Unity3D воспроизводит звук, когда Player сталкивается с объектом с определенным тегом - PullRequest
5 голосов
/ 11 декабря 2019

Я использую Unity 2019.2.14f1 для создания простой 3D-игры.

В этой игре я хочу воспроизводить звук в любое время, когда мой игрок сталкивается с gameObject с определенным тегом.

MainCamera имеет Audio Listener, и я использую Cinemachine Free Look, который следит за моим аватаром, внутри ThridPersonController (я использую тот, который входит в Стандартные активы - но я спрятал Итана и добавил свой собственныйперсонаж / аватар).

Объект gameObject с тегом, который я хочу уничтожить, имеет источник звука:

Audio Source on the GameObject with the specific tag


Чтобы звук воспроизводился при столкновении, я начал с создания пустого игрового объекта, который будет служить AudioManager, и добавил к нему новый компонент (скрипт C #):

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();
    }
}

И создал скрипт 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;
}

После этого в пользовательском интерфейсе Unity я зашел к Инспектору в gameObject AudioManager и добавил в скрипт новый элемент, который я назвал: CatchingPresent.

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

В сценарии персонажа от третьего лица, чтобы уничтожить игровой объект (с определенным тегом) при столкновении с ним, я добавил следующее:

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

            }
        }

Этоработает правильно, так как этот конкретный объект исчезает при столкновении. Теперь, чтобы воспроизводить звук «CatchingPresent» в любое время, когда проигрыватель сталкивается с объектом с тегом, в данном случае, Present, я попытался добавить следующее к if в OnCollisionEnter:

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

Но я получаю ошибку:

Не удалось найти тип или имя пространства имен 'AudioManager' (вы пропустилииспользуя директиву или ссылку на сборку?)

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

Но я получаю ошибку:

Имя 'AudioManager 'не существует в текущем контексте

Поскольку все ошибки компилятора должны быть исправлены перед входом в Playmode, любые указания о том, как заставить воспроизводиться звук после столкновения между игроком и gameObjectс тегом Present приветствуется.


Редактировать 1: Предполагая, что это полезно, здесь идет полный 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!";
            }
        }
    }
}

Редактировать 2: Иерархия в единстве:

Hierarchy in Unity

1 Ответ

0 голосов
/ 11 декабря 2019

Сам импорт ваших скриптов работает без проблем при использовании FindObjectOfType<AudioManager>().Play("CatchingPresent");. Попробуйте повторно импортировать ваши сценарии из редактора (щелкните правой кнопкой мыши в папке проекта> повторно импортировать все. Это может занять некоторое время в зависимости от размера вашего проекта)

, чтобы использовать AudioManager.instance.Play("CatchingPresent");, вам сначала потребуется создать статическийпеременная, которая содержит instance, как это (это работает только как синглтон и сломается, если в сцене несколько AudioManager):

public class AudioManager : MonoBehaviour
{
    //Create a static AudioManager that will hold the reference to this instance of AudioManager
    public static AudioManager Instance;
    public Sound[] sounds;

    //Assign Instance to the instance of this AudioManager in the constructor
    AudioManager()
    {
        Instance = this;
    }

    // Rest of the AudioManager code
}

Делая это так, и используя остальныеваш код также работает для меня.

...