【问题标题】:Access GameObject in other Scenes that are not instantiated yet in Unity在 Unity 中尚未实例化的其他场景中访问 GameObject
【发布时间】:2018-12-14 09:15:01
【问题描述】:

我已经在 Stack Overflow 和 Internet 上检查了其他问题 here,但找不到类似的问题。

我有一个“设置场景”,我想在其他场景中切换特定的音频剪辑(例如,我想只在游戏场景(场景 7)中的设置场景(场景 2)中静音倒数计时器声音)。

在带有倒数计时器的游戏场景中,我附加了一个音频剪辑,我想从设置场景访问它并发送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;
    }
}

任何想法如何访问和编辑尚未实例化的游戏对象?

【问题讨论】:

  • 我发现保存单独的设置文件更容易。它需要在初始创建时加载并与您的变量一起存储,但您可以将其全部设置为默认值。然后你可以在保存场景中编辑这个文件,在游戏场景中加载这个文件

标签: unity3d gameobject


【解决方案1】:

您无法访问尚未创建(实例化)的对象。

标准解决方案之一是在生成的 (TimerHandler) 类中包含代码,通知其控制器类 (TimerSoundHandler) 对象现在在场景中。

我通常会使用 OnEnable/OnDisable 方法对,也可能使用静态方法。

这对于维护您想要跟踪的对象的最新列表很有用


活跃听众列表

TimeHandlerController.cs

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

TimerHandler.cs

void OnEnable()
{
    TimeHandlerController.RegisterTimer(this);
}

void OnDisable()
{
    TimeHandlerController.UnRegisterTimer(this);
}

public void DoStuff() 
{ 
 // Do your stuff 
}

此模式可让您可靠地处理多个受控对象,以便控制器始终拥有需要控制的活动对象的最新列表(无需搜索场景)。

如果您不需要跟踪所有 TimeHandler,一个更简单的解决方案是使用每个对象订阅的事件(也称为观察者模式),它的代码要少得多,但您会丢失积极的听众,这通常很有用。例如,使用事件来调试异常会更加困难,因为堆栈跟踪会在事件调用时丢失。

事件订阅

TimeHandlerController.cs

public static System.Action tick; // event

void Tick()
{
  if (tick!=null) // exception if no handlers otherwise
    tick.Invoke();
}

TimeHandler.cs

void OnEnable()
{
    TimeHandlerController.tick+=DoStuff;
}

void OnDisable()
{
    TimeHandlerController.tick-=DoStuff;
}

public void DoStuff() 
{ 
 // Do your stuff 
}

在事件订阅的情况下,订阅者的类型是无关紧要的(只要方法签名匹配),如果是列表,您需要知道对象的基类才能对其调用方法,或(通常最好)指定一个接口(这超出了问题的范围)

【讨论】:

  • 谢谢@Zambari。我真的不明白这一点,您能否解释一下或尝试编辑您发布的代码?抱歉,我是 Unity 新手。
  • @Johny 这是 C# 中的 Observer Pattern,并非特定于 Unity3D。您可以在DotNetPerls/Event 上查看如何使用它们
  • @Johy 我已添加到发布的代码中(显示示例调用)并提供了一个更简单的示例。我希望这会有所帮助
猜你喜欢
  • 2017-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多