2016-06-08 3 views
2

Я создаю двумерную космическую игру в Unity. У меня есть объект под названием «Player» с прикрепленным к нему скриптом. В сценарии, у меня есть класс, представляющий корабль игрока:List.Count Raises Null Reference Exception

public class Ship : MonoBehaviour 
{ 
    public List<Weapon> weaponsList; 

    void Start() 
    { 
     weaponsList = new List<Weapon>(); 
     weaponsList.Add(new Weapon()); 
     weaponsList.Add(new Weapon()); 
    } 
} 

И этот класс (в пределах того же сценария), представляющий собой оружие:

public class Weapon 
{ 
    //properties here 
} 

Теперь, когда я пытаюсь ссылаться weaponsList, чтобы получить List.Count с помощью этого кода (из другого скрипта), он бросает NullReferenceException, говоря ссылка на объект не указывает на экземпляр объекта:

Ship ship = GameObject.Find("Player").GetComponent<Ship>(); 
if (ship.weaponsList.Count >=2) 
{ 
    //do stuff 
} 

Но любое другое имущество судна Я пытаюсь получить доступ к работам просто отлично. Может кто-нибудь помочь? Если вам нужен дополнительный контекст или код, сообщите мне, и я сделаю необходимые изменения.

EDIT: Метод запуска является особым для Unity и всегда вызывается по умолчанию при инициализации сценария.

ответ

1

Чтобы избежать этой ошибки Добавить конструктор в класс

public class Ship : MonoBehaviour 
{ 
    public Ship() 
    { 
     weaponsList = new List<Weapon>(); 
    } 
    public List<Weapon> weaponsList; 

    void Start() 
    { 
     weaponsList = new List<Weapon>(); 
     weaponsList.Add(new Weapon()); 
     weaponsList.Add(new Weapon()); 
    } 
} 
+0

Это решило проблему. Я сделал редактирование вопроса о том, что Unity всегда вызывает метод Start(), когда скрипт инициализируется раньше всего, поэтому я предположил, что он будет работать так же, как и конструктор. Спасибо за предложение. –

+2

Это решение вызывает инициализацию 'weaponList' дважды. Если что-то было сделано с 'weaponList', прежде чем вызывать метод' Start() ', это приведет к нечетному поведению. Лучше удалите вторую инициализацию из метода 'Start()' и еще лучше убедитесь, что 'weaponList' может быть инициализирован только один раз и/или только внутри класса' Ship'. –

0

Корабль не содержит список оружия.

Вы можете избежать этого исключения

Ship ship = GameObject.Find("Player").GetComponent<Ship>(); 
if (ship != null && ship.weaponsList != null && ship.weaponsList.Count >=2) 
{ 
    //do stuff 
} 

¿Является ли метод Start() был звонок?

0

Вместо того, чтобы инициализировать список оружия в void Start(), поместите его в конструктор объекта. Затем, когда корабль будет создан, список оружия всегда будет инициализирован нулевым отсчетом. Конструктор всегда должен помещать рассматриваемый объект в допустимое состояние, чтобы его можно было использовать. Иногда программисты создают методы Init() или Start(), чтобы отложить дорогостоящую логику до тех пор, пока метод действительно не понадобится, но в этом случае я определенно поставил бы эту инициализацию в конструкторе.

0

Список построен, когда Start() называется. Если Start() не вызывается до доступа к списку, появится ваша ошибка. Я предполагаю, что вы пытаетесь получить доступ к списку до того, как вызывается Start().

Вы должны подумать о создании конструктора для класса Ship и размещая код инициализации там:

public class Ship : MonoBehaviour 
{ 
    public List<Weapon> weaponsList; 

    public Ship() 
    { 
     weaponsList = new List<Weapon>(); 
     weaponsList.Add(new Weapon()); 
     weaponsList.Add(new Weapon()); 
    } 
} 

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

1

Ваш weaponsList является null если Start() не называется ... или он становится null в какой-то момент. Измените открытую переменную, чтобы стать общественным достоянием, чтобы запретить внешним абонентам изменять внутренний список:

public class Ship : MonoBehaviour 
{ 
    public List<Weapon> weaponsList { get; private set; } 
    public Ship() 
    { 
     weaponsList = new List<Weapon>(); 
    } 
    ... 
} 

Это, вероятно, создавать ошибки компилятора в других частях вашего приложения. Эти ошибки, вероятно, являются причиной того, почему weaponsList становится null.

С точки зрения лучшей практики кодирования еще несколько предложений, чтобы изменить свойство к этому:

public IList<IWeapon> Weapons { get; private set; } 
  • Изменение List к интерфейсу.
  • Измените Weapon на IWeapon. (Weapons, а не weapons).
  • типы Избегайте в именах: Weapons, не WeaponsList (что это список очевидно)
Смежные вопросы