Как убедиться, что объект MonoBehaviour загрузил свои данные, прежде чем другой Actor хочет получить к ним доступ? - PullRequest
3 голосов
/ 01 июля 2019

У меня есть Inventory: MonoBehaviour, который загружает некоторые фиктивные данные в Start (), включая переменную selectedWeapon, которая установлена ​​и может быть прочитана.

Допустим, я хочу получить доступ к этой переменной, когда я настраиваю другой MonoBehaviour в той же сцене.

Есть ли хороший способ убедиться, что переменная установлена ​​при попытке доступа к ней? Я стремлюсь сделать это в Start () или какой-нибудь начальной функции, желательно только один раз.

Мое временное решение состоит в том, чтобы использовать функцию Update () в экземпляре, который хочет получить доступ к «selectedWeapon» из инвентаря и неоднократно пытается установить свою собственную переменную, пока она не установлена.

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

Временное решение кажется неустойчивым, так как проверки в обновлении, безусловно, будут расти в моем проекте.

1 Ответ

4 голосов
/ 01 июля 2019

Мой общий сокращенный вариант всегда

  • Используйте Awake для всего, где вы не зависите от других, поэтому настройте свои собственные значения, настройте всессылки между компонентами (но без использования их значений), вещи, где вы можете использовать static классы.

    Также используйте это, если возможно, для long, принимая загрузки / ввода-вывода, так что это делается во времяприложение загружается и не отображается как задержка для пользователя.

  • Используйте Start для всего, где вам нужно, чтобы другие компоненты уже были настроены, например, для использованиязначения ссылок, которые были установлены в Awake.

, также см. Учебное пособие по пробуждению и запуску


Это имеет свои пределы курсапоэтому при необходимости вы можете начать манипулировать Порядком выполнения скрипта , но я стараюсь этого избегать, насколько это возможно.


Если это становится действительно сложным, то иногда не всегда можно обойтисьсистема событий, например,

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
    }
}

. Это выглядит более раздражающим и сложным, но гораздо более эффективно, чем ожидание какого-либо события only-do-it-Once вUpdate метод.

...