【Unity3D】SetActive的NullReferenceException与LoadLevel的初始化

一、SetActive的NullReferenceException

众数周知,让一个物体隐藏,使用的是SetActive(false),比起移到视野外,又要重新移回来计算坐标;或者直接改透明度,考虑到2D对象不一定有render给你改,这算是万能通用的方法,也是最普遍的方法,但是,在使用中,常常遇到隐藏又显示的情况,此时就不是简简单单地一句SetActive(true)能搞定的,如下代码:

using UnityEngine;
using System.Collections;

public class Script : MonoBehaviour
{

    //错误的写法
    void Start()
    {
        GameObject.Find("Text1").SetActive(false);
    }

    void Update()
    {
        //一开始,想先让Text1隐藏……
        //做了一些事件之后,我想让其重新显示……
        GameObject.Find("Text1").SetActive(true);
    }
}
这叫姿势不对,会报如下的错误:


因为SetActive(false)之后会带来一种副作用,GameObject.Find("XX");将再也找不到这个对象,

所以在SetActive(false)使用之前,我们一定要留个种,不然真的和直接销毁这个物体没区别~

正确写法是这样的,比如这里是Text的隐藏与显示:

using UnityEngine;
using System.Collections;

public class Script : MonoBehaviour
{
    //正确的写法
    GameObject Text1;
    void Awake()
    {
        Text1 = GameObject.Find("Text1");//你必须先在Awake()函数找到这个对象,并保留其实例(基本和指针的意思)
    }
    void Start()
    {
        Text1.SetActive(false);//然后在Start()基于其属性,分2步初始化,比较麻烦。
    }
    void Update()
    {
        //一开始,想先让Text1隐藏……
        //做了一些事件之后,我想让其重新显示……
        Text1.SetActive(true);
    }
}

二、LoadLevel的初始化

使用Application.LoadLevel("某某场景"),当然Unity5.x已经取消掉了,不过在大部分项目还是Unity4.x的前提下,这方法还是非常常见。

首先这方法一上来就是一个坑,在Applicaiton有个loadedLevel分分钟让你混淆,尤其是你写程序写到飘飘欲仙,迷迷糊糊的时候,不小心用了loadedLevel是一辈子都在报错的。


这还是小问题,如果这东西配合Time.timeScale = 0;使用,那就又有一个坑。

例如,我布置了一个场景,此场景中有个刚体球会自然下落,然后落到y<0的位置会自动停止,同时弹出版本,提示“游戏结束”,当然我们肯定要设置一个按钮,给用户重新开始,显示起来的代码,自然而然如下:

using UnityEngine;
using System.Collections;

public class Script : MonoBehaviour
{
    //初始化的时候我需要将Text1这东西隐藏……
    GameObject Text1;
    void Awake()
    {
        Text1 = GameObject.Find("Text1");
    }
    void Start()
    {
        Text1.SetActive(false);
    }

    void Update()
    {
        //一段代码、一段处理、一段事情之后……
        //……
        //比如用户Gameover之类的,我需要让这个场景停止一个
        //if(游戏失败){
        if (GameObject.Find("Sphere").transform.position.y < 0)
        {           
            Time.timeScale = 0;
            Text1.SetActive(true);
        }
        //}
    }

    //这或许是你的提示窗里面的一个按钮的onclick事件
    public void onRestart()
    {
        Application.LoadLevel("Canvas");
    }
}
但具体的运行效果却是如下的:


此游戏的球,在开始的时候,原本是自然而然地落下的,但是,点击button之后,执行Application.LoadLevel("Canvas"),重新载入本关,它就不会开始自动掉了。

甚至有些版本的Unity3D,那个文字不会在初始化的时候隐藏。喂!不是说Application.LoadLevel("Canvas")所有东西会重新还原的吗?而且Start、Awake这些初始化函数也照样会执行一遍的吗?你官方文档都这样写了!我的球的刚体属性怎么没了?


其实Application.LoadLevel一点问题都没有,你错就错在用了Time.timeScale = 0;布置了一个时间结界,告诉用户一些信息之后,在用户点击“重新开始”游戏,没重新将这个时间结界打开而已,你在Awake()函数再补个Time.timeScale = 1;如下代码:

using UnityEngine;
using System.Collections;

public class Script : MonoBehaviour
{
    //初始化的时候我需要将Text1这东西隐藏……
    GameObject Text1;
    void Awake()
    {
        Time.timeScale = 1;//记得重新打开时间结界哦,由于有Application.LoadLevel的存在
        Text1 = GameObject.Find("Text1");
    }
    void Start()
    {
        Text1.SetActive(false);
    }

    void Update()
    {
        //一段代码、一段处理、一段事情之后……
        //……
        //比如用户Gameover之类的,我需要让这个场景停止一个
        //if(游戏失败){
        if (GameObject.Find("Sphere").transform.position.y < 0)
        {
            Time.timeScale = 0;//关了时间结界
            Text1.SetActive(true);
        }
        //}
    }

    //这或许是你的提示窗里面的一个按钮的onclick事件
    public void onRestart()
    {
        Application.LoadLevel("Canvas");
    }
}
就药到病除了:


这是在使用了LoadLevel的时候,初始化时候容易忽视的问题!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值