【问题标题】:C# OnTriggerEnter NullReferenceExceptionC# OnTriggerEnter NullReferenceException
【发布时间】:2013-04-16 14:14:17
【问题描述】:

我在学习中使用 Zigfu 的 ZDK 进行游戏项目。我拿了标准的化身并在手上附加了两个对撞机(带刚体的球体对撞机)。一个用于左手,一个用于右手。 我在化身周围构建了一些 (24) 盒式对撞机,以跟踪手是否正在进入新区域。每个盒子都有一个从 0 到 23 的“id”以及以下脚本:

using UnityEngine;
using System.Collections;

public class handsTracking : MonoBehaviour 
{
    public int id;

    void OnTriggerEnter (Collider other) {
        if(other.tag == "handsLeftTracking"){
            print("leftHand entered: " + id);
            playerCommunication.activity += 0.1f;
            playerCommunication.handsLeft[id] = true; //here ist the exception
        }
        else if (other.tag == "handsRightTracking"){
            print("rightHand entered: " + id);
            playerCommunication.activity += 0.1f;
            playerCommunication.handsRight[id] = true; //here ist the exception
        }
    }
    void OnTriggerExit (Collider other) {
        if(other.tag == "handsLeftTracking"){
            print("leftHand exited: " + id);
            playerCommunication.activity += 0.01f;
            playerCommunication.handsLeft[id] = false; //here ist the exception
        }
        else if (other.tag == "handsRightTracking"){
            print("rightHand exited: " + id);
            playerCommunication.activity += 0.01f;
            playerCommunication.handsRight[id] = false; //here ist the exception
        }
    }
}

在播放器的另一个脚本中,我想使用这些碰撞。 handsTracking.cs 应该只编辑 playerCommunication.cs 脚本中的值:

using UnityEngine;
using System.Collections;

public class playerCommunication : MonoBehaviour {

    public static bool[] handsRight;
    public static bool[] handsLeft;
    public static float activity;
    public float fallback;

    // Use this for initialization
    void Awake () {
        activity = 0.0f;
    }

    // Update is called once per frame
    void Update () {
        if((activity - fallback * Time.deltaTime) >= 0.0f){
            activity -= fallback * Time.deltaTime;
        }
    }

    void OnGUI () {
        GUI.Box (new Rect (10,200,150,20), "Activity: " + activity);    
    }
}

到目前为止,这工作正常。但我得到以下例外:

NullReferenceException: Object reference not set to an instance of an object
handsTracking.OnTriggerEnter (UnityEngine.Collider other) (at Assets/SeriousGame/Scripts/handsTracking.cs:19)

如果我推荐我尝试编辑数组的行,错误就会消失。 我试图在 playerCommunication 脚本中调用一个函数,或处理 handsTracking.cs 中的数组,但没有任何效果。不明白碰撞和数组之间的联系?!

【问题讨论】:

  • 在发生错误的第 19 行,我看到 }。我从顶部倒数,所以我看不到行号。错误具体发生在哪一行?
  • 啊抱歉,我对代码做了一点实验,所以错误与这里的代码不匹配。我现在又开始了,它仍然是 playerCommunication.handsLeft[id] = true; 的行,......在这里他抛出了异常......

标签: c# unity3d collision


【解决方案1】:

您的数组从未被初始化过。你得到了一个NullReferenceException,因为你的数组是对 null 的引用,因为它没有被分配到任何地方。

例如,您可以在 Awake 中初始化它们:

int[] array1 = new int[5];

public static bool[] handsLeft;

// Use this for initialization
void Awake () {
    activity = 0.0f;
    handsLeft = new bool[ARRAY_SIZE];
}

也许您尝试从检查器初始化这些数组字段,但它们被声明为静态,因此当您从编辑器切换到播放模式时,Unity3D 不会序列化它们。

请注意,playerCommunication 类的所有实例都将共享一个静态字段。所以,如果你想让多个 GameObject 使用这个脚本,并且在你的数组中有不同的值,你不应该将它们声明为静态的。

如果你想有效地将​​它们声明为静态,因为你不知道你的类的创建顺序,最好在类静态构造中初始化它们:

static playerCommunication ()
{
     handsLeft = new bool[ARRAY_SIZE];
     handsRight = new bool[ARRAY_SIZE];
}

【讨论】:

  • 在 awake() 函数中初始化数组解决了我的问题,谢谢!
【解决方案2】:

你得到一个空指针异常的原因是你试图在数组中添加一个尚未初始化的对象。

您有以下声明:

public int id;

之后,你有以下代码行:

print("leftHand entered: " + id);

将其更改为,例如:

Debug.Log("ID value is now: " + id);

您可能会看到以下内容:

ID value is now: null

你还没有给id 赋值。当您调用playerCommunication.handsLeft[id] = true; 时,您实际上是在尝试将数组的null'est 值设置为true。确保将 id-value 设置为某个值。你说每个盒子都有一个从 0 到 23 的 id 值。你在 Unity 属性视图中设置正确了吗?

【讨论】:

  • 我在 Unity 检查器中设置了 id。当然,我使用print("id"); 检查了 id 的值,我尝试了 Debug.Log 到现在。这里的变量也是正确的:ID value is now: 19 UnityEngine.Debug:Log(Object) handsTracking:OnTriggerEnter(Collider) (at Assets/SeriousGame/Scripts/handsTracking.cs:11)
【解决方案3】:

我猜测您收到异常的原因是因为您没有访问播放器上的 playerCommunication 脚本,而是尝试使用脚本文件夹中的那个(我想)没有有什么设置在公众手中等。

你需要做的是像这样替换行:

playerCommunication.handsLeft[id] = true;

用这个:

GameObject.Find("Avatar").GetComponent<playerCommunication>().handsLeft[id] = true;

其中“Avatar”将是化身/玩家游戏对象的名称,而 playerCommunication 是该对象中具有 handsLeft 公共布尔值的脚本。

【讨论】:

  • handsRight 被声明为静态,因此他可以通过类名直接访问。
  • @Heisenbug 它是静态的,但在 Unity 中,您可以填充数组并从 Inspector 设置其大小。听起来他为播放器对象设置了大小并填充了数组,但文件夹中的脚本仍然没有。因此例外。
  • 在编辑器和播放模式之间切换时,静态字段不会被序列化。所以即使他已经从inspector初始化了,数据也会丢失。
  • @Heisenbug 这仍然不是重点。正如他所说:“在播放器的另一个脚本中,我想使用这些碰撞。handsTracking.cs 应该只编辑 playerCommunication.cs 脚本中的值”,这意味着他不想访问游戏文件夹中的脚本,他想访问播放器上的脚本。
  • 这是一个静态字段。 playerCommunication 的所有实例都将共享同一个 handsLeft 数组。
猜你喜欢
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多