如何确保 MonoBehaviour 对象在另一个 Actor 想要访问它之前加载了它的数据?
How to ensure that MonoBehaviour object has loaded its data before another Actor wants to access it?
我有一个 Inventory : MonoBehaviour,它在 Start() 中加载了一些模拟数据,包括一个已设置且可以读取的 "selectedWeapon" 变量。
假设我想在同一场景中设置另一个 MonoBehaviour 时访问此变量。
有什么好的方法可以确保在尝试访问变量时已设置该变量?我的目标是在 Start() 或某些初始函数中最好只执行一次。
我的临时解决方案是在想要从 Inventory 访问 "selectedWeapon" 的实例上使用 Update() 函数,并重复尝试设置它自己的变量,只要它没有设置。
/// This is only an example, illustrating my problem.
public class Inventory : MonoBehaviour
{
[SerializeField]
private WeaponItem m_SelectedWeapon = null;
.
.
.
void Start()
{
m_SelectedWeapon = MockDatabase.GetSelectedWeapon();
}
.
.
.
public WeaponItem GetSelectedWeapon()
{
return m_SelectedWeapon;
}
}
//--------------------------------------------------------------------
public class Actor : MonoBehaviour
{
private WeaponItem m_SelectedWeapon = null;
public Inventory inventory;
.
.
.
void Start()
{
// Would like to set up things here
// but this can let m_SelectedWeapon be null
// since it may be null in Inventory
m_SelectedWeapon = inventory.GetSelectedWeapon();
}
void Update()
{
// If not yet set, load from inventory
if(m_SelectedWeapon == null)
m_SelectedWeapon = inventory.GetSelectedWeapon();
}
.
.
.
}
临时解决方案感觉不可持续,因为更新中的检查肯定会在我的项目中增加。
我的总规则总是
对不依赖他人的一切使用Awake
,因此设置自己的值,设置组件之间的所有引用(但尚未使用它们的值),其中的东西你可以使用 static
类.
如果可能的话,也可以使用这个 长时间使用 loading/IO 所以它是在应用程序加载期间完成的,并且不会对用户显示为延迟。
使用 Start
用于您需要已经设置其他组件的所有内容,例如使用已在 Awake
.
中设置的引用值
这当然有其局限性,因此在需要时您可以开始操纵 Script Execution Order 但我会尽可能避免这样做。
如果它变得非常复杂,有时就没有办法使用事件系统,例如
public class A : MonoBehaviour
{
public event Action OnReady;
public bool isReady;
private void Awake()
{
// do your stuff
isReady = true;
// execute whatever was added as callback
OnReady?.Invoke();
}
}
然后在需要的地方添加回调,例如
public class B : MonoBehaviour
{
// either reference it in the Inspector
public A a;
private void Awake()
{
// or get it somehow on runtime
a = FindObjectOfType<A>();
// if ready directly move on otherwise add callbacks
if(a.isReady)
{
OnAReady();
}
else
{
// it is always good to remove the callback even though
// it wasn't added yet. Makes sure it is always only added once
a.OnReady -= OnAReady;
a.OnReady += OnAReady;
}
}
private void OnDestroy()
{
// always remove callbacks when no longer needed
a.OnReady -= OnAReady;
}
private void OnAReady()
{
// always remove callbacks when no longer needed
a.OnReady -= OnAReady;
// use stuff from A
}
}
这看起来更烦人和复杂,但比在 Update
方法中等待某些 only-do-it-once 事件更有效。
我有一个 Inventory : MonoBehaviour,它在 Start() 中加载了一些模拟数据,包括一个已设置且可以读取的 "selectedWeapon" 变量。
假设我想在同一场景中设置另一个 MonoBehaviour 时访问此变量。
有什么好的方法可以确保在尝试访问变量时已设置该变量?我的目标是在 Start() 或某些初始函数中最好只执行一次。
我的临时解决方案是在想要从 Inventory 访问 "selectedWeapon" 的实例上使用 Update() 函数,并重复尝试设置它自己的变量,只要它没有设置。
/// This is only an example, illustrating my problem.
public class Inventory : MonoBehaviour
{
[SerializeField]
private WeaponItem m_SelectedWeapon = null;
.
.
.
void Start()
{
m_SelectedWeapon = MockDatabase.GetSelectedWeapon();
}
.
.
.
public WeaponItem GetSelectedWeapon()
{
return m_SelectedWeapon;
}
}
//--------------------------------------------------------------------
public class Actor : MonoBehaviour
{
private WeaponItem m_SelectedWeapon = null;
public Inventory inventory;
.
.
.
void Start()
{
// Would like to set up things here
// but this can let m_SelectedWeapon be null
// since it may be null in Inventory
m_SelectedWeapon = inventory.GetSelectedWeapon();
}
void Update()
{
// If not yet set, load from inventory
if(m_SelectedWeapon == null)
m_SelectedWeapon = inventory.GetSelectedWeapon();
}
.
.
.
}
临时解决方案感觉不可持续,因为更新中的检查肯定会在我的项目中增加。
我的总规则总是
对不依赖他人的一切使用
Awake
,因此设置自己的值,设置组件之间的所有引用(但尚未使用它们的值),其中的东西你可以使用static
类.如果可能的话,也可以使用这个 长时间使用 loading/IO 所以它是在应用程序加载期间完成的,并且不会对用户显示为延迟。
使用
中设置的引用值Start
用于您需要已经设置其他组件的所有内容,例如使用已在Awake
.
这当然有其局限性,因此在需要时您可以开始操纵 Script Execution Order 但我会尽可能避免这样做。
如果它变得非常复杂,有时就没有办法使用事件系统,例如
public class A : MonoBehaviour
{
public event Action OnReady;
public bool isReady;
private void Awake()
{
// do your stuff
isReady = true;
// execute whatever was added as callback
OnReady?.Invoke();
}
}
然后在需要的地方添加回调,例如
public class B : MonoBehaviour
{
// either reference it in the Inspector
public A a;
private void Awake()
{
// or get it somehow on runtime
a = FindObjectOfType<A>();
// if ready directly move on otherwise add callbacks
if(a.isReady)
{
OnAReady();
}
else
{
// it is always good to remove the callback even though
// it wasn't added yet. Makes sure it is always only added once
a.OnReady -= OnAReady;
a.OnReady += OnAReady;
}
}
private void OnDestroy()
{
// always remove callbacks when no longer needed
a.OnReady -= OnAReady;
}
private void OnAReady()
{
// always remove callbacks when no longer needed
a.OnReady -= OnAReady;
// use stuff from A
}
}
这看起来更烦人和复杂,但比在 Update
方法中等待某些 only-do-it-once 事件更有效。