【问题标题】:Unity3D playing sound when Player collides with an object with a specific tag当 Player 与具有特定标签的对象碰撞时 Unity3D 播放声音
【发布时间】:2020-04-04 17:48:03
【问题描述】:

我使用 Unity 2019.2.14f1 创建了一个简单的 3D 游戏。

在那个游戏中,我想在我的播放器与带有特定标签的游戏​​对象发生碰撞时播放声音。

MainCamera 有一个音频监听器,我正在使用 Cinemachine Free Look,它在 ThridPersonController 内跟随我的头像(我使用的是 Standard Assets 上的那个 - 但我隐藏了 Ethan 并添加了我自己的角色/头像)。

带有我要销毁的标签的游戏​​对象有一个音频源:


为了让声音在碰撞时播放,我首先创建了一个空的游戏对象作为 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 UI 中,我转到 gameObject AudioManager 中的 Inspector,并在脚本中添加了一个新元素,我将其命名为:CatchingPresent。

在第三人称角色脚本中,为了在与游戏对象(带有特定标签)发生碰撞时破坏它,我添加了以下内容:

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

            }
        }

它工作正常,因为该特定对象在碰撞时消失。现在,为了在播放器与带有标签的对象(在本例中为Present)碰撞时播放声音“CatchingPresent”,我尝试将以下内容添加到OnCollisionEnter 中的if

  • FindObjectOfType&lt;AudioManager&gt;().Play("CatchingPresent");

但我得到了错误:

找不到类型或命名空间名称“AudioManager”(您是 缺少 using 指令或程序集引用?)

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

但我得到了错误:

当前上下文中不存在名称“AudioManager”

由于所有编译器错误都需要在进入播放模式之前修复,任何有关如何在玩家和带有标签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:Unity 中的层次结构:

【问题讨论】:

  • 首先,在一个非常全面的问题上做得很好。很高兴看到为此付出的努力。现在澄清一下,AudioManager.instance 没有在上面的脚本 sn-p 中定义;你在Awake/Start 中分配它的值吗?它的定义很明确,所以我觉得其他东西正在停止编译。当你删除这两行代码时它会编译吗?你也可以使用这个script 来创建那个单例。所以你可以AudioManager.Instance...你调用碰撞代码的命名空间是什么?
  • @user14492 首先,是的。第二个问题,是的。如果有帮助,我可以添加整个 ThirdPersonUserControl.cs
  • 如果你不介意分享的话,当然可以。
  • @user14492 它已经在“Edit 1”之后了。
  • 快速搜索以检查标准资产的项目部分中是否没有另一个 AudioManager 类?

标签: c# unity3d audio collision


【解决方案1】:

重新制定我遵循的方法并通过简单地将音频源添加到 ThirdPersonController(使用我想要调用的 AudioClip)并将GetComponent&lt;AudioSource&gt;().Play(); 添加到 if 语句中来解决问题,如下所示:

void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.CompareTag("Present"))
            {
                Destroy(other.gameObject);
                count = count - 1;
                SetCountText();
                GetComponent<AudioSource>().Play();
            }
        }

【讨论】:

  • 此解决方案仅适用于一个音频源,但我不确定使用 2 个或更多音频源会如何。
【解决方案2】:

在使用FindObjectOfType&lt;AudioManager&gt;().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
}

这样做,并使用您的其余代码也适用于我。

【讨论】:

  • 我尝试重新导入所有内容,但问题仍然存在。
  • @GoncaloPeressupportsMonica 作为健全性检查;您的 AudioManager.cs 文件在 /assets/ 文件夹中吗?
  • AudioManager.cs 位于名为 Sounds (/Assets/Sounds) 的文件夹内的 Assets 文件夹中,该文件夹不同于 Standard Assets 文件夹 (/Assets/Standard Assets)
  • 好的,那条路径应该没问题。 Unity 中有一些“特殊”文件夹可能会导致问题。 /声音/不是其中之一。只是想确定一下。您是否尝试过从 UserController namespace UnityStandardAssets.Characters.ThirdPerson 中删除命名空间(或将命名空间添加到音频管理器)?虽然它不应该因为 AudioManager 处于更高的指令中。无论如何,它可能值得一试......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 2022-01-21
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 2013-10-20
相关资源
最近更新 更多