unity3d判空方法_unity gameobject 判空 - CSDN
精华内容
参与话题
  • F:http://www.unitygeek.com/unity_c_singleton/ Objective : ...Singleton is a very complex topic, In this, we try to understand basics and various implementation of Singleton in Unity3d using

    F:http://www.unitygeek.com/unity_c_singleton/

    Unity_Singleton

    Objective :

    Singleton is a very complex topic, In this, we try to understand basics and various implementation of Singleton in Unity3d using C#.

    Intro:

    Singleton is a basic Design Pattern. Classes implementing Singleton pattern will ensure that only one instance of the object ever exists at any one time. It is recommend using Singletons for things that do not need to be copied multiple times during a game.This is great for controller classes like GameManager or AudioController.

    Implementation:

    There are several ways of implementing Singleton in Unity, we will some of the implementation in this tutorial

    1. Simplest Implementation
    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    public class SingletonController : MonoBehaviour {
    public static SingletonController instance;
     
      private void Awake() {
       if (instance != null) {
         Destroy(gameObject);
       }else{
         Instance = this;
       }
     }
    }

    Above code is the simplest implementation of Singleton, but there are some issues which we have to address

    1. Singleton is not persistent across the Unity scenes.
    2. All the executable code must be attached to GameObject in the hierarchy.
    3. It is not recommended to call SingletonController.Instance in any Awake() method because, since we don’t know the order that Awake() will be executed through all scripts, we can end up with a Null Reference Exception.
    4. This code works only for SingletonController Class, but if you want another singleton controller eg. AudioController, we have to copy paste the same code to AudioController Class and do some minor changes to works, but this leads to boilerplate code .

     

    Solution For First Issue:

    This one is easy to fix, just add the DontDestroyOnLoad(gameObject)

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    public class SingletonController : MonoBehaviour {
    public static SingletonController instance;
     
      private void Awake() {
       if (instance != null) {
         Destroy(gameObject);
       }else{
         Instance = this;
         DontDestroyOnLoad(gameObject);
       }
     }
    }

    Solution for Second and Third Issue :

    For this issue we have to create the Singleton at the time it is required, means we have to lazily instantiate the SingletonController in Unity

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class SingletonController : MonoBehaviour
    {
       

 private static SingletonController instance = null;

       public static SingletonController Instance

        {

          get
         
 {
             if(instance == null)

             {

                instance = FindObjectOfType<SimpleSingleton>();

                if( instance == null)

                {
                 
 GameObject go = new GameObject();
                  go.name = "SingletonController";
                  instance = go.AddComponent<SingletonController>();

                  DontDestroyOnLoad(go);

                }
             
 }
              

 return instance;

            }
         
 }
        


 void Awake()

         {

           if(instance == null )

           {
             instance = this;

             DontDestroyOnLoad(this.gameObject);

           }
          else
           {
             Destroy(gameObject);

           }
        }

    }

    Above code solves two different issues, it first searches for instance of SingletonController  in the scene, If it doesn’t find a SingletonController component, a GameObject is created and a SingletonController component is attached to it, so with this it is not necessary for SingletonController to exist in the scene before hand, and  this code will also destroy any additional copies it finds.

    As in this implementation we are lazily instantiating the Singleton, so now we did not worry about Null Reference Exception.

    Solution for Fourth Issue : Generic Unity Singleton

    The fourth issue was boilerplate code, so we need generic implementation of Singleton to solve this issue

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class GenericSingletonClass<T> : MonoBehaviour where T : Component
    {
        private static T instance;
        public static T Instance {
          get {
            if (instance == null) {
               instance = FindObjectOfType<T> ();
               if (instance == null) {
                 GameObject obj = new GameObject ();
                 obj.name = typeof(T).Name;
                 instance = obj.AddComponent<T>();
               }
            }
           return instance;
          }
        }
     
        public virtual void Awake ()
        {
           if (instance == null) {
             instance = this as T;
             DontDestroyOnLoad (this.gameObject);
        } else {
          Destroy (gameObject);
        }
      }
    }

    So with this class we can make any class singleton, without duplicating  the code. Just inherit your class fromGenericSingletonClass and it ready to go.

    e.g

    ?
    1
    2
    3
    4
    public class MyAudioController : GenericSigletonClass<MyAudioController>;
    {
      
    }

     

    Conclusion:

    Singleton is bit complex, but it plays very important role in game development. In complex game we may need many Singleton, so it is good to have a generic implementation of Singleton to reduce code duplication. Fourth solution deals with most of the issue.

     

    I am happy to hear from you guys, Please share your view in the comment section.


    展开全文
  • ... 两种都试过都不行 总是提示 ...Couldn't open file /项目/Assets/StreamingAssets/Actor.assetbundle ...<LoadRoleGameObject>c__Iterator17:MoveNext() (at Assets/EffectScripts/ABC.cs:20) ...
  • 就在Awake()方法里面写了GameObject.FindGameObjectWithTag(Tags.player).GetComponentInParent();这句代码 报指针错误,调试发现是Getcomponent出错了。 查了好久发现脚本确实在本体而没有在子物体,也没有在别...

    今天跟着视频写代码,最后是获得游戏主角身上的脚本的信息来使物品栏显示。

    就在Awake()方法里面写了GameObject.FindGameObjectWithTag(Tags.player).GetComponent<PlayerStatus>();这句代码

    报空指针错误,调试发现GameObject.Find没有错而是Getcomponent出错了。

    查了好久发现脚本确实在本体而没有在子物体,也没有在别的脚本禁用PlayerStatus(自己猜的)。


    这就有点纳闷了。

    于是就把代码改为

     print(GameObject.FindGameObjectWithTag(Tags.player).GetComponentInParent<PlayerStatus>());

    打印出来后竟然找到PlayerStatus这个脚本了,

    然后将GameObject.FindGameObjectWithTag(Tags.player)的内容打印出来

    结果就有点惊讶了GameObject.FindGameObjectWithTag(Tags.player)找到的是Magician下的Magician_Body


    其实是Magician和Magician_Body都设置了tags.player这个标签

    后者是不经意设上去的。

    算是自己对这个函数不了解吃的亏吧!

    所以以后看函数要了解清楚(其实说了可能过会就忘了)

    下次再遇见这样的错误可能就是这个原因了。


    展开全文
  • 持久化数据PlayerPrefs其实说白了,就是Android里面的bundle《【Android】多个Activity之间利用bundle传递数值》...在《【Unity3D】同场景物体传值与Vector》(点击打开链接)我曾经写了Unity3D中,同一个场景的各个

    持久化数据PlayerPrefs其实说白了,就是Android里面的bundle《【Android】多个Activity之间利用bundle传递数值》(点击打开链接),其实说得更直白些,就是一个超级全局变量,这个全局变量贯穿于整个游戏之中,所有的场景都可以对其操作,相当于一个文件似得的。在《【Unity3D】同场景物体传值与Vector》(点击打开链接)我曾经写了Unity3D中,同一个场景的各个组件怎么传递数据,本文将论述如何在场景中传值。同时,继《【Unity3D】场景切换、UGUI组件事件、开始游戏与关闭游戏》(点击打开链接)继续补存UGUI的使用,讲述下按钮组ToggleGroup如何使用。

    下面将用一个程序讲述这个问题,如图所示,其实也不用怎么解释,类似与《【php】基本语法与页面之间数值传递》(点击打开链接):


    具体制作过程如下:

    一、场景布置

    1、两个场景一个Input,另一个Output。Input场景布置如下图,3个Text分别是姓名、性别与国籍这个没什么好说,下拉列表DropDownList在《【Unity3D】Unity3D 4.x利用原生UGUI完成下拉列表DropDownList》(点击打开链接)已经说过。InputField输入框其实也没什么好说的,直接在GameObject->UI->InputField可以创建。


    下面重点说说按钮组ToggleGroup的制作:

    (1)先在Canvas下创建一个Create Empty改名为ToggleGroup,部分版本默认的话,空物体会直接创建到Canvas以外,需要再自己手动拖到这个Canvas以内,不然之后附着于这个空物体的Toggle看不到。

    (2)之后在这个ToggleGroup创建Toggle,只有一个Toggle的Is On是打开的。


    (3)最关键的是这里,在空物体ToggleGroup添加组件UI->Toggle Group


    (4)之后,对于各个Toggle,Toggle0~ToggleN,都设置为这个组的成语,如图所示:


    至此一个按钮组ToggleGroup制作完毕,在这个组下的Toggle只有一个可以被选择。

    2、下面Output场景的布置简单得不能再简单,就一个Canvas、一个Button和一个用于接受输出结果的Text,还有一个用于接受脚本的空物体GameObject。


    二、脚本编写

    1、Input场景的脚本核心,在于最下方的确定按钮,给予一个Ensure.cs,如下所示:

    using UnityEngine;
    using UnityEngine.UI;//用到了多个UI
    using System.Collections;
    using System.Collections.Generic;//按钮组将会用到C#的集合
    
    public class Ensure : MonoBehaviour
    {
    
        public void Onclick()
        {
            string name = GameObject.Find("Canvas/InputField/Text").GetComponent<Text>().text;//这样就能直接获取输入框的输入内容
            //当然接下来你还可以做些判空检测之类的
    
            //接下来将展示按钮组的使用
            string sex = "";
            IEnumerable<Toggle> toggleGroup = GameObject.Find("Canvas/ToggleGroup").GetComponent<ToggleGroup>().ActiveToggles();//用于获取按钮组中哪个Toggle被选择
            foreach (Toggle t in toggleGroup)
            {//遍历这个存放Toggle的按钮组IEnumerable,此乃C#的一个枚举集合,一般直接用foreach遍历
                if (t.isOn)//遍历到一个被选择的Toggle
                {
                    switch (t.name)//根据这个Toggle的name,我们给string sex赋予不同的值
                    {
                        case "Toggle0":
                            sex = "男";
                            break;
                        case "Toggle1":
                            sex = "女";
                            break;
                    }
                    break;//就没必要遍历下去了,后面已经可以预见到,都是没被选择的Toggle。
                }
            }
    
            //最后是下拉菜单的获取
            string nation = GameObject.Find("Canvas/DropDownList/Button0/Text").GetComponent<Text>().text;
    
            //用持久化数据PlayerPrefs来存储数据
            //Unity3D对中文支持不好,必须按照擦写一下,才能保存到这个PlayerPrefs里面
            //实质上,PlayerPrefs是一个key-value的键值对,也就是Java中的Map,Python中的Dict,Javascript的Json……就是一个数据字典
            PlayerPrefs.SetString("name", WWW.EscapeURL(name));
            PlayerPrefs.SetString("sex", WWW.EscapeURL(sex));
            PlayerPrefs.SetString("nation", WWW.EscapeURL(nation));
    
            Application.LoadLevel("Output");//切换到场景Output
        }
    
    }
    
    上述脚本同时展示了UGUI用户输入组件中,对用户输入数据的获取。其中按钮组ToggleGroup遍历的思想,与《【mfc】标签页》(点击打开链接)中是一模一样的。对存放在数组的Toggle直接进行遍历得了!

    最后这里的持久化数据PlayerPrefs,大家权当一个数据字典来操作就好,HashMap这东西在各个语言都有,也就是所谓的容器类,估计对其研究得更加透彻的,大有人在,大部分的程序猿的面试题一考再考……这里需要小吐槽一个,人家Android什么的全局变量是支持setObject的,它这个Unity3d作为这么高级的游戏引擎,居然只让setString、setInt和setFloat简直药丸,毕竟扔个数组什么的,估计他让你走文件了,又或者自己弄成json字符串压进去吧……存个东西还要像Javascript害怕乱码一样转个码-_-!

    而Unity3D的切换场景在《【Unity3D】场景切换、UGUI组件事件、开始游戏与关闭游戏》(点击打开链接)说过了,这里不再赘述了。

    2、至于Output场景赋予其空物体GameObject的脚本Result.cs更是简单了:

    using UnityEngine;
    using UnityEngine.UI;//用到Text这头文件还是需要的
    using System.Collections;
    
    public class Result : MonoBehaviour
    {
    
        void Start()
        {
            //将持久化数据PlayerPrefs的结果输出到Text
            GameObject.Find("Canvas/Text").GetComponent<Text>().text =
                    WWW.UnEscapeURL(PlayerPrefs.GetString("name")) + "," +
                    WWW.UnEscapeURL(PlayerPrefs.GetString("sex")) + "," +
                    WWW.UnEscapeURL(PlayerPrefs.GetString("nation"));
        }
    
        public void Onclick()
        {
            Application.LoadLevel("Input");//切换回Input场景
        }
    
    }
    
    只是记得在输出持久化数据PlayerPrefs的时候注意,刚才是Input是转码压入PlayerPrefs的,你输出自然转回来。

    如果不经历这个转码解码的过程,亲测,对于中文,就是一堆坑爹Bug!

    展开全文
  • 补充:在胶囊碰撞体里的物体都会被检测到,因此当添加了...=1,导致浮判断为真.或者你可以重新写关于数组的判断方法. 这个问题困扰了我几天,在我找到解决方案之前,尝试了以下方法 1.射线,在角色坐标(一般是脚底...

    补充:在胶囊碰撞体里的物体都会被检测到,因此当添加了诸如武器之类的碰撞盒时,应该将他们的layer设置为和角色本身一样的Layer,否则将会导致碰撞数量大于一个,而且即使脱离了地面,OverLarpCapsule返回碰撞数组也会>=1,导致浮空判断为真.或者你可以重新写关于数组的判断方法.

     

    这个问题困扰了我几天,在我找到解决方案之前,尝试了以下方法

    1.射线,在角色坐标(一般是脚底),发射一根向下的射线,长度大约为0.2,这样是的确可以检测到玩家是否在地面的,但只适用于简单地形,如果你配置好了下落动画,那么用这种方法在斜面上往下走的话就会导致着地状态检测为false,如果有动画的话,就会播放浮空动画..这是由于角色往前走了一步时,刚体还没来得及让玩家因重力而下降足够的高度,导致射线不能射到斜面.因此判false,加长射线长度可以缓解问题,但又会导致跳跃动画出现问题,(动画会提前着地).而且在经过脚下有缝隙的情况而角色胶囊体半径大于缝隙并不会掉下去的时也会导致着地状态判false;

    2.unity官方角色控制器,简单的加上控制器并调用控制器脚本查询是否着地时无法达到想要的效果的,着地状态返回false,折腾了半天发现控制器只能在调用simplemove时(和move等移动函数)判断isGrounded(是否着地),而且播放一些动画会导致判断在true和false状态来回切换.并且Skinwidth也会导致这种问题.再加上一些角色控制器的限制,逻辑上不是那么自由.例如需要自己编写重力,因此我放弃了这个方法.

    如果你有能用角色控制器达到正确的效果的方法的话,希望能告诉我,谢谢

     

    最终使用的方法是投射一个胶囊碰撞体来检测地面

    方法来自这个视频,视频作者并不是我:视频链接

    原理:投射一个和角色本身胶囊体碰撞器一样大小的胶囊碰撞器,(也可以不一样,知道原理后就会知道什么样的大小合适了)通过这个胶囊体能比较准确的检测着地状态,再不是特别陡的坡和不是特别快的速度下都能比较准确的检测到.

    API:

    Physics.OverlapCapsule(pointBottom, pointTop, radius, LayerMask);

    以pointBottom为底部半圆圆心,PointTop为顶部半圆圆心,radius为半径,连接起来构成一个胶囊体。radius从玩家碰撞体获取,不过可以设置的小一点来避免侧面碰撞,一般设置为radius*0.9左右。

     

    值得注意的是:LayerMask的设置方法,假设ground层为10,那么这里如果要只碰撞第10层Layer,那么Layermask mask=1<<10;这是位运算.按这种格式写就行了.

    然而,投射的胶囊体也会检测自己本身,而再游戏中也希望基本上任何能碰撞物体都能够用来站脚,所以实际上我们要做的应该是碰撞除了用户本身Layer以外的所有层.假设Player层为8

    写出来的话就是:~(1<<8)

    ~可以理解为位运算的取反符号

    注意

    关于层级的三种写法:

    第一种:

    LayerMask.GetMask("Player")是获取玩家层级并且经过位运算后的层级,所以不能写成

    ~(1<<LayerMask.GetMask("Player"))

    这样并不会忽略玩家层级,获取到的还是玩家层级。应该写成下面这样才能忽略玩家层级。

     LayerMask ignoreMask = ~LayerMask.GetMask("Player");

    第二种忽略玩家层级的正确写法(玩家层级为8):

    LayerMask ignoreMask = ~(1<<8);

    删除~符号则为打开玩家层级。

    第三种忽略玩家层级的正确写法:

    LayerMask ignoreMask = ~(1<<LayerMask.NameToLayer("Player"));

    要想忽略多个或打开多个层级可以使用  | 符号(键盘上顿号的英文符号),如(1 << 10) | (1 << 8)表示打开第10层和第8层,

    ~((1<<10)|(1<<8))表示忽略第10层和第8层。

    总结:LayerMask.GetMask("Player")实际上相当于(1<<8),而LayerMask.NameToLayer("player")返回值为8,因此要注意两种函数的区别与写法。给LayerMask添加public修饰符的话还可以在Inspector面板中进行多选。

    实际的代码:

     private CapsuleCollider capsuleCollider;
        private Vector3 pointBottom, pointTop;
        private float radius; 
        public LayerMask ignoreLayer;
    
    void Awake () {
           
            capsuleCollider = GetComponent<CapsuleCollider>();
            radius = capsuleCollider.radius*0.9f;
    
    
        }

     

    bool OnGround()
        {
    
            pointBottom = transform.position + transform.up * radius-transform.up*overLapCapsuleOffset;
            pointTop = transform.position + transform.up * capsuleCollider.height - transform.up * radius;
            LayerMask ignoreMask = ~ignoreLayer;
    
            colliders = Physics.OverlapCapsule(pointBottom, pointTop, radius, ignoreMask);
            Debug.DrawLine(pointBottom, pointTop,Color.green);
            if (colliders.Length!=0)
            {
                isOnGround = true;
                return true;
            }
            else
            {
                 isOnGround = false;
                return false;
            }
         
           
        }

    注意玩家坐标的位置!overlapCapsuleOffset代表将胶囊体的下半球下移一定距离,如果在玩家中心,玩家高度为2的话,overlapCapsuleOffset则需要设置为1.1f,而如果坐标在玩家脚底则应该设置为0.1f左右。今天用自己博客里的检测方法半天检测不到地面才反应过来,赶紧来补充一下。

    另外: 为避免角色在下陡坡时直接浮空,应该增加一个时间变量来计算浮空时间,当达到一定时间后才播放浮空动画.同时也能避免角色在经过一个小坡后离地面只有几厘米时直接播放浮空动画的不合理情况.

     
    Searching...
    展开全文
  • 1. 一个gameObject被destroy,如何判断操作已经完成? 我试过gameObject == null ... 都不行是我的方法错了吗。 2. destroy删除后的游戏对象的内存是否被完全释放了,如果没有,我们如何进行清理工作?
  • Unity——关于UnityEngine.Object的判空

    千次阅读 2018-10-25 18:37:19
    #开始 先看一段代码: using UnityEngine; public class UnityEngineObjectCheck : MonoBehaviour { ... void Start () { ... GameObject go1 = new GameObject (&... GameObject go2 = new GameOb
  • Unity3D编辑器:删掉MissingScirpt脚本

    千次阅读 2017-09-21 09:25:32
    using UnityEngine; using System.Collections;...using UnityEditor; using UnityEngine.SceneManagement; public class RemoveMissingScripts : Editor { [MenuItem("Tools/移除丢失的脚本")] public static void
  • Unity中的Destroy和null 问题

    千次阅读 2018-08-01 19:55:31
    Unity中的Destroy和null 问题 Unity中,我们经常需要销毁物体,Unity也给我们提供了销毁的API。 Destroy( )和 DestroyImmediate( ); 这两种都可以进行销毁,但是还是有一定的区别,同时还是要注意使用的坑点。 ...
  • 1、Unity第一次启动时将streamingassets下的首包资源拷贝到persistentDataPath目录下。 2、Unity-android平台上的的这种操作只能使用www去加载streamingassets下的文件,导致速度问题。 备注: 1、此方案需要您对...
  • 在建立出UI時,Unity會自動幫我們建立Event System物件,此物件是基於滑鼠、觸摸、鍵盤的輸入方式,傳送 Event 到 Object 上,物件下有3個組件,分別為Event System Manager、Standalone Input Module、Touch ...
  • Unity 3D是套非常好用的遊戲開發引擎, 內建的物理系統讓使用者不需寫長長的程式碼, 就能夠迅速設定好所有物件之間的碰撞關係, 做出讓角色走不過去的牆、或是可以射穿牆壁的子...出處:關於unity3d碰撞的一些知識
  • [Unity 3D] Unity 3D 性能优化-粒子优化

    千次阅读 2016-10-24 14:26:18
    听到过很多用Unity 3D开发游戏的程序员抱怨引擎效率太低,资源占用太高,包括我自己在以往项目的开发中也头疼过。最近终于有了空闲,可以仔细的研究一下该如何优化Unity 3D下的游戏性能。其实国外有不少有关U3D优化...
  • Unity3d 周分享(20期 2019.6.30 )

    千次阅读 2019-06-30 15:03:41
    选自过去1~2周 自己所看到外文内容:https://twitter.com/unity3d 和各种其他博客来源吧 1、Unity的Android音频延迟在2019.1.0 中改进 ... 文章作者因为这个延迟问题,弄了一个,正是基于Op...
  • Unity_C#判断字符串为的几种用法

    千次阅读 2018-11-16 11:16:28
    转载自CSDN_FreeSon; ... 字符串判断:string在C#中是一个引用类型,但其又具有一定的...我们在使用string时,往往会把“变量值为的字符串对象”和“变量值为字符的字符串对象”搞混。  因为string是我们开发...
  • unity3d制作背包系统(1)--物品

    千次阅读 2019-04-26 19:23:39
    unity3d制作背包系统(1)–物品 序言 在这篇文章写下的时候,距离我开始设计这个背包系统的时间已经过去将近一年了。这个背包系统是属于我的一个正在开发的小游戏的,之所以当时没有写下这篇文章而是现在来完成的...
  • Unity3D游戏-愤怒的小鸟游戏源码和教程(一) Unity愤怒的小鸟游戏教程 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人! Spring Joint 2D : 是Unity提供的一个弹簧关节组件,可通过AddComponent...
  • Unity3D】中的引用 Null Reference Exception
  • 我们的脚本代码里经常会需要访问gameObject引用或者某个组件的引用,最好的方式当然是在脚本Awake的时候就把这些可能访问的东西都缓存下来;如果需要访问临时gameObject实例的某属性或者临时某组件的gameObject实例...
  • [Unity 3D] Unity 3D 性能优化 (一)

    千次阅读 2013-09-14 17:51:11
    听到过很多用Unity 3D开发游戏的程序员抱怨引擎效率太低,资源占用太高,包括我自己在以往项目的开发中也头疼过。最近终于有了空闲,可以仔细的研究一下该如何优化Unity 3D下的游戏性能。 模型贴图等美术资源的优化...
1 2 3 4 5 ... 8
收藏数 142
精华内容 56
关键字:

unity3d判空方法