2016-07-03 3 views
0

В сценарии Unity C# у меня есть объект игрового контроллера Singleton, в котором хранятся игровые переменные, но я получаю странное поведение при доступе к ним в функции-члене. Он печатает инициализированное значение, а не текущее. Однако в функции обновления он печатает правильное значение для каждого кадра. Я подвел итоги ниже. Класс контроллера имеет статическую ссылку на себя. Если вам нужно знать дополнительные сведения, вы можете спросить. Я новичок в C# и Unity, поэтому мне может не хватать какого-то очевидного ответа.Невозможно получить доступ к переменной класса в функции-члене

Благодаря

public class controller : MonoBehaviour { 

    public int[] star = new int[64]; 

    void Start(){ /* calls another function to set 0 for each star index */ } 

    void Update(){ // during gameplay star[0] gets a value of 1 
     print(star[0]); // prints correct value which is 1 
    } 

    public void checkValue(){ 
     print(star[0]); // prints 0 incorrectly which should be 1  
    } 


} 
+0

Я нашел проблему, но я не знаю, как ее решить. Функция checkValue запускается при нажатии кнопки и возвращает правильное значение, если оно было вызвано из обновления. Не знаю, что вызывает его. – Sangratura

+0

Пуск должен быть no-op, так как массив всегда инициализируется нулем. В противном случае происходит что-то, что не видно в этом фрагменте кода. –

+0

Это тот же самый экземпляр 'controller' во всех случаях. Каждый экземпляр имеет свое собственное поле («переменная класса»), когда вы используете нестатический член 'star'. –

ответ

1

Я создал маленький пример. Я создал кнопку и пустой игровой объект GameController. Я добавил этот код GameController:

using UnityEngine; 
using System.Collections; 

public class GameController : MonoBehaviour { 

    public static GameController instance; 

    [System.NonSerialized] public int[] star = new int[64]; 

    private void Awake() 
    { 
     if(instance == null) 
      instance = this; 
     else if(instance != this) 
      Destroy(gameObject); 

     DontDestroyOnLoad(gameObject); 
    } 

    private void Start() 
    { 
     StartCoroutine(SetAllTo(1)); 
    } 

    // for simulating some changes during the game 
    private IEnumerator SetAllTo(int value) 
    { 
     yield return new WaitForSeconds(2.0f); 

     for(int i = 0; i < star.Length; i++) 
      star[i] = value; 

     Debug.Log("Setting done"); 
    } 

    public void PrintFirst() 
    { 
     Debug.Log(star[0]); 
    } 
} 

Теперь я добавил OnClick событие кнопки, перетащил GameController GameObject в слот и выбрал PrintFirst.

я начать игру и нажмите на кнопку один раз перед сопрограммная журнал и сразу после того, как и консоль дает следующее:

0 
Setting Done 
1 

Edit:
геймобжекты для OnClick события должны быть в сцене, он не может быть сборником в папке с ресурсами.

+0

Thats interesting. Вы перетащили GameController, который присутствовал в сцене, в событие OnClick? Это тоже работает для меня, но он не работает, если я перетаскиваю сборный файл. – Sangratura

+0

О, да, со сцены. Если 'перетащить prefab', вы фактически намереваетесь перетащить его из папки с ресурсами: это будет ** никогда ** работать. Сборники не являются частью игры, а только чертежи на вашем жестком диске. Вы можете ссылаться только на материал, который находится в сцене (иерархии) или каким-то образом связан с чем-то в сцене (например, скрипт, не поддерживающий MonoBehaviour, в сценарии MonoBehaviour, созданный с помощью 'new'). –

+0

Хорошо, я получил его, но я могу запустить функцию prefab, например, он печатает строку. Он возвращает значение по умолчанию для переменных класса. Но как это назвать, не вызывая конструктор? Я помещаю печать в конструктор, и она не печаталась при нажатии кнопки. Большое спасибо за вашу помощь! – Sangratura

0

Кажется, что это вызов функции запуска может также происходит в ваших внешних вызовов перед вызовом для ckeckValue

Try отладки, поставив точку останова в каждой из этих функций и вы можете понять, что происходит.

+0

Функция запуска запускается один раз в начале игры, а не снова. Функция checkValue запускается при нажатии кнопки. Если бы это было так, то функция обновления не вернула бы правильный после нажатия кнопки. Думаю. – Sangratura

+0

Добавить публичную недвижимость и использовать полевую звезду, а также сделать поле закрытым. Добавить точку останова в сеттере, чтобы наблюдать, когда значение установлено, и использовать кодовую карту для просмотра вызывающего абонента –

0

Функция запуска запускается один раз в начале игры, а не снова.

Для этого у вас есть картина - Singleton

Вторая вещь, почему для вызова внешней функции для инициализации члена класса? сделайте это в своем подрядчике по умолчанию.

- C# default constractor уже инициализирует 0 в int [].

, если вы до сих пор, что для запуска Start из другой сферы в коде обнародуют его (C# делает переменные/методы как частные по умолчанию)

+0

Спасибо за вашу помощь. Я все еще изучаю дизайн. Когда я отлаживаю печать, я вижу, что запуск запускается один раз во время сцены. Причина, по которой я вызываю другую функцию в Start, заключается в том, что она должна сохранять и загружать в зависимости от состояния игры, и они являются функциями класса, а не внешними. – Sangratura

+1

Я нашел, что проблема. Функция, которая дает неправильные результаты, вызывается кнопкой Unity. Так или иначе, когда кнопка нажата, он не ищет объект контроллера, который присутствует в сцене, и использует сам класс, который имеет значение по умолчанию 0 для своей звездной переменной. Но более интересно, что это не вызывает его конструктор в этом процессе. Если бы я сказал функции специально искать экземпляр этого класса, который присутствует в сцене, и использовать его переменные, то бум он работает. – Sangratura

+0

Привет, Леон. НЕТ, что это проект UNITY3D - нет ни одного синглтона. – Fattie

Смежные вопросы