2016-06-08 53 views
2

我在Unity中创建2D宇宙飞船游戏。我有一个标题为“Player”的对象,并附有此脚本。在脚本中,我代表游戏者的船这个类:List.Count引发空引用异常

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 
} 

但船上其他财产我尝试访问作品很好。有人可以帮忙吗?如果您需要其他上下文或代码,请告诉我,我会进行必要的修改。

编辑:启动方法是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'被初始化两次。如果在调用'Start()'方法之前有'weaponList'做了任何事情,这会导致奇怪的行为。最好从'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

您的weaponsListnull如果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(这是一个列表是显而易见的)