我已经检查了Stack Overflow和Internet上的其他问题here,但找不到类似的内容。
我有一个“设置场景”,我想在其他场景中切换特定的音频片段(例如,我只想从游戏场景(场景7)的设置场景(场景2)中关闭倒计时计时器的声音)。
在带有倒数计时器的游戏场景中,我连接了一个AudioClip,我想从“设置场景”中访问它并发送timerHandler.ToggleMuteTimer(false)
以下是一些代码:
public class TimerSoundHandler : MonoBehaviour {
public GameObject audioOnIcon;
public GameObject audioOffIcon;
private TimerHandler timerHandler;
void Start()
{
//timerHandler = GameObject.FindWithTag("TimerTAG").GetComponent<TimerHandler>();
//timerHandler = GameObject.FindGameObjectWithTag("TimerTAG");
timerHandler = FindObjectOfType<TimerHandler>();
SetSoundState();
}
public void ToggleSound()
{
if (PlayerPrefs.GetInt("TimerMuted", 0) == 0)
{
PlayerPrefs.SetInt("TimerMuted", 1);
}
else
{
PlayerPrefs.SetInt("TimerMuted", 0);
}
SetSoundState();
}
public void SetSoundState()
{
if (PlayerPrefs.GetInt("TimerMuted", 0) == 0)
{
UnmuteSound();
}
else
{
MuteSound();
}
}
private void UnmuteSound()
{
//timerHandler.ToggleMuteTimer(true);
audioOnIcon.SetActive(true);
audioOffIcon.SetActive(false);
}
private void MuteSound()
{
//timerHandler.ToggleMuteTimer(false);
audioOnIcon.SetActive(false);
audioOffIcon.SetActive(true);
}
}
这是TimerHandler脚本:
public class TimerHandler : MonoBehaviour {
public Text timerText;
public AudioClip timerClipSound;
[Range(0,3600)]
[SerializeField]
private float totalTime = 300f;
private bool timeUp = false;
private AudioSource audioSource;
private void Awake()
{
audioSource = GetComponent<AudioSource>();
}
private void Update()
{
if (timeUp)
return;
totalTime -= Time.deltaTime;
string minutes = ((int)totalTime / 60).ToString("00");
string seconds = (totalTime % 60).ToString("00");
timerText.text = minutes + ":" + seconds;
if (totalTime <= 0)
{
timeUp = true;
audioSource.mute = true;
}
}
public void ToggleMuteTimer(bool value)
{
audioSource.mute = value;
}
}
有什么想法可以访问和编辑尚未实例化的游戏对象?
答案 0 :(得分:1)
您无法访问尚未创建(实例化)的对象。
一种标准的解决方案是在生成的(TimerHandler)类中包含代码,以通知其控制器类(TimerSoundHandler)该对象现在在场景中。
我通常会使用OnEnable / OnDisable对方法,可能还会使用静态方法。
这对于维护您要跟踪的对象的最新列表很有用
static List<TimeHandler> activeHandlers;
public static RegisterTimer(TimeHandler source)
{
if (activeHandlers==null) activeHandlers = new List<TimeHandler>();
activeHandlers.Add(source);
}
public static UnRegisterTimer(TimeHandler source)
{
activeHandlers.Remove(source); //if (activeHandlers.Contains(source))
}
void DoStuffWithTimeHandlers()
{
foreach(TimeHandler th in activeHandlers)
th.DoStuff();
}
void OnEnable()
{
TimeHandlerController.RegisterTimer(this);
}
void OnDisable()
{
TimeHandlerController.UnRegisterTimer(this);
}
public void DoStuff()
{
// Do your stuff
}
此模式可让您可靠地处理多个受控对象,以便控制器始终具有需要控制的活动对象的最新列表(无需搜索场景)。
一个更简单的解决方案,如果您不需要跟踪所有TimeHandler,则使用每个对象订阅的事件(又称Observer模式),它的代码要少得多,但是您松开了积极的听众,这通常很有用。例如,使用事件调试异常更加困难,因为事件调用会丢失堆栈跟踪。
public static System.Action tick; // event
void Tick()
{
if (tick!=null) // exception if no handlers otherwise
tick.Invoke();
}
void OnEnable()
{
TimeHandlerController.tick+=DoStuff;
}
void OnDisable()
{
TimeHandlerController.tick-=DoStuff;
}
public void DoStuff()
{
// Do your stuff
}
在订阅事件的情况下,订阅者的类型无关紧要(只要方法签名匹配),在列表的情况下,您需要知道对象的基类才能在其上调用方法,或(通常最好)指定一个接口(超出问题范围)