Unity 2D:NullReferenceException。如何添加两个管理器脚本?
Unity 2D: NullReferenceException. How to add two manager scripts?
我是 Unity 的新手,所以请容忍我糟糕的解释。我在 youtube 上关注了一个关于 2D 格斗游戏的教程:https://www.youtube.com/watch?v=n8S3WgVoOmo&t=3319s
我将在下面提供我的代码。
在链接的视频中,视频制作者制作了一个 PlayerManager
脚本来控制我的播放器和我的播放器的副本。通过一个简单的 AI,复制品成为我的敌人,我们开始战斗。这符合预期。
现在我想把它改得有点像 2D 平台游戏。我把 PlayerManager
分成两部分。 AIManager
(与整个教程中的代码相同)和 PlayerManager
,但有一些变化。这也很有效,我可以移动,而且 AI 也能认出我。问题来自一个名为 DamageScript 的脚本。它会识别我是否以及何时受到伤害,并触发相关动画。
当DamageScript
只连接到PlayerManager
时,当我击中AI或AI击中我时,谁被击中显示伤害动画。但是在我进行拆分之后,有了单独的 AI 和 Player 经理,我有两个选择。要么我击中 AI,他做伤害动画,当他击中我时我得到错误。或者他打我,我有伤害动画,当我打他时我得到一个错误。错误是这样的:
NullReferenceException: Object reference not set to an instance of an object
DamageScript.OnTriggerEnter2D (UnityEngine.Collider2D col) (at Assets/Scripts/DamageScript.cs:19)
这是原始的 DamageScript:
public class DamageScript : MonoBehaviour {
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<PlayerManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
这样我的播放器就可以制作伤害动画,当我击中时会出现错误。所以,我想像这样的东西会起作用,但我想我真的不知道如何编码:
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
line 11 if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<AIManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
else
{
if (!col.transform.GetComponent<PlayerManager>().damage)
{
line 19 col.transform.GetComponent<PlayerManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
}
毫不奇怪,它不起作用,我仍然在某些点击时崩溃。
如果可能的话,我们将不胜感激。
谢谢!
根据您所描述的情况,我假设错误主要是由于责任委派的错误重构造成的。
更具体地说,我相信很明显您所遵循的教程没有正确遵循 single responsibility principle,而是实施了 多重责任(玩家和AI) 在单个 class/file 上,以节省视频时间或简化教程。
稍后,当将职责拆分为两个脚本和两个对象时,作为初学者,您 was/is 不了解参考管理中涉及的一些细节 and/or 陷阱,因此无法分配对两个对象的引用,或者由于脚本现在已拆分而无法处理丢失的引用。
出现这个问题是因为,如果你的玩家和AI现在有不同的脚本集;每个经理都有一个,但两者都没有(不像以前,当玩家和 AI 对象都有 "both");然后,在第一个或第二个 if
*manager.damage
语句中,有问题的管理器不会在 GetComponent
中找到,因为它不在该对象中,并且在尝试访问 fields/properties/methods 在 null
引用上,将抛出 NullReferenceException
。
解决方案只是在访问 fields/properties/methods 之前进行适当的空值检查,以防止出现异常并在发现第一个管理器是 [= 时继续执行第二个 if
语句14=].
同时,不妨缓存查询以使事情变得更好,正如 RetiredNinja 在评论中所建议的那样。
代码:
void OnTriggerEnter2D(Collider2D col) {
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger) {
//Cache to avoid multiple queries and to simplify access
var playermanager = col.transform.GetComponent<PlayerManager>(); //One of these won't be found and will receive null instead
var aiManager = col.transform.GetComponent<AIManager>(); //One of these won't be found and will receive null instead
var animator = col.transform.root.GetComponentInChildren<Animator>();
if (aiManager != null //Null-check was missing
&& !aiManager.damage && !aiManager.blocking) { //Much nicer
aiManager.damage = true;
if(animator!=null)
animator.SetTrigger("Damage");
}
else {
if (playerManager != null && !playerManager.damage) {
playerManager.damage = true;
animator.SetTrigger("Damage");
}
}
}
}
我是 Unity 的新手,所以请容忍我糟糕的解释。我在 youtube 上关注了一个关于 2D 格斗游戏的教程:https://www.youtube.com/watch?v=n8S3WgVoOmo&t=3319s
我将在下面提供我的代码。
在链接的视频中,视频制作者制作了一个 PlayerManager
脚本来控制我的播放器和我的播放器的副本。通过一个简单的 AI,复制品成为我的敌人,我们开始战斗。这符合预期。
现在我想把它改得有点像 2D 平台游戏。我把 PlayerManager
分成两部分。 AIManager
(与整个教程中的代码相同)和 PlayerManager
,但有一些变化。这也很有效,我可以移动,而且 AI 也能认出我。问题来自一个名为 DamageScript 的脚本。它会识别我是否以及何时受到伤害,并触发相关动画。
当DamageScript
只连接到PlayerManager
时,当我击中AI或AI击中我时,谁被击中显示伤害动画。但是在我进行拆分之后,有了单独的 AI 和 Player 经理,我有两个选择。要么我击中 AI,他做伤害动画,当他击中我时我得到错误。或者他打我,我有伤害动画,当我打他时我得到一个错误。错误是这样的:
NullReferenceException: Object reference not set to an instance of an object
DamageScript.OnTriggerEnter2D (UnityEngine.Collider2D col) (at Assets/Scripts/DamageScript.cs:19)
这是原始的 DamageScript:
public class DamageScript : MonoBehaviour {
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<PlayerManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
这样我的播放器就可以制作伤害动画,当我击中时会出现错误。所以,我想像这样的东西会起作用,但我想我真的不知道如何编码:
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
line 11 if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<AIManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
else
{
if (!col.transform.GetComponent<PlayerManager>().damage)
{
line 19 col.transform.GetComponent<PlayerManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
}
毫不奇怪,它不起作用,我仍然在某些点击时崩溃。 如果可能的话,我们将不胜感激。 谢谢!
根据您所描述的情况,我假设错误主要是由于责任委派的错误重构造成的。
更具体地说,我相信很明显您所遵循的教程没有正确遵循 single responsibility principle,而是实施了 多重责任(玩家和AI) 在单个 class/file 上,以节省视频时间或简化教程。
稍后,当将职责拆分为两个脚本和两个对象时,作为初学者,您 was/is 不了解参考管理中涉及的一些细节 and/or 陷阱,因此无法分配对两个对象的引用,或者由于脚本现在已拆分而无法处理丢失的引用。
出现这个问题是因为,如果你的玩家和AI现在有不同的脚本集;每个经理都有一个,但两者都没有(不像以前,当玩家和 AI 对象都有 "both");然后,在第一个或第二个 if
*manager.damage
语句中,有问题的管理器不会在 GetComponent
中找到,因为它不在该对象中,并且在尝试访问 fields/properties/methods 在 null
引用上,将抛出 NullReferenceException
。
解决方案只是在访问 fields/properties/methods 之前进行适当的空值检查,以防止出现异常并在发现第一个管理器是 [= 时继续执行第二个 if
语句14=].
同时,不妨缓存查询以使事情变得更好,正如 RetiredNinja 在评论中所建议的那样。
代码:
void OnTriggerEnter2D(Collider2D col) {
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger) {
//Cache to avoid multiple queries and to simplify access
var playermanager = col.transform.GetComponent<PlayerManager>(); //One of these won't be found and will receive null instead
var aiManager = col.transform.GetComponent<AIManager>(); //One of these won't be found and will receive null instead
var animator = col.transform.root.GetComponentInChildren<Animator>();
if (aiManager != null //Null-check was missing
&& !aiManager.damage && !aiManager.blocking) { //Much nicer
aiManager.damage = true;
if(animator!=null)
animator.SetTrigger("Damage");
}
else {
if (playerManager != null && !playerManager.damage) {
playerManager.damage = true;
animator.SetTrigger("Damage");
}
}
}
}