我正在使用Unity 5.3和C#作为代码编辑器
这些就是我所拥有的:
我的项目中有2个场景:home
和options
。我在两个场景都有bg
个对象。这两个bg
个对象都有Audio Source
个组件,其中包含play on awake
相同的背景音乐。我没有对这些背景音乐使用任何代码,我只点击Unity中的Add Component
按钮并添加Audio Source
。
这就是我想要的:
Options
场景可以为所有场景打开/关闭背景音乐。因此,btnOn
场景中有btnOff
和Options
。
这是我在Audio Manager.cs中的代码:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class AudioManager : MonoBehaviour {
public Button btnOn;
public Button btnOff;
// Use this for initialization
void Start () {
btnOn = GetComponent<Button>();
btnOff = GetComponent<Button>();
btnOn.onClick.AddListener(() => PlayAudio());
btnOff.onClick.AddListener(() => StopAudio());
}
void PlayAudio()
{
AudioSource.volume = 0.5f;
}
void StopAudio()
{
AudioSource.volume = 0f;
}
}
这就是问题:
我有这个错误:An object reference is required to access non-static member UnityEngine.AudioSource.volume
。也许,这是因为我没有在我的代码中写public AudioSource audioSource
。但是,如果我写这个,我必须在Get Component
框中添加另一个音频,我将在一个场景中加倍Audio Source
。我该怎么办?谢谢
答案 0 :(得分:2)
由于您在两个场景中都有bg
个对象,并且AudioManager
未被标记为[DontDestroyOnLoad]
(我假设您还有一个AudioManager
两个场景),每次加载场景时它都会触发Start()
功能。
因此,您可以声明private AudioSource
并通过在场景中找到bg对象并在其上调用GetComponent
来获取它的引用:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class AudioManager : MonoBehaviour
{
public Button btnOn;
public Button btnOff;
private AudioSource audioSource;
// Use this for initialization
void Start()
{
btnOn = GetComponent<Button>();
btnOff = GetComponent<Button>();
btnOn.onClick.AddListener(() => PlayAudio());
btnOff.onClick.AddListener(() => StopAudio());
audioSource = GameObject.Find("bg").GetComponent<AudioSource>();
}
void PlayAudio()
{
audioSource.volume = 0.5f;
}
void StopAudio()
{
audioSource.volume = 0f;
}
}
答案 1 :(得分:1)
引发错误是因为您需要在单个对象上分配属性;卷之间不共享卷。因此,您需要在检查器中指定一个字段,或者使用GetComponent
获取参考。
虽然使用不同的场景来处理选项并没有错,但它有点笨拙;必须卸载当前场景(销毁所有未标记为DontDestroyOnLoad
的对象和与之关联的信息),然后加载选项,然后加载前一场景。虽然卸载音乐很可能会停止播放,但在加载后,会再次从头开始播放。不提及这些对象的任何设置都会丢失(音量,音轨变化等)。
前面提到的DontDestroyOnLoad
可以帮助您,因为您对同一个对象进行了更改,但是每次加载场景时您都必须处理重复项...这样的对象存在...您可以使用该函数OnLevelWasLoaded
(文档目前缺乏一点)作为确定要销毁哪些对象的时刻。
另一点是您目前拥有公开的Button
字段。这允许通过检查器分配它们,但是在Start
中覆盖它们时相当没有意义(新值是分配给同一对象的第一个按钮组件)。我会将这些字段设为私有,或者至少确保它们未被分配。但我稍微谈谈如何在场景之间保持设置的持续性。
这里有一些代码可以给你一个想法,但要注意它是未经测试的,因为我目前无法访问测试它的环境。此解决方案使用在场景之间持久的对象。请记住,在加载另一个场景后,通过编辑器建立到此对象的任何连接都将丢失。
public class AudioManager : MonoBehaviour
{
private AudioSource source;
// Called regardless of whether the object is enabled or not.
// Should not be called in a new scene.
private void Awake()
{
// Protect this object from being destroyed so its volume
// is maintained between scenes.
DontDestroyOnLoad(this.gameObject);
source = GetComponent<AudioSource>();
}
public void DestroyPossibleDuplicates()
{
AudioManager[] managers = FindObjectsOfType(typeof(AudioManager)) as AudioManager[];
foreach (AudioManager manager in managers)
{
// Use something to determine whether a manager is a duplicate.
// It must not be this, but have something in common; a name perhaps?
if ((manager != this) && (manager.gameObject.name == this.gameObject.name))
{
// Destroy the duplicates so their sound won't interfere.
Destroy(manager.gameObject);
}
}
}
private void BindToInterface()
{
Slider[] sliders = FindObjectsOfType(typeof(Slider)) as Slider[];
foreach (Slider slider in sliders)
{
// Determine whether the specified slider should have effect on this object.
// If the slider's name contains this object's name assume it should.
if (slider.gameObject.name.indexOf(this.gameObject.name)!=-1)
{
slider.onValueChanged.addListener((float value)=>
{
// In this case a slider is used for more control over the volume.
// Different elements require other logic to function.
source.volume = value;
});
}
}
}
// If my memory serves correct this method is only called on objects
// that were in the scene before it started loading.
// Just to be safe, don't have it do anything depending on this difference.
private void OnLevelWasLoaded()
{
DestroyPossibleDuplicates();
BindToInterface();
}
}