• Unity面向组件开发

    2018-05-23 16:17:53
    Unity面向组件开发 ##1、Unity组件开发 ++1.1、工程与应用程序 ++++新创建的Unity工程,在其目录文件夹中包含4个文件夹。 -- Assets: 里面存放的是项目所需要的资源; -- Library: 里面存放的是所需要的库文件; ...

    Unity面向组件开发

    ##1Unity组件开发

    ++1.1、工程与应用程序

    ++++新创建的Unity工程,在其目录文件夹中包含4个文件夹。

    -- Assets: 里面存放的是项目所需要的资源;

    -- Library: 里面存放的是所需要的库文件;

    -- ProjectSettings: 里面存放的是工程设置文件;

    -- Temp: 里面存放的是临时文件;

    ++1.2Unity工程开发框架

    ++++工程,场景,游戏对象和组件的关系

    -- 一个工程里面有多个场景,相当于一个游戏有多个关卡;

    -- 一个场景里面有多个游戏对象,相当于游戏中的不同元素;

    -- 每个游戏对象又有一个或者多个组件,游戏对象想要实现什么样的功能只需要加上相对应的组件即可;


    ++1.3Unity面向组件开发思想

    ++++Unity面向组件开发,游戏物体想要实现什么样的功能,只需要添加相对应的组件即可,此时会在Inspector面板中显示出来,一些属性值可以可视化的更改。

    -- Transform组件,决定物体的位置,旋转和缩放。

    -- Mesh Filter组件,选择网格。

    -- Box Collider组件,用来给物体添加碰撞器。

    -- Mesh Renderer组件,可以给物体添加材质,纹理以及渲染的方式。


    ++1.4、脚本组件的使用

    ++++脚本组件开发工具

    -- Unity自带脚本编辑器,创建Mono应用程序,适用于LinuxMac OS XWindows的继承开发环境,支持C#BOOJavaScript等高级编程语言。

    -- 微软公司的开发工具包,包括了整个软件生命周期中需要的大部分工具,如团队开发工具、集成开发环境等等。

    -- Unity中通过菜单设置修改默认的脚本编辑器: 【Edit=>Preferences=>External Tools=>External Script Editor

    ++++脚本组件

       -- 脚本是一种特殊的组件,它用于添加到游戏对象上以实现用户自定义的一些功能。

    ++++脚本的创建

    -- Project视窗Asset文件夹中点击右键,创建C#脚本,然后把创建的脚本拖到游戏物体上即可。

    ++++脚本的使用

    -- 双击创建的脚本组件,即可打开脚本

    using UnityEngine;

    using System.Collections;

     

    pulbic class CubeScript : MonoBehaviour{

        //注:类名与脚本组件名一致,并自动的继承MonoBehaviour类,类名与脚本名不一样会出错。

    }


    ++2Unity脚本组件

    ++2.1Unity脚本类

    ++++Unity中的常用脚本类就可以简单的分成如下四大类:

    Unity脚本类  --宏观控制类

                 -- 游戏对象类

                 -- 组件类

                 -- 资源类

    ++++宏观控制类: 主要作用是针对Unity程序中的某一方面进行宏观控制。包括应用程序类(Application)、输入类(Input)、图形输出类(GUI)、物理引擎类(Physics)、资源类(Resources)、时间类(Time)等。

    ++++游戏对象(GameObject)类: 表示当前脚本挂在的游戏对象。

    ++++组件(Component)类: 脚本开发中的组件类往往可以和图形界面界面中的检视面板对应起来。 每一个游戏对象的细节设置与操控都需要借助组件类来完成。

    ++++资源类: 资源一般都是在图形界面导入进来之后直接使用。

    ++2.2MonoBehaviour

    ++++Unity脚本组件必须继承MonoBehaviour类。

    ++++继承自MonoBehaviour的脚本组件可以自动调用其封装好了的回调方法。

    ++2.3、脚本生命周期


    ++MonoBehaviour类常用方法

    ++++初始阶段:Awake()OnEnable()Start()

    ++++物理阶段:FixedUpdate()

    ++++游戏逻辑:Update()LateUpdate()

    ++++场景渲染:OnGUI()OnBecameVisible()OnBecameInvisible()

    ++++结束阶段:OnDisable()OnDestroy()OnApplicationQuit()

     

    ++++初始阶段

    -- Awake() 唤醒: 当物体载入时立即调用1次,常用于在游戏开始前进行初始化,可以判断当满足某种条件执行此脚本this.enable=true

    -- OnEnable() 当可用: 每当脚本对象启用时调用。

    -- Start()  开始:物体载入且脚本对象启用时被调用1次。常用于数据或游戏逻辑初始化,执行时机晚于Awake

     

    ++++物理阶段

    -- FixedUpdate() 固定更新: 脚本启用后,固定时间被调用,适用于对游戏对象做物理操作,例如移动等。

          设置更新频率: Edit=>Project Setting=>Time=>Fixed Timestep】值,默认为0.02s


    ++++游戏逻辑

    --Update()更新: 脚本启用后,每次渲染场景时调用,频率与设备性能及渲染量有关。

    --LateUpdate()延迟更新: 在Update函数被调用后执行,适用于跟随逻辑。

     

    ++++场景渲染

    -- OnGUI() 渲染: 渲染和处理GUI事件时调用。

    -- OnBecameVisible() 当可见: 当Mesh Renderer在任何相机上可见时调用。

    -- OnBecameInvisible() 当不可见: 当Mesh Renderer在任何相机上不可见时调用。

    ++++结束阶段

    -- OnDisable() 当不可用:对象变为不可用和附属游戏对象非激活状态时此函数被调用。

    -- OnDestroy() 当销毁: 当脚本销毁或附属的游戏对象被销毁时调用。

    -- OnApplicationQuit() 当程序结束: 应用程序退出时被调用。


    ++2.4、常用调试方法

    ++++在学习或使用Unity时经常会调试,调试的方式大约有两种:

    -- 第一种: 在可能出错的行添加断点

    --第二种:选择打印消息的方式

      常用打印消息的方式:一种是print,一种是Debug.Log

          -- print方法:它是MonoBehaviour类的成员。

          -- Debug方法: 则是一个独立、密闭的类。


    ##3、常用类

    APIApplication Programming Interface)应用程序编程接口,是一些预先定义的函数。Unity引擎提供了丰富的组件和类库,为开发者提供了非常大的便利,熟练掌握和使用这些API对于游戏开发效率提高很重要。

    ++3.1Component

    ++++gameObject :组件附加的游戏对象。组件总是被附加到游戏对象上。

    ++++transform :附加到此游戏对象Transform组件(如果没有则为空)。

    ++++tag :此游戏对象的标签。

    ++++collider :附加到此游戏对象的Collider(如无附加则为空)。

    ++++renderer :附加到此游戏对象Renderer组件(如果没有则为空)。

    ++++rigidbody :附加到此游戏对象Rigidbody组件(如果没有则为空)。

    ++++GetComponent :如果游戏对象有附加type类型的组件,则返回,如果没有则为空。

    ++++GetComponentInChildren :返回此游戏对象上type类型的组件或任何它的子对象,使用深度首先搜索。

    ++++GetComponents :返回此对象type类型的所有组件。

    ++++GetComponentsInChildren :返回此游戏对象与其子对象所有type类型的组件。

    ++3.2GameObject


    ++++脚本中得到游戏对象

    -- 通过tag得到游戏物体

      static GameObject FindWithTag(string tag)

      => GameObject.FindWithTag(“Player”);

    -- 通过name得到游戏物体

      static GameObject Find(stirng name)

      => GameObject.Find(“char_ethan”);

    ++++常用属性和方法

    -- tag :可读写属性,游戏物体的tag

    -- name :可读写属性,游戏物体的name

    -- FindGameObjectsWithTag(string tag) :静态方法,返回所有tag标识的物体,返回值是个数组。

    -- T GetComponent<T>() :泛型实例方法,得到T类型的组件(强烈建议使用)。

    -- SetActive(bool value) :实例方法,设置游戏物体是否是活动的。

    -- FindWithTag(string tag) :静态方法,得到tag标识的游戏物体。


    ++3.3Transform


    ++++Transorm组件作用:

    --1、负责游戏对象的变换(位置,旋转和缩放)

    --2、维持父子关系

    ++++常用属性:

    --position :世界坐标系中transform的位置

    --localPosition :相对于父物体的位置

    --eulerAngles :欧拉角,旋转的角度

    --rotation :世界坐标系中变换的四元数

    --parent :物体父物体的Transform组件

    --root :物体最高层次父物体的Transform组件

    ++++常用方法:

    -- void Translate(Vector3 translation) :使当前对象朝translation

    -- void Rotate(Vector3 eulerAngles) :按给定的欧拉角进行旋转

    -- void RotateAround(Vector3 point, Vector3 axis, float angle) :绕point点沿axis轴旋转angle

    -- Transform Find(string name) :通过名字查找子物体

    -- void LookAt(Transform target) :使物体朝向target

    ++3.4Vector3

    ++++点乘

    又称“点积”或“内积”。

    公式:各分量乘积和 [x1,y1,z1]*[x2,y2,z2] = x1x2 + y1y2 + z1z2

    几何意义: a*b = |a|*|b|cos<a,b> 两个向量的单位向量相乘后再乘以二者夹角的余弦值。

    APIfloat dot = Vector3.Dot(Va, Vb);

    ++++点乘应用

    对于标准化过的向量,点乘结果等于两向量夹角的余弦值。

    应用:计算两向量夹角

    float dot = Vector3.Dot(a.normalized, b.normalized);

    float angle = Mathf.Acos(dot)*Mathf.Rad2Deg;

    ++++叉乘

    又称“叉积”或“外积”。

    公式:

    各分量乘积和 [x1,y1,z1]*[x2,y2,z2] = [y1*z1 - z1*y2,  z1*x2 - x1*z2,  x1*y2-y1*x2]

    几何意义:结果为两个向量所组成面的垂直向量,模长为两向量模长积乘再乘夹角的正弦值。

    脚本: Vector vector = Vector3.Cross(a, b);

    ++++叉乘应用

    创建垂直于平面的向量。

    判断两条向量相对位置。

    ++++Vector3 是封装了向量运算相关变量和方法的结构体。

    --normalized :标准化向量,方向不变,长度为1(只读)

    --magnitude :向量长度(只读)

    --sqrMagnitude :向量长度平方(只读)

    --forward Vector(0,0,1)的简码,Z轴正方向

    --up Vector(0,1,0)的简码,Y轴正方向

    --right Vector(1,0,0)的简码,X轴正方向

    --void Normalize() :标准化向量,长度为1

    --static Vector3 Lerp(Vector3 from, Vector3 to, float t) :两个向量之间的线性差值

    --static float Angle(Vector3 from, Vector3 to) :两个向量之间的夹角

    --static float Distance(Vector3 a, Vector3 b) :两向量之间的距离


    ++3.5Quaternion

    ++++identity :该四元数无旋转,常用在代码创建对象

    ++++LookRotation :创建一个旋转,沿着forward(z)并且头部沿着upwards(y)的约束注释

    ++++四元数左乘向量,表示将该向量按照四元数表示的角度旋转。

    ++++例如: Vector3 point = new Vector3(0,0,10);

               Vector3 newPoint = Quaternion.Euler(0,30,0)*point;

    ++++避免万向节死锁:

    --this.transform.rotation *= Quaternion.Euler(0,1,0);  //使物体沿自身Y轴旋转

    --this.transform.Rotate(Vector3 eulerAngles);  //内部就是使用四元数相乘实现


    ++3.6Time

    ++++time :从游戏开始到现在所用的时间(只读)

    ++++deltaTime :获取上一次Update()方法执行的时间到本次执行Update()方法时间的差值

    ++++fixedDeltaTime :在物理和其他固定帧速率进行更新上一帧所消耗的时间,以秒计算

    ++++timeScale :表示事件缩放,正常时间为1


    ++3.7Mathf

    ++++C#脚本中,Mathf是封装了常见数学计算方法的结构体。

    --Lerp :两个浮点数之间进行插值

    --Clamp :返回一个限制值

    --Sin :计算并返回浮点型的正弦值

    --Cos :计算并返回浮点型的余弦值

    --Abs :计算并返回指定参数的绝对值

    --Max :返回两个值之中最大的值

    --Min :返回两个值之中最小的值

    --Sqr :返回平方根

    --PI :圆周率


    ++拓展1:《Translate

    ++++1Space.self: [单位向量= 三维坐标]

    -- transform.Translate(transform.forward * Time.deltaTime);

      移动方向为(两向量相加):自身在世界坐标系的方向(向量)+自身的前方(向量)

    -- transform.Translate(transform.position * Time.deltaTime);

      移动方向为(单向量):自身在世界坐标系的方向向量

    -- transform.Translate(target.forward * Time.deltaTime);

      移动方向为(单向量):目标的前方

    -- transform.Translate(target.position * Time.deltaTime);

      移动方向为(单向量):目标在世界坐标系的方向向量

    ++++2Space.world

    同理


    ++拓展2:《理解Gameobject, gameObject, Transform, transform的区别和关联》

    ++++1GameObjectgameObject

    --GameObject是一个类型,所有的游戏物件都是这个类型的对象。

    --gameObject是一个对象,就跟java里面的this一样,指的是这个脚本所附着的游戏物件

    --示例

      public class ShowSliderValue:MonoBehaviour{

          private GameObject obje;  //定义GameObject类型的指针

          void Start(){

              Text lal = gameObject.GetComponent<Text>(); //获取到Text组件

              Debug.Log(Text+lal.text); //打印获取到组件中的text属性

    }

    }

    --Text lal = gameObject.GetComponent<Text>()中不使用gameObject,直接通过GetComponent<Text>(),也是可以的。


    ++++2Transformtransform

    --Transform是一个类,用来描述物体的位置,大小,选择等等信息。

    --transformTransform类的对象,依附于每一个物体。也是当前游戏对象的一个组件(每个对象都会有这个组件)

    ++++transformgameObject

    --1>二者的含义

       ---transform: 当前游戏对象的transform组件

       ---gameObject: 当前游戏对象的实例

    --2>二者的联系和区别

       ---unity中每个游戏对象都是一个gameObjectmonodevelop中的gameObject就代表着本脚本所依附的对象。 每个gameObject都包含各种各种的组件,但从这点可以看出transformgameObject的一个组件,控制着gameObject的位置,缩放和旋转,而且每个gemeObject都有而且必有一个transform组件。

       ---gameObject.Find()用来获取场景中那个我们需要查找的对象(object),而transform.Find()方法则是获取当前对象的子对象下我们需要获取的目标对象位置信息。

       ---注意:在update()中尽量不适用find()方法,影响性能。

    --3>gameObject.transformtransform.gameObject

       ---gameObject.transform,是获取当前游戏对象的transform组件。

         所以在start函数中gameObject.transformthis.transform,指向的都是同一个对象。 即:gameObject.transform == this.transform == transform

       ---transform.gameObject:获取当前transform组件所在的gameObject

         所以在start()函数中transform.gameObject == this.gameObject == gameObject

       ---所以他们可以无限的引用下去:

        gameObject.transform == this.transform == gameObject.transform.gameObject.transform == transform.gameObject.transform

           ---示例:

              public class ShowSliderValue:MonoBehavior{

                  private GameObject obje;  //定义GameObject类型的指针

                  private Transform trans;    //定义Transform类型指针

                  void Start(){

                      Debug.Log(gameObject.name:, + gameObject.name);

                      Debug.Log(gameObject.transform.gameObject.name, + gameObject.transform.gameObject.name);

                      Debug.Log(ThisGame.name: + this.gameObject.name);

    }

    }

    输出: gameObject.name: Label Percent

           gameObject.transform.gameObject.name: Label Percent

           ThisGame.name: Label Percent


    ++拓展3:《对Vector3.Lerp插值的理解》

    在做游戏时会发现有些跟随动作不够圆滑或者需要一个缓冲的效果,这时,一般会考虑到插值。(比如摄像机跟随主角)

    ++++插值是数学上的一个概念,在这里用公式表示就是: from + (to - from)*t;这也就是Lerp的返回值(用这个公式分别算出x,y,z)。

    static function Lerp(from:Vector3, to: Vector3, t:float):Vector3

      -- from 是起始位置,

      -- to 是目标位置,

      -- t fromto之间插值。

     

    ++++举例:

    public class test:MonoBehaviour{

        Vector3 start = new Vector3(1, 1, 1);

        Vector3 end = new Vector3(2, 2, 2);

        Vector3 result;

     

        void Update(){

            result = Vector3.Lerp(start, end, 0.5f);

            Debug.log(result.ToString());

    }

    }

    输出: (1.5, 1.5, 1.5)

     

    ++++看一个官方的例子:

    //1秒时间动画位置移动从from开始到to结束。

    public class example:MonoBehaviour{

        public Transform start;

        public Transform end;

        void Update(){

            transform.position = Vector3.Lerp(start.position, end.postion, Time.time);

    }

    }

    位置移动从start开始到end结束,这好理解,但是为什么是1秒呢?

    Time.time是从0开始随时间增加的。

    (上一个例子t是固定的值,返回一个固定的向量)

    本例中t是变量,在不断增加。

    -- Time.time=0时,transform.position = start.position,位置没有变化;

    -- Time.time0趋向于1时,transform.position不断接近start.position,该脚本是挂在start物体上的,所以start会不断靠近end

    -- Time.time>1的时候,会怎么样呢?(这个是不会发生的)

        ---由上面的公司 from+(to-from)*t可知,当t=1时,to-from=0,此时t就无效了。

    --1是从静态角度看,例2是从动态角度看(两个变量,一个是时间在变化,一个是位置在变化)

    --??2中如果不是Time.time,而是0.5,会怎么样?(只看一个变量)

       ---A物体会不断以0.5的比例无限接近于B

     

    ++++看一下官方第二个例子

    //像弹簧一样跟随目标物体

    public class example:MonoBehaviour{

        public Transform target;

        public float smooth = 5.0F;

        void Update(){

            transform.position =Vector3.Lerp(transform.position, target.position,Time.deltaTime*smooth);

        }

    }


    ++拓展4:《摄像机跟随之Vector3.Lerp(start,end,t)方法》

    ++++插值是数学上的一个概念,在这里用公式表示就是: from+(to-from)*t;这也就是Lerp的返回值(用这个公式分别算出x,y,z

    static function Lerp(from:Vector3, to:Vector3, t:float) :Vector3

    from是起始的位置,to是目标位置,按照数字tfromto之间插值

     

    using UnityEngine;

    using Systme.Collections;

     

    public class ThirdPersonCam:MonoBehaviour{

        public Transform follow;  //摄像机所跟随的对象

        public float distanceAway; //摄像机在水平方向与对象的距离

        public float distanceUp;  //摄像机在垂直方向与对象的距离

        public float smooth;  //过渡速度

        private Vector3 targetPosition;  //摄像机的目标速度

     

        //LateUpdate中执行摄像机操作,确保在对象的操作完成之后

        void LateUpdate(){

            //计算目标距离

            targetPosition = follow.position +Vector3.up*distanceUp - follow.forward*distanceAway;

            //对当前位置进行插值计算

            transform.position = Vector3.Lerp(transform.position, targetPosition,Time.deltaTime*smooth);

            //使摄像机观察对象

            transform.LookAt(follow);

        }

    }


    ++拓展5:《Vector3.Lerp线性插值原理介绍》

    ++++向量from和向量toxy平面上,其实这并不影响讲解插值原理。

    ++++图中可以看出当t=0.5f时,插值向量就是中间那个向量,其x轴分量的计算图中已经给出了,y轴也同理,z轴也一样。

    ++++下面分析这个函数:

    public static Vector3 Lerp(Vector3 a, Vector3 b, float t);

    其中a就是图中的from向量,b就是to向量。

    t是夹在[0 ... 1]之间,

    --t=0时,返回from

    --t=1时,返回to

    --t=0.5,返回fromto的平均数。

       --具体实现代码如下:

    /*

    Summary:两个向量之间的线性插值

    Param: from,向量fromto,向量tot

    */

    public static Vector3D Lerp(Vector3D from, Vector3D to, float t){

        if(t < 0){

            return from;

        }else if(t >= 1){

        returnto;

        }

        returnt*to + (1-t)*from

    }

    ++++线性插值比Slerp球形插值简单的多。


    ++拓展6:《deltaTime

    ++++deltaTime是你这一帧到下一帧经历的时间。

    ++++假设一秒走10帧,每帧不太稳定,间隔时间不一样,用t0, t1, t2, ... t9来表示,他们满足t0 + t1 + t2 + ... + t9 = 1

    ++++现在你定义了一个速度V=5,意思是想要1秒走5米,现在设每帧所走的路程是s0, s2, s2, ... ,s9; 满足s0=V*t0, s1=V*t1, s2=V*t2, ..., s9=V*t9

    那么看看1秒走了多少路程:S = s0 + s1 + s2 + ... + s9


    ++拓展7:《为何需要Time.deltaTime》(其实就是一个补偿)

    ++++先说下Unity3D脚本中常用的两个方法:

    --Update() :每帧被调用一次

    --FixedUpdate :每隔Time.fixedDeltaTime被调用一次。

    Time.fixedDeltaTime默认是0.02s

      (可以通过【Edit=>ProjectSettings=>Time】来设置)

    --在控制游戏逻辑的过程中,一般是需要按照每帧去处理的(使用Update()),而物理相关的处理,则需要根据时间的变化去处理(使用FixedUpdate()

    ++++当我们在Update()中,希望通过每隔一段时间去执行一些逻辑(比如最常见的修改GameObjectTransform),就需要使用Time.deltaTime来达到效果了。

    -- 根本原因,就是帧率在不断变化,Update()被调用的时间并不是线性的。

      |Frame_1     |Frame_2   |Frame_3          |Frame_4    |Frame_5  |

    -- 如果我们希望使GameObject每隔一段时间沿X轴正方向移动1个单位,可以在FixedUpdate()中这样写:

       transform.Translate(Vector3.right);

    -- 如果希望通过Update()来实现,把这句写到Update()中是不合适的,你会看到GameObject移动起来出现卡段。解决方法,是给移动的距离乘以Time.deltaTime:

       transform.Translate(Vector3.right * Time.deltaTime);

    -- 为什么乘以Time.deltaTime之后就好了呢?

      ---TransformTranslate方法接受的参数,实际上是一个唯一,而不是速度。

      ---FixedUpdate()的调用间接是: 0.02s=t1=t2=t3=t4,所有实际上,位移=速度*时间,transform.Translate(Vector3.right) ==>transform.Translate(Vector3.right*1)

        ----1就代表了单位时间Time.fixedDeltaTime

      ---因为Update()并不是按照单位时间被调用的,所以要乘以每次的“帧间时间”,而这个时间就是Time.deltaTime。(这样的操作相当于一个“补偿”,将每次帧率的变化,通过时间的变化同步体现到执行逻辑上。)

    ++++还有一个问题,就是乘以Time.deltaTime之后速度变慢。

    --其实很好解决,在FixedUpdate()中,我们每次的执行间隔是0.02s,而单位时间体现的是1;同样我们在Update()中,执行间隔是Time.deltaTime,为了与FixedUpdate一致,时间单位也需要是1

      ---所以直接乘以FixedUpdate中真实时间和单位时间的比例:(1/0.02=50)即可,让Update中的时间也变成单位时间。

    ++++Update()中需要依赖固定时间去执行的逻辑,都可以通过Time.deltaTime来进行“补偿”。道理是一样的。


    ++拓展8:《四元数(Quaternion)和旋转》

    ++++旋转,应该是三种坐标变换:缩放、旋转和平移,中最复杂的一种了。

    ++++有一种旋转的表示方法叫四元数。(我们熟悉的另外两种旋转和表示方法:矩阵旋转和欧拉旋转。)

    ++++四元数本质上是一种高阶复数,是一个四维空间,相对于复数的二维空间。(复数由实部和虚部组成,即x=a+bii是虚数部分)

    ++++Unity里,transform组件有一个变量名为rotation,它的类型就是四元数。(实际上,四元数的x,y,zR的三个值从直观上来讲没什么关系,当然会存在一个表达式可以转换)

    ++++三种旋转方式(矩阵旋转、欧拉旋转、四元数旋转)的优缺点:

    --矩阵旋转

      ---优点:

        ----旋转轴可以是任意向量;

      ---缺点:

        ----旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素。

        ----而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费。

    --欧拉旋转

      ---优点:

        ----很容易理解,形象直观;

        ----表示更方便,只需要3个值(分别对应x,y,z轴的旋转角度);(?它还是转换到了33*3的矩阵做变换,效率不如四元数)

      ---缺点:

        ----要按照一个固定的坐标轴的顺序旋转的,因此不同的顺序会造成不同的结果;

        ----会造成万向节锁(Gimbal Lock)的现象。这种现象的发生就是由于上述固定坐标轴旋转顺序造成的。理论上,欧拉旋转可以靠这种顺序让一个物体指到任何一个想要的方向,但如果在旋转中不幸让某些坐标轴重合了就会发生万向节锁,这时就会丢失一个方向上的旋转能力,也就是说在这种状态下我们无论怎么旋转(当然还是要原先的顺序)都不可能得到某些想要的旋转效果,除非我们打破原先的旋转顺序或者同时旋转3个坐标轴。

        ----由于万向节锁的存在,欧拉旋转无法实现球面平滑插值;

    --四元数旋转

      ---优点:

        ----可以避免万向节锁现象;

        ----只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;

        ----可以提供平滑插值;

       ---缺点:

         ----比欧拉旋转稍微复杂了一点点,因为多了一个维度;

         ----理解更困难,不直观。


    ++拓展9:《unity用点乘和叉乘来判断物体与人物的相对位置》

    ++++用点乘来判断物体是在人物的前方,还是后方。

    ++++用叉乘来判断是在人物的左手边,还是右手边。

     

    ++++示例代码

    using UnityEngine;

    using System.Collections;

    using UnityEngine.UI;

     

    public class NewBehaviourScript : MonoBehaviour{

        public Text textA;

        public Text textB;

        public Text textLR;

        public Text textFB;

        public GameObject targetGameObject;

     

        void Start(){

        }

     

        //Update is called once per frame

        void Update(){

        }

     

        void OnGUI(){

            Vector3 vectorTarget = targetGameObject.transform.position - transform.position;

            vectorTarget = new Vector3(vectorTarget.x, 0, vectorTarget.z);

            Vector3 vectorForward = transform.forward;

            float dotValue = Vector3.Dot(vectorForward.normalized, vectorTarget.normalized);

            float angle = Mathf.Acos(dotValue)*Mathf.Rad2Deg;

            textA.text =angle: + angle + dotValue: + dotValue;

     

            Vector3 crossValue = Vector3.Cross(vectorForward, vectorTarge);

            textB.text =crossValue: + crossValue;

     

            if(crossValue.y > 0){

                textLR.text =;

            }else{

                textLR.text =;

            }

     

            if(dotValue > 0){

                textFB.text =;

            }else{

                textFB.text =;

            }

        }

     

        public Slider slider;

        public void ownAngleChange(){

            float angle = slider.value;

            transform.rotation = Quaternion.Euler(0, angle, 0);

        }

    }



    ##4、预设体

    ++4.1、预设体相关概念

    ++++预设体是一个游戏对象及其组件的集合,目的是使游戏对象及资源能够被重复使用,相同的游戏对象可以通过一个预设体来创建,此过程可以理解为实例化。

    ++++把一个游戏对象从层级视窗拖到工程视窗后就会生成一个预设体。


    ++4.2、预设体实例化

    ++++把预设体直接拖到层级视窗上,就会实例化一个游戏对象。

    ++++对预设体做出修改后,其所实例化的对象也会做出相应的改动。


    ++++Prefab】通过预设体创建的游戏对象会在Inspector视窗出现Prefab

    ++++Select】点击Select可以选中创建该物体的预设体。

    ++++Revert】更改实例化后的游戏物体,点击Revert,会取消更改。

    ++++Apply】将该对象的信息同步到预设体,使用该预设体实例化的其他游戏对象也随之改变。

    ++++预设体的使用:

        static Object Instantiate(Object original, Vector3 position, Quaternion rotation);


    ++拓展11:《多种移动方式参考》

    ++++1transform.position

    transform.position += Vector3.forward * Time.deltaTime * 5;

     

    ++++2Translate:

        transform.Translate(Vector3.forward * 5 * Time.deltaTime, target.transform);

     

    ++++3Lerp:

        transform.position = Vector3.Lerp(transform.position, target.position, 0.5f*Time.deltaTime);

     

    ++++4、获取输入设备的横轴、纵轴:

    float hor = Input.GetAxis(Horizontal);

    float var = Input.GetAxis(Vertical);

    transform.position += new Vector3(hor, 0, ver) * Time.deltaTime * 5f;


    ++++5、刚体:

    float hor = Input.GetAxis(Horizontal);

    float ver = Input.GetAxis(Vertical);

    rig.AddForce(new Vector3(hor, 0, ver) * 5f * Time.deltaTime);


    ++++6Vector3.MoveTowards();

    transform.position = Vector3.MoveTowards(transform.position, target.position, 5f * Time.deltaTime);

     

    ++++7SmoothDamp();

    Mathf.SmootDamp();

    //角色控制器;




    #立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    ++立钻哥哥推荐的拓展学习链接(Link_Url

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    ++++Unity引擎基础https://blog.csdn.net/vrunsoftyanlz/article/details/78881685

    ++++Unity面向组件开发https://blog.csdn.net/vrunsoftyanlz/article/details/78881752

    ++++Unity物理系统https://blog.csdn.net/vrunsoftyanlz/article/details/78881879

    ++++Unity2D平台开发https://blog.csdn.net/vrunsoftyanlz/article/details/78882034

    ++++UGUI基础https://blog.csdn.net/vrunsoftyanlz/article/details/78884693

    ++++UGUI进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78884882

    ++++UGUI综合https://blog.csdn.net/vrunsoftyanlz/article/details/78885013

    ++++Unity动画系统基础https://blog.csdn.net/vrunsoftyanlz/article/details/78886068

    ++++Unity动画系统进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78886198

    ++++Navigation导航系统https://blog.csdn.net/vrunsoftyanlz/article/details/78886281

    ++++Unity特效渲染https://blog.csdn.net/vrunsoftyanlz/article/details/78886403

    ++++Unity数据存储https://blog.csdn.net/vrunsoftyanlz/article/details/79251273

    ++++Unity中Sqlite数据库https://blog.csdn.net/vrunsoftyanlz/article/details/79254162

    ++++WWW类和协程https://blog.csdn.net/vrunsoftyanlz/article/details/79254559

    ++++Unity网络https://blog.csdn.net/vrunsoftyanlz/article/details/79254902

    ++++C#事件https://blog.csdn.net/vrunsoftyanlz/article/details/78631267

    ++++C#委托https://blog.csdn.net/vrunsoftyanlz/article/details/78631183

    ++++C#集合https://blog.csdn.net/vrunsoftyanlz/article/details/78631175

    ++++C#泛型https://blog.csdn.net/vrunsoftyanlz/article/details/78631141

    ++++C#接口https://blog.csdn.net/vrunsoftyanlz/article/details/78631122

    ++++C#静态类https://blog.csdn.net/vrunsoftyanlz/article/details/78630979

    ++++C#中System.String类https://blog.csdn.net/vrunsoftyanlz/article/details/78630945

    ++++C#数据类型https://blog.csdn.net/vrunsoftyanlz/article/details/78630913

    ++++Unity3D默认的快捷键https://blog.csdn.net/vrunsoftyanlz/article/details/78630838

    ++++游戏相关缩写https://blog.csdn.net/vrunsoftyanlz/article/details/78630687

    ++++设计模式简单整理https://blog.csdn.net/vrunsoftyanlz/article/details/79839641

    ++++U3D小项目参考https://blog.csdn.net/vrunsoftyanlz/article/details/80141811

    ++++UML类图https://blog.csdn.net/vrunsoftyanlz/article/details/80289461

    ++++Unity知识点0001https://blog.csdn.net/vrunsoftyanlz/article/details/80302012

    ++++U3D_Shader编程(第一篇:快速入门篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372071

    ++++U3D_Shader编程(第二篇:基础夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372628

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/


    --_--VRunSoft : lovezuanzuan--_--

    展开全文
  • 如果你接触过《设计模式》、软件架构的编程思想,就会知道优秀的设计准则:“组合优于继承的”。 这句话很简短,但开始学习OOP的时候,真切的是—-不太好理解(以我个人当初学习为例)。

    如果你接触过《设计模式》、软件架构的编程思想,就会知道优秀的设计准则:“组合优于继承的”。

    这句话很简短,但开始学习OOP的时候,真切的是—-不太好理解(以我个人当初学习为例)。

     

    OOP的继承思想

    image

    在设计主角(Player)的时候,为了能够复用A、B、C的功能,我开始把A、B、C按照继承来写,多了一些Virutal\Override\Protected等修饰符,功能没有任何问题,就是有些别扭。如Start、Update方法,只能在A中采用模板方法处理,万一B、C、Player中直接用了Start、Update方法,会导致奇奇怪怪的问题;同时在继承的基类中,无形之间多了一些包袱,对于Player不得不使用A、B、C的函数、变量(非private的)。

    整个关系变为了:

    • Player is a A
    • Player is a B
    • Player is a C

    心理上疙疙瘩瘩的,总觉得有点别扭。

     

    OOP的组合思想

    image

    以前使用组合思想较多的是构建树、树叶模型,例如电信中的网元模型。这种思想,属于Unity 3D的核心思想–组件。在Player、A、B、C中可自由使用Start、Update函数(请不考虑执行顺序,脚本组件的先后顺序外部可调整,但是意义不大),最重要的是,关系理顺了—主角变成更积极、主动。

    • Player have a A
    • Player have a B
    • Player have a C
    • 在Unity 3D中,可复用的几乎全部为封装为了组件,eg: transform、rigibody、render、camera、***.cs脚本;为了配合方便的使用非内置的组件,可使用gameObject.AddComponent<T>()、gameObject.GetComponent<T>()来添加、获得组件(一般是自定义的脚本)。

     

    这里我举一个实际的例子,在《Unity 3D手机游戏开发》第二版的“太空射击游戏”中,有一个需求,需要给游戏中可复用的GameObject添加自动销毁的功能(通过时间计时器,或者触发器添加),代码很简单,不到100行,要添加的GameObject有5、6个,虽然工作量不大,但总不能每个都拷贝一遍代码吧。

    开始我是按照OOP继承做的,

    image

     

    看了几天,很不爽,后来重构为如下图:

    image

    这样使得自动销毁组件的功能发挥的更加灵活、机动,即不必拘泥于静态的继承思想来实现。

    从这个重构过程中,我学到Unity 3D组件思想的闪闪发光……

    附录:完整的自动销毁组件代码:

    public class AutoDestoryComponent : MonoBehaviour 

        #region ICanCache 
        public ParticleSystem[] m_pss = null; 
        public int m_life = 1; //3条命 
        public float m_AutoDeadTime = 3;//3s自动销毁

        private int m_life_Base = 3; //3条命【恢复用】 
        private float m_AutoDeadTime_Base = 3;//3s自动销毁【恢复用】【-1:表示不自动销毁,如Enemy】

        void Update() 
        { 
            //需要自动销毁 
            if (m_AutoDeadTime_Base >= 0) 
            { 
                m_AutoDeadTime -= Time.deltaTime;

                if (m_AutoDeadTime <= 0) 
                { 
                    InnerDead(); 
                    return; 
                } 
            }

            if (m_life <= 0) 
            { 
                InnerDead(); 
            } 
        }

        /// <summary> 
        /// 设置自动销毁数据 
        /// </summary> 
        /// <param name="life_base">默认生命值</param> 
        /// <param name="autoDeadTime_base">-1不自动销毁;其他数据代表销毁时间(单位s)</param> 
        public void SetBasePara(int life_base = 1, float autoDeadTime_base = -1) 
        { 
            m_AutoDeadTime = m_AutoDeadTime_Base = autoDeadTime_base; 
            m_life = m_life_Base = life_base; 
        }

        //是否启用 
        public bool IsUse { get; set; } 
        //死后位置 
        public Vector3 DeathPosition 
        { 
            get 
            { 
                return new Vector3(2000, 2000, 2000); 
            } 
        }

        //复活 
        public void Init(Vector3 position, Quaternion rotation) 
        { 
            transform.gameObject.SetActive(true); 
            transform.position = position; 
            transform.rotation = rotation; 
            IsUse = true; 
            foreach (ParticleSystem item in m_pss) 
            { 
                item.Play(true); 
            }

            //有些绕 
            m_life = m_life_Base; 
            m_AutoDeadTime = m_AutoDeadTime_Base; 
        }

        private void InnerDead() 
        { 
            IsUse = false; 
            transform.position = DeathPosition; 
            foreach (ParticleSystem item in m_pss) 
            { 
                item.Stop(true); 
            }

            this.gameObject.SetActive(false); 
        } 
        #endregion 
    }

     

     

    包括系统自带的Audio、Transform、Camera、Image、Button等等。GameObject是一个容器,没有Image的GameObject,只要新建一个空的GameObject,添加Image Component极为Image GameObject对象的。

    也即是在Unity3D中,很少用GameObject.ID的概念,而是用GameObject.Tag、GameObject.name来区分不同的GameObject,且Tag、name不唯一。

     

    结论:在Unity3D中,万事万物都是Component。

    展开全文
  • 作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity中创建和使用Shader,为后面...



    本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/40723789

    作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442

    邮箱: happylifemxy@163.com

     

     

    作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分为系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity中创建和使用Shader,为后面专注于介绍如何在Unity中进行Shader编程打好了基础。

     

    因为后面推出的系列文章会着重介绍各种Shader的写法和实现,不会再具体讲解如何创建场景和写出Shader代码后如何使用,相信这篇文章作为本系列的开篇,发表出来肯定还是会对大家多少有些帮助的。大家以后阅读稍后推出的Unity Shader系列文章的时候,有场景创建或者Shader代码写好了如何使用方面的疑问的话,可以随时回过头来查阅这篇文章。

     

    OK,就让我们从这篇文章开始一趟精彩万分的Shader游戏编程旅途。

    依旧国际惯例,看几张文章中实现的场景美图先:



     

     





    上图中展示的文本配套Unity工程的可运行exe浅墨也为大家准备好了,有兴趣的朋友们可以点击 这里进行下载、运行和探索:


    PS:文章配套的三个unitypackage和最终的工程源码在文章末尾处提供下载。

     







    一、系列文章前言





    在这个系列开头,浅墨想说的是,其实这个系列文章中我们学的主要是着色器编程技术,重点不是学Unity。

    甚至可以这样说,我们学的是HLSL——没错,就是DirectX中的那个HLSL。


    为什么这样讲,让我们来捋一捋。

    首先,Unity中编写Shader的语言叫做ShaderLab,而ShaderLab说白了就是裹着一层皮的CG着色器语言而已。Cg,即C forgraphics,即用于图形的C语言,是微软Microsoft和英伟达NVIDIA相互协作在标准硬件光照语言的语法和语义上达成的一种一致性协议。

    HLSL和CG其实是同一种语言(参见Cg教程_可编程实时图形权威指南29页的致谢部分)。很多时候,我们会发现用HLSL写的代码可以直接当中Cg代码使用。

    Microsoft和NVIDIA联手推出CG语言,想在经济和技术上实现双赢,从而通过这种方式联手打击他们共同的对手GLSL。


    既然Unity主打Shader编程的语言ShaderLab是CG语言披上一层皮,而CG语言又约等于HLSL。这就是说,在Unity中写Shader约等于用HLSL写Shader,也就约等于给DirectX写Shader。虽然有点绕orz,最后总结一下也就是:

    在Unity中写Shader约等于给DirectX写Shader


    而Unity又是这样一个集万千宠爱于一身的可见即所得的目前在移动互联网时代火到不行的游戏引擎。可以说,Unity可见即所得的开发环境非常适合Shader的学习,而且在Unity分分钟可以创建出来一个漂亮的场景里面写写Shader,心情都会好很多。不再是苦逼地面朝代码背朝天了。

    所以浅墨决定开始在Unity中进行这个shader学习系列,毕竟Unity、CG、HLSL不分家。

    另外促成这个系列文章的成型的一个原因是Unity的Asset store。浅墨很喜欢Unity引领的Asset store这样一站式的游戏素材商店,里面有数不尽的游戏插件、素材、资源、脚本代码参考、shader资料等等,甚至现成的游戏工程范例。Asset store给开发者们带来了很大的便利,简直就是游戏开发界的大宝库。

    但需要说明的是,Unity这款引擎的缺点也是很明显的。比如Unity不对外开源,我们看不到源码,坑比较多,遇到坑了看不到

    源码给解决带来了很大难度。执行效率还是不太行,渲染大场景和做高级渲染的时候还是显得力不从心。比如渲染大片的近乎

    真实的动态水面时,帧数就立马降下来了,需要后期做很多的优化。就画面质量来说和Unreal Engine和cryEngine等次时代

    引擎比还是有差距。是最近几年互联网的浪潮和得屌丝者的天下商业模式促进了其最近几年如此的成功。


     

    说了这么多,总结一下。

    Unity只是我们学习CG、HLSL编程可见即所得的好帮手好工具而已。我们主要还是利用它来更好的学计算机图形学和Shader编程,顺便掌握目前热门的Unity引擎的基本使用和研发思路。

    我们还是忘不了C++和DirectX,我们还是渴望通过自己的努力,最终有能力用C/C++一句一句写出自己的游戏引擎,我们还是想从零开始造轮子,毕竟那样一句一句写出来的代码都是自己的,而不是那些别人为我们准备好的现成的API函数。

    谨以此前言,与诸君共勉。

     

     


     

     

     




    二、用Unity创建第一个美丽的游戏场景





    首先要说明的是,作为一个从入门内容开始逐渐深入介绍的系列教程,这一部分在Unity下创建场景的内容是为还不太熟悉Unity的朋友们准备的,如果你已经熟悉了Unity的使用,这部分可以快速跳读。

     

     

    OK,正式开始吧。

     





    2.1 【第一步】当然是新建一个项目

     



    大家肯定都知道,每次新建项目后或者新建场景后,会得到一片Unity中默认为全蓝的场景。想要场景变得有生机,一般都是去菜单栏的GameObject里面新建Terrain(地形)然后进行编辑。Terrain的制作很耗时而且水很深,想要精通也是得花一些功夫。

    甚至Unity Asset Store中有各种可以辅助快速生成AAA级大作风格的真实场景的插件,如Terrain Composer,配合着Unity中有名的Relief Terrain Pack v3地形辅助着色渲染工具,可以生成近乎以假乱真的三维自然风光出来。

    漂亮地形的创建当然不属于我们讲解的重点,网络上有数不清的文章和视频讲这方面的内容,有需要的话,大家去学一些基础,或者直接用Asset Store中现成的各种漂亮场景。反正浅墨是各种在网上下载AssetStore中美工大牛们做场景,然后简单的修改,为自己测试和平常调数值所用。

    这不,浅墨为了写这篇博客,就为大家再加工“创作“了一个夏威夷风格的场景来:)


     




    2.2 【第二步】导入Hawaii Environment.unitypackage场景包



    上文讲到,为了节约时间,浅墨提前为大家修改好了一个场景,然后这个场景已经打包,叫做“HawaiiEnvironment.unitypackage “,在文章末尾提供下载。(限于Unity对中文的支持拙计,无奈只能取英文名,不然直接导入就报错)。

          HawaiiEnvironment.unitypackage单独下载请点我】

     

    双击这个包,导入到我们空空如也的工程中,经过一段时间的读条,就导入完毕了。然后我们双击打开出现在Project面板中Assets文件夹下的场景文件Hawaii Environment.unity

     

    接着便打开了场景,如果打开成功,Scene面板中应该便出现了如下类似的场景画面:

     


     

    因为略去了场景编辑部分,直接导入,所以过程是非常简单的。但是,这还完全不够。让我们在场景中添加一个可以自由控制的摄像机吧。

     

     




    2.3 【第三步】添加第一人称摄像机



    浅墨准备的这个场景包是没有摄像机的,单单就是场景,所以我们还需要在场景中添加一个摄像机。

     

    大家应该清楚,比较常见添加摄像机的做法是通过菜单栏中的GameObject->CreateOther->Camera来添加。但这种方式的摄像机是固定的,不合我们的要求。我们想添加的是一个在游戏运行时可以自由移动视角的第一人称摄像机。其实Unity自带的资源包中刚好可以满足我们的要求。于是我们在Project面板中右键【Import Package】,或者菜单栏中Assets->ImportPackage->Character Controller来导入官网为我们准备的的角色控制资源包。如下图:

     

     

     

     

    点击之后,会弹出如下的资源导入确认窗口,我们直接点确定就行了:

     

     

     

    因为这个包很小,所以很快就导入完成,这时Assets根文件夹下会出现一个名为Standard Assets的文件夹,展开它或者点进去,就是名为【CharacterControllers】的文件夹,继续点进去,发现了一个胶囊状的叫【First PersonController】的家伙,这就是我们需要的了。

    然后我们先在Scene面板中利用【右键+键盘W、A、S、D】以及滚轮等操作调整好场景,然后在我们刚才的【CharacterControllers】下点击这个胶囊装的【First Person Controller】按住不放,拖动到Scene场景中,选到合适的地方(如草坪上)后就放手,操作如下:

    Unity会自动将这个【CharacterControllers】的中心位置依附到地形表面。

     

    这个时候我们会发现之前是黑屏的Game面板中也有了画面:

     

     

    这时我们还要将这个 First Person Controller的底部向上拖动一点,不然运行游戏时我们会不停的往下掉,因为在Unity默认情况下First Person Controller的中心位于中部,这会照成它的底部已经穿透地形,悬空位于地形的下方,自然一运行就往下掉。

     

    我们Hierarchy面板中选中First Person Controller,工具栏中选择【移动】工具

    然后对着场景中胶囊上的代表Y轴的绿色箭头向上适当拖动,让胶囊的底部确保位于草地之上就行了。

     

    这时候我们点击unity中间三角尖的【运行】按钮,就可以自由地在场景中观察和移动了~



    Unity第一人称控制器默认操作方式类似CS,CF一类的FPS游戏。W、A、S、D前后左右移动,空格跳跃,鼠标移动调整视角,非常有亲切感有木有~

    这就很好地体现了Unity的入门容易的特点,只用点点鼠标一个漂亮的场景就展现在眼前。





     

    2.4 【第四步】在游戏场景中加入背景音乐

     

     


    话说这么美丽的场景怎么能没有音乐?

    不妨就让我们添加一段优美的钢琴曲吧。曲子浅墨都为大家准备好了,上文已经导入的HawaiiEnvironment.unitypackage包中,在Assets根目录下包含了一首林海的《日光告别》。

     

    我们要做的只要是把这个音乐文件拖拽到第一人称摄像机First PersonController上就可以了,就像箭头中指的这样:

     

     

    拖拽完成后,First Person Controller的Inspector面板中就应该会多了一个Audio Source组件。


    运行场景,伴随着美丽的场景,“吹着海风”,优美的钢琴曲入耳,非常怡人。

     

    先放两张测试过程中的场景美图,再继续我们下一部分的讲解吧:




    非常逼真的水效,采用大名鼎鼎的NGUI工作室Tasharen Entertainment出品的水面插件:



     






     

     

     

    三、导入QianMo’s Toolkit并使用







    3.1 认识QianMo's Toolkit

     



    所谓的QianMo's Toolkit,其实就是浅墨为场景测试写的一个小脚本工具集,打包成一个unitypackage方便多次使用而已。若有需要,浅墨会在其中添加更多的功能。

    以后我们每次新建工程的时候,只要导入这个小工具就可以使用我们之前已经写好的各种特性,非常便捷。


    QianMo's Toolkit v1.0.unitypackage单独下载请点我】


    QianMo's Toolkit v1.0版的内容如下:

     

    也就是包含了五个脚本文件,两张图片。这五个脚本文件的功能分别为:

     

    ShowFPS:在游戏运行时显示帧率相关信息

    ShowObjectInfo:在场景中和游戏窗口中分别显示添加给任意物体文字标签信息。隐藏和显示可选,基于公告板技术实现。

    ShowGameInfo:在游戏运行时显示GUI相关说明

    ShowLogo:在游戏运行时显示Logo

    ShowUI:在游戏运行时显示简单的镶边UI。

     

    这个五个脚本的代码浅墨都已经详细注释,在后续文章中有机会我们会介绍其具体写法。这篇文章中就先简单的认识一下他们就好。PS:下文第四节中贴出了ShowGameInfo脚本的全部代码。

     

     

     

     




    3.2 使用QianMo's Toolkit




    上文已经说了,既然这是一个unitypackage,那么只用双击它导入到我们当前的项目中就行了。导入完成之后。Assets文件夹下就又多了一个名为” QianMo's Toolkit v1.0“的文件夹,内容就是我们刚才介绍的5个脚本文件两张图:

     

     

    暂时我们要使用的是ShowGameInfo、ShowLogo、ShowUI这三个脚本文件,把它们一起拖到我们之前创建的第一人称摄像机First Person Controller上就行了:

     

     


    拖动完成后,我们在First Person Controller的Inspector面板中发现其多了三个组件,就是我们给他添加的这个三个脚本:

     

    其实Show Logo无关紧要,就是显示了浅墨自己的logo而已,当然你可以换成自己的logo。show UI也无关紧要,就是显示了一个顶部的镶边png。主要的是这个ShowGameInfo,它是用于显示帧率等相关文字消息的。(其实简约党会觉得三个都无关紧要,orz)

     

    拖动完成之后,再次运行,我们来看一看效果:


     

    可以发现,游戏窗口的边边角角多了一些说明和图片,以及有了帧率的显示。

     

     

     

     

     

     


     

     

    四、书写和使用第一个Shader

     




    上文讲解的都是一般的场景构建过程,接下来就要正式开始我们的核心部分,书写第一个Shader了。在完成上文中讲解的创建好漂亮的场景之后,我们首先可以在Assets根目录下创建一个文件夹,用于以后Shader和Material文件的存放。创建过程可以是在Project面板的空白处右键->Create->Folder,也可以是点击Project面板中的Create下拉菜单->Folder

     

     

     

    给新出来的这个文件夹取名Shaders,然后回车。然后再用同样的方法在Assets根目录下创建一个名为Textures的文件夹,用于稍后素材图片的存放。那么,如果你按照浅墨按照目前描述的步骤来的话,Assets根目录到现在就是这样的5个文件夹:

     

     

    接着,进去到我们创建的Shader文件夹。同样在空白处右键->Create->Shader,或者是直接点Create下拉菜单->Shader,创建一个Shader文件,取名为   “0.TheFirstShader”。然后双击打开它,Unity会默认使用名为MonoDevelop的编辑器打开这个Shader文件。


    小tips:可以在菜单栏中Edit->Preferences->ExternalTools中调成默认用Visual Studio打开,但未经修改配置文件的Visual Studio对Shader后缀的文件是不支持语法高亮的,浅墨修改了部分配置文件才让Visual Studio支持了Unity Shader书写的语法高亮。对于不太清楚如何修改的朋友,可以善用搜索引擎,或者过些天浅墨会单独发一篇名为《Unity中使用Visual Studio编写shader并设置代码高亮》的文章来专门讲解。

     

     

    作为初次写Shader,我们暂且先用MonoDevelop顶一顶,后面的文章再换用修改了配置文件的Visual Studio。

     

    好了,用MonoDevelop打开我们新建的这个Shader文件,发现Unity已经为我们写好了很多代码。

    我们不妨自己重新写点不一样的东西。删掉原本的这些代码,拷贝浅墨写的如下代码到编辑器中:

     

     

    //-----------------------------------------------【Shader说明】----------------------------------------------
    //		Shader功能:   凹凸纹理显示+自选边缘颜色和强度
    //     使用语言:   Shaderlab
    //     开发所用IDE版本:Unity4.5 06f 、Monodevelop   
    //     2014年11月2日  Created by 浅墨    
    //     更多内容或交流请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
    //---------------------------------------------------------------------------------------------------------------------
    
    
    Shader "浅墨Shader编程/0.TheFirstShader" 
    {
    	//-------------------------------【属性】-----------------------------------------
    	Properties 
    	{
    		_MainTex ("【纹理】Texture", 2D) = "white" {}
    		_BumpMap ("【凹凸纹理】Bumpmap", 2D) = "bump" {}
    		_RimColor ("【边缘颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)
    		_RimPower ("【边缘颜色强度】Rim Power", Range(0.6,9.0)) = 1.0
    	}
    
    	//----------------------------【开始一个子着色器】---------------------------
    	SubShader 
    	{
    		//渲染类型为Opaque,不透明
    		Tags { "RenderType" = "Opaque" }
    
    		//-------------------开始CG着色器编程语言段-----------------
    		CGPROGRAM
    
    		//使用兰伯特光照模式
    		#pragma surface surf Lambert
    		
    		//输入结构
    		struct Input 
    		{
    			float2 uv_MainTex;//纹理贴图
    			float2 uv_BumpMap;//法线贴图
    			float3 viewDir;//观察方向
    		};
    
    		//变量声明
    		sampler2D _MainTex;//主纹理
    		sampler2D _BumpMap;//凹凸纹理
    		float4 _RimColor;//边缘颜色
    		float _RimPower;//边缘颜色强度
    
    		//表面着色函数的编写
    		void surf (Input IN, inout SurfaceOutput o)
    		{
    			//表面反射颜色为纹理颜色
    			o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    			//表面法线为凹凸纹理的颜色
    			o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    			//边缘颜色
    			half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    			//边缘颜色强度
    			o.Emission = _RimColor.rgb * pow (rim, _RimPower);
    		}
    
    		//-------------------结束CG着色器编程语言段------------------
    		ENDCG
    	} 
    
    	//“备胎”为普通漫反射
    	Fallback "Diffuse"
    }


     


    由于这是第一篇Shader系列文章,已经涉及到很多内容了,所以浅墨不可能展开讲解这段代码的具体思路和写法,不过已经详细注释,大家应该会多少有点明白。随着稍后文章的深入,这段代码就显得很简单易懂了。

    拷贝完成,保存一下这段代码,unity会自动检测和编译被保存的代码,我只需返回Unity窗口,等待编译完成即可。若没有错误,在“0.TheFirstShader”的inspector面板中得到的结果应该是有红色的错误提示的。

     

    需要注意的是,Shader想要使用到游戏物体上,一般得有个媒介,这个媒介就是我们的老朋友——材质(Material)。我们把Shader作用于材质,接着再把材质对应地作用于给游戏物体,这样写的Shader就间接地给物体表面使用了。


     


    而这一层关系,在Unity中完全可以通过点点鼠标,拖动来完成。下面我们就来讲一讲如何将一个着色程序的结果显示到物体表面上。

     

    知道以上原理了就很简单了,在“0.TheFirstShader.shader”的同一目录下创建一个Material。同样是可以通过Create下拉菜单->Material或者空白处右键->create->Material来完成。


    为了到时候方便对应,我们将这个材质也取名为0.TheFirstShader。

     

     

    接着,将0.TheFirstShader.shader拖动到0.TheFirstShader材质身上然后释放。

     

     

    拖动完成后,我们单击0.TheFirstShader材质,打开他的面板,发现他已经和一开始不一样了,泛着蓝光:




    还没完,接下来我们还得给这个材质添加两张纹理图片。图片浅墨也已经提前准备好了,在名为Textures01 by QianMo.unitypackage的Unity包中,同样双击这个包然后打开导入到项目中。


    Textures01 by QianMo.unitypackage单独下载请点我】


    我们在Textures文件夹下找到这两张纹理,接下来做的就是将他们拖动到0.TheFirstShader材质对应的纹理区域中,如下:

     

     

    或者点击这里的Select分别选择,操作如下:


     

    两张纹理选择完毕后,我们的材质就准备好了,最后的结果,有点黑科技,如各种科幻游戏和电影中发光的矿石,非常炫酷:

     

     


    OK,那么就只剩下最后一步了,就是在场景中创建一个物体,然后将我们做好的材质拖拽到物体身上赋给这个物体就行了。

     

    菜单栏【GameObject】->【Create Other】->【Capsule】或者【Create】下拉菜单->【Capsule】来在场景中创建一个胶囊装的物体。把他拖动到和我们的第一人称摄像机【First Person Controller】很近的地方,这样方便观察,接着就可以把我们的“0.TheFirstShader”材质直接拖拽给场景中的这个胶囊,或者Hierachy面板中【Capsule】名字上就行了,操作如下图中的箭头所示:

     

     

     

     

    经过拖拽,Capsule加上Material后的效果如下:



     

     




     

    4.1 给使用Shader的物体加上文字说明




    为了以后介绍多个Shader写法时能更清晰更方便,浅墨专门在QianMo’s Toolkit中做了一个可以在场景中和游戏窗口中分别显示附加给任意物体文字标签信息的工具脚本,叫做ShowObjectInfo,其详细注释的代码如下:

     


     

    //-----------------------------------------------【脚本说明】-------------------------------------------------------
    //      脚本功能:    在场景中和游戏窗口中分别显示给任意物体附加的文字标签信息
    //      使用语言:   C#
    //      开发所用IDE版本:Unity4.5 06f 、Visual Studio 2010    
    //      2014年10月 Created by 浅墨    
    //      更多内容或交流,请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
    //---------------------------------------------------------------------------------------------------------------------
    
    //-----------------------------------------------【使用方法】-------------------------------------------------------
    //      第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨's Toolkit v1.0]->[ShowObjectInfo]
    //      第二步:在Inspector里,Show Object Info 栏中的TargetCamera参数中选择需面向的摄像机,如MainCamera
    //      第三步:在text参数里填需要显示输出的文字。
    //      第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。
    
    //      PS:默认情况下文本信息仅在游戏运行时显示。
    //      若需要在场景编辑时在Scene中显示,请勾选Show Object Info 栏中的[Show Info In Scene Editor]参数。
    //      同理,勾选[Show Info In Game Play]参数也可以控制是否在游戏运行时显示文本信息
    //---------------------------------------------------------------------------------------------------------------------
    
    
    //预编译指令,检测到UNITY_EDITOR的定义,则编译后续代码
    #if UNITY_EDITOR    
    
    
    //------------------------------------------【命名空间包含部分】----------------------------------------------------
    //  说明:命名空间包含
    //----------------------------------------------------------------------------------------------------------------------
    using UnityEngine;
    using UnityEditor;
    using System.Collections;
    
    //添加组件菜单
    [AddComponentMenu("浅墨's Toolkit v1.0/ShowObjectInfo")]
    
    
    //开始ShowObjectInfo类
    public class ShowObjectInfo : MonoBehaviour
    {
    
        //------------------------------------------【变量声明部分】----------------------------------------------------
        //  说明:变量声明部分
        //------------------------------------------------------------------------------------------------------------------
        public string text="键入你自己的内容 by浅墨";//文本内容
        public Camera TargetCamera;//面对的摄像机
        public bool ShowInfoInGamePlay = true;//是否在游戏运行时显示此信息框的标识符
        public bool ShowInfoInSceneEditor = false;//是否在场景编辑时显示此信息框的标识符
        private static GUIStyle style;//GUI风格
    
    
    
        //------------------------------------------【GUI 风格的设置】--------------------------------------------------
        //  说明:设定GUI风格
        //------------------------------------------------------------------------------------------------------------------
        private static GUIStyle Style
        {
            get
            {
                if (style == null)
                {
                    //新建一个largeLabel的GUI风格
                    style = new GUIStyle(EditorStyles.largeLabel);
                    //设置文本居中对齐
                    style.alignment = TextAnchor.MiddleCenter;
                    //设置GUI的文本颜色
                    style.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
                    //设置GUI的文本字体大小
                    style.fontSize = 26;
                }
                return style;
            }
    
        }
    
    
    
    
        //-----------------------------------------【OnGUI()函数】-----------------------------------------------------
        // 说明:游戏运行时GUI的显示
        //------------------------------------------------------------------------------------------------------------------
        void OnGUI( )
        {
            //ShowInfoInGamePlay为真时,才进行绘制
            if (ShowInfoInGamePlay)
            {
                //---------------------------------【1.光线投射判断&计算位置坐标】-------------------------------
                //定义一条射线
                Ray ray = new Ray(transform.position + TargetCamera.transform.up * 6f, -TargetCamera.transform.up);
                //定义光线投射碰撞
                RaycastHit raycastHit;
                //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
                collider.Raycast(ray, out raycastHit, Mathf.Infinity);
                
                //计算距离,为当前摄像机位置减去碰撞位置的长度
                float distance = (TargetCamera.transform.position - raycastHit.point).magnitude;
                //设置字体大小,在26到12之间插值
                float fontSize = Mathf.Lerp(26, 12, distance / 10f);
                //将得到的字体大小赋给Style.fontSize
                Style.fontSize = (int)fontSize;
                //将文字位置取为得到的光线碰撞位置上方一点
                Vector3 worldPositon = raycastHit.point + TargetCamera.transform.up * distance * 0.03f;
                //世界坐标转屏幕坐标
                Vector3 screenPosition = TargetCamera.WorldToScreenPoint(worldPositon);
                //z坐标值的判断,z值小于零就返回
                if (screenPosition.z <= 0){return;}
                //翻转Y坐标值
                screenPosition.y = Screen.height - screenPosition.y;
                
                //获取文本尺寸
                Vector2 stringSize = Style.CalcSize(new GUIContent(text));
                //计算文本框坐标
                Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
                //设定文本框中心坐标
                rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
    
    
                //----------------------------------【2.GUI绘制】---------------------------------------------
                //开始绘制一个简单的文本框
                Handles.BeginGUI();
                //绘制灰底背景
                GUI.color = new Color(0f, 0f, 0f, 0.8f);
                GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
                //绘制文字
                GUI.color = new Color(1, 1, 1, 0.8f);
                GUI.Label(rect, text, Style);
                //结束绘制
                Handles.EndGUI();
            }
        }
    
        //-------------------------------------【OnDrawGizmos()函数】---------------------------------------------
        // 说明:场景编辑器中GUI的显示
        //------------------------------------------------------------------------------------------------------------------
        void OnDrawGizmos()
        {
            //ShowInfoInSeneEditor为真时,才进行绘制
            if (ShowInfoInSceneEditor)
            {
                //----------------------------------------【1.光线投射判断&计算位置坐标】----------------------------------
                //定义一条射线
                Ray ray = new Ray(transform.position + Camera.current.transform.up * 6f, -Camera.current.transform.up);
                //定义光线投射碰撞
                RaycastHit raycastHit;
                //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
                collider.Raycast(ray, out raycastHit, Mathf.Infinity);
                
                //计算距离,为当前摄像机位置减去碰撞位置的长度
                float distance = (Camera.current.transform.position - raycastHit.point).magnitude;
                //设置字体大小,在26到12之间插值
                float fontSize = Mathf.Lerp(26, 12, distance / 10f);
                //将得到的字体大小赋给Style.fontSize
                Style.fontSize = (int)fontSize;
                //将文字位置取为得到的光线碰撞位置上方一点
                Vector3 worldPositon = raycastHit.point + Camera.current.transform.up * distance * 0.03f;
                //世界坐标转屏幕坐标
                Vector3 screenPosition = Camera.current.WorldToScreenPoint(worldPositon);
                //z坐标值的判断,z值小于零就返回
                if (screenPosition.z <= 0) { return; }
                //翻转Y坐标值
                screenPosition.y = Screen.height - screenPosition.y;
                
                //获取文本尺寸
                Vector2 stringSize = Style.CalcSize(new GUIContent(text));
                //计算文本框坐标
                Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
                //设定文本框中心坐标
                rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
    
    
    
                //----------------------------------【2.GUI绘制】---------------------------------------------
                //开始绘制一个简单的文本框
                Handles.BeginGUI();
                //绘制灰底背景
                GUI.color = new Color(0f, 0f, 0f, 0.8f);
                GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
                //绘制文字
                GUI.color = new Color(1, 1, 1, 0.8f);
                GUI.Label(rect, text, Style);
                //结束绘制
                Handles.EndGUI();
    
            }
    
        }
    
    }
    
    //预编译命令结束
    #endif

     

    这个脚本的用法倒是很简单,在代码的说明部分已经详细写出,在这里我们再列出一遍:

     

    第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨's Toolkit v1.0]->[ShowObjectInfo]

    第二步:在Inspector里,ShowObject Info 栏中的TargetCamera参数中选择需面向的摄像机,如Main Camera,FirstPerson Controller等

    第三步:在text参数里填需要显示输出的文字。

    第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。

     

     

    也就是拖拽ShowObjectInfo脚本或者直接添加组件给需要附加文字的物体,然后在Inspector中输入需要显示的文字,然后选择其面对的摄像机就可以了。

     

     

     

    我们将ShowObjectInfo脚本拖拽给上文中刚刚变得炫酷外形黑科技的Capsule:

     

    那么他在Inspector就多了一个“ShowObject Info(Script)”组件,将该组件的Text项中填上“凹凸纹理+边缘发光效果”,TargetCamera中填上First Person Controller的子物体Main Camera:

     

     

    最后,得到的效果就是这样:


     









     


    五、总结、配套资源&最终工程下载

     




    好了,本篇的文章到这里就大概结束了。

     

    今天讲的内容还是非常多的,对于新接触Unity的朋友们来说或许还得好好消化消化,而熟悉Unity的朋友应该很快就可以看懂,或者觉得浅墨讲了一堆废话,orz。

     

    这篇文章的内容说白了就非常简单,也就是新建工程,然后导入三个浅墨提前准备好的unitypackage游戏资源,点一点鼠标拖动拖动脚本,新建一个Shader,写点代码,再创建一个Material,Shader赋给这个Material,最后创建一个胶囊状Capsule,Material赋给这个Capsule,点运行查看最终效果。一切,就是这么简单。:)

     

     

    本文配套的三个unitypackage打包请点击此处下载:


    【浅墨Unity3D Shader编程】之一 配套的三个unitypackage打包下载




    本文最终的Unity工程请点击此处下载:


    【浅墨Unity3D Shader编程】之一 配套Unity工程




    最后放几张最终的场景美图吧。

     

    站在亭子上看世界:

     

     

    逼真的光晕:

     

     

    漂亮的天空:

     

     

     

    乱真的水面:

     

     

    蓝天和草地树木交相辉映:

     

     

     

    OK,全文到此结束。

    新的游戏编程之旅已经开启,下周一,我们不见不散。


     

    展开全文
  • 面向组件编程Unity 2.怎样获取脚本所在物体的各种组件 例如:gameObject属性
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class TransformFeng2 : MonoBehaviour
    {
    
        Transform Ts;
        BoxCollider Tg;
        // Use this for initialization
        void Start()
        {
            #region
            //3.可以通过游戏物体身上transform
            //组件得到其他的任意一个组件
            transform.GetComponent<BoxCollider>();
            //4.gameObject属性,可以直接得
            //到脚本所在游戏物体上的gameobject组件
            gameObject.tag = "Finish";
            #endregion
        }
    }

    展开全文
  • Unity企业内训》 版本 作者 参与者 完成日期 备注 Unity_Training_V01_1.0 严立钻   2018.09.11 ...

    《Unity企业内训》

    版本

    作者

    参与者

    完成日期

    备注

    Unity_Training_V01_1.0

    严立钻

     

    2018.09.11

     

     

     

     

     

     

     

     

    ##《Unity企业内训》发布说明:

    ++++“Unity企业内训”是对企业内非程序员岗位的Unity普及,比如产品运营等,让相关人员熟悉Unity开发过程,更了解程序员的开发流程和技能点;有利于沟通交流和产品需求提出及优化;

    ++++“Unity企业内训”定位是非程序员岗位,再次声明:程序员请绕行,产品运营美术等请进入

     

     

    ##《Unity企业内训》目录:

    ++++Unity企业内训(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82634668

    #第1讲:Unity中C#开发基础

    #第2讲:Unity引擎基础

    #第3讲:Unity面向组件开发

    #第4讲:Unity物理系统

    #第5讲:UGUI

    #第6讲:Unity动画系统

    #第7讲:Unity特效渲染

    #第8讲:Unity数据存储

    #第9讲:Unity中Sqlite数据库

    #第10讲:Unity中的资源管理

    #第11讲:Unity中的性能优化

    #第12讲:Unity网络

    #第13讲:设计模式

    #第14讲:UML类图

    #第15讲:Shader编程

    #第16讲:游戏框架

    #第17讲:Lua热更新

    #第18讲:UnityAPI

    #第19讲:VIVE开发

    #第20讲:Oculus开发

    #第21讲:Unity案例分析

    #第22讲:VRTK跨平台开发

     

     

     

     

     

     

    #第3讲:Unity面向组件开发

    #第3讲:Unity面向组件开发

    #第3讲:Unity面向组件开发

    ++++3.1、Unity组件开发

    ++++3.2、Unity脚本组件

    ++++3.3、常用类

    ++++3.4、Prefab预设体

     

     

     

    ##3.1、Unity组件开发

    ##3.1、Unity组件开发

    ++3.1、Unity组件开发

    ++++3.1.1、工程与应用程序

    ++++3.1.2、Unity工程开发框架

    ++++3.1.3、Unity面向组件开发思想

    ++++3.1.4、脚本组件的使用

     

     

     

    ###3.1.1、工程与应用程序

    ###3.1.1、工程与应用程序

    ++3.1.1、工程与应用程序

    ++++立钻哥哥:新创建的Unity工程,在其目录文件夹中包含4个文件夹:Assets/、Library/、ProjectSettings/、Temp/等

    ++++[Assets/]:里面存放的是项目所需要的资源

    ++++[Library/]:里面存放的是所需要的库文件

    ++++[ProjectSettings/]:里面存放的是工程设置文件

    ++++[Temp/]:里面存放的是临时文件

     

     

     

    ###3.1.2、Unity工程开发框架

    ###3.1.2、Unity工程开发框架

    ++3.1.2、Unity工程开发框架

    ++++立钻哥哥:

    ++++工程,场景,游戏对象和组件的关系:

    --一个工程里面有多个场景,相当于一个游戏有多个关卡

    --一个场景里面有多个游戏对象,相当于游戏中的不同的元素

    --每个游戏对象又有一个或者多个组件,游戏对象想要实现什么样的功能只需要加上相对应的组件即可

     

     

     

    ###3.1.3、Unity面向组件开发思想

    ###3.1.3、Unity面向组件开发思想

    ++3.1.3、Unity面向组件开发思想

    ++++立钻哥哥:Unity面向组件开发,游戏物体想要实现什么样的功能,只需要添加相对应的组件即可,此时会在Inspector检视面板中显示出来,一些属性值可以可视化的更改

     

     

     

    ###3.1.4、脚本组件的使用

    ###3.1.4、脚本组件的使用

    ++3.1.4、脚本组件的使用

    ++++立钻哥哥:Unity2017之前版本自带Mono脚本编辑器,创建Mono应用程序;Unity2017之后推荐使用VS(Visual Studio),包括了整个软件生命周期中需要的大部分工具

    ++++在Unity中通过菜单设置修改默认的脚本编辑器:[Edit]=>[Preferences]=>[External Tools]=>[External Script Editor];

     

    ++脚本组件

    ++++立钻哥哥:脚本是一种特殊的组件,它用于添加到游戏对象上以实现用户自定义的一些功能

    ++++Unity主要支持C#来编写脚本

     

    ++脚本的创建

    ++++立钻哥哥:在Project视窗Asset文件夹中点击右键,创建C#脚本,然后把创建的脚本拖放到游戏物体上即可

     

    ++脚本的使用

    ++++立钻哥哥:双击创建的脚本组件,即可打开脚本

    using UnityEngine;

    using System.Collections;

    using System.Collections.Generic;

    using System;

     

    public class MyClass : MonoBehaviour{

    }    //立钻哥哥:public class MyClass:MonoBehaviour{}

    ++++说明:类名与脚本组件名一致,并自动的继承MonoBehaviour类;(类名与脚本名不一样会出错

     

     

     

     

     

    ##3.2、Unity脚本组件

    ##3.2、Unity脚本组件

    ++3.2、Unity脚本组件

    ++++3.2.1、Unity脚本类

    ++++3.2.2、MonoBehaviour类

    ++++3.2.3、脚本生命周期

    ++++3.2.4、常用调试方法

     

     

    ###3.2.1、Unity脚本类

    ###3.2.1、Unity脚本类

    ++3.2.1、Unity脚本类

    ++++立钻哥哥:Unity中的常用脚本类可简单分为四大类:宏观控制类;游戏对象类;组件类;资源类

    ++++[宏观控制类]:主要作用是针对Unity程序中的某一方面进行宏观控制;包括:应用程序类(Application)、输入类(Input)、图形输出类(GUI)、物理引擎类(Physics)、资源类(Resources)、时间类(Time)等

    ++++[游戏对象类(GameObject)]:表示当前脚本挂载的游戏对象

    ++++[组件类(Component)]:脚本开发中的组件类可以和图形界面中的检视面板对应起来;(每一个游戏对象的细节设置与操控都需要借助组件类来完成)

    ++++[资源类]:资源一般都是在图形界面导入之后直接使用

     

     

     

    ###3.2.2、MonoBehaviour类

    ###3.2.2、MonoBehaviour类

    ++3.2.2、MonoBehaviour类

    ++++立钻哥哥:Unity脚本组件必须继承MonoBehaviour类

    ++++继承自MonoBehaviour的脚本组件可以自动调用其封装好了的回调方法

     

     

     

    ###3.2.3、脚本生命周期

    ###3.2.3、脚本生命周期

    ++3.2.3、脚本生命周期

    ++++立钻哥哥:脚本生命周期:[Awake()]=>[OnEnable()]=>[Start()]=>[FixedUpdate()]=>[Update()]=>[LateUpdate()]=>[OnBecameVisible()]=>[OnGUI()]=>[OnBecameInvisible()]=>[OnDisable()]=>[OnDestroy()]=>[OnApplicationQuit()]

    ++++初始阶段:Awake()OnEnable()Start()

    --Awake()唤醒:当物体载入时立即调用1次,常用于在游戏开始前进行初始化,可以判断当满足某种条件执行此脚本 this.enable = true

    --OnEnable()当可用:每当脚本对象启用时调用

    --Start()开始:物体载入且脚本对象启用时被调用1次;常用于数据或游戏逻辑初始化,执行时机晚于Awake()

    ++++物理阶段:FixedUpdate()

    --FixedUpdate()固定更新:脚本启用后,固定时间被调用,适用于对游戏对象做物理操作,例如移动等

    --设置更新频率:[Edit]=>[Project Setting]=>[Time]=>[Fixed Timestep]值,默认为0.02s

    ++++游戏逻辑:Update()LateUpdate()

    --Update()更新:脚本启用后,每次渲染场景时调用,频率与设备性能及渲染量有关

    --LateUpdate()延迟更新:在Update()函数被调用后执行,适用于跟随逻辑

    ++++场景渲染:OnGUI()OnBecameVisible()OnBecameInvisible()

    --OnGUI()渲染:渲染和处理GUI事件时调用

    --OnBecameVisible()当可见:当Mesh Renderer在任何相机上可见时调用

    --OnBecameInVisible()当不可见:当Mesh Renderer在任何相机上不可见时调用

    ++++结束阶段:OnDisable()OnDestroy()OnApplicationQuit()

    --OnDisable()当不可用:对象变为不可用和附属游戏对象非激活状态时此函数被调用

    --OnDestroy()当销毁:当脚本销毁或附属的游戏对象被销毁时调用

    --OnApplicationQuit()当程序结束:应用程序退出时被调用

     

     

     

    ###3.2.4、常用调试方法

    ###3.2.4、常用调试方法

    ++3.2.4、常用调试方法

    ++++立钻哥哥:在学习和使用Unity时会经常调试代码,常用的调试方法有:第一种,在可能出错的行添加断点;第二种,选择打印消息的方式

     

    ++调试方法1:在可能出错的行添加断点

    ++++立钻哥哥:

     

    ++调试方法2:打印消息的方式

    ++++立钻哥哥:常用打印消息的方式:一种是print,一种是Debug.Log()

    ++++[print()方法]:它是MonoBehaviour类的成员;当一个脚本继承MonoBehaviour时,才可以使用Print方法

    ++++[Debug方法]:是一个独立的、密闭的类;Debug任何地方都可以,建议使用Debug.Log()方法

     

     

     

     

     

    ##3.3、常用类

    ##3.3、常用类

    ++3.3、常用类

    ++立钻哥哥:APIApplication Programming Interface)应用程序编程接口,是一些预先定义的函数;Unity引擎提供了丰富的组件和类库,为开发者提供了非常大的便利,熟练掌握和使用这些API对于提高游戏开发效率很重要

    ++++3.3.1、Component

    ++++3.3.2、GameObject

    ++++3.3.3、Transform

    ++++3.3.4、Vector3

    ++++3.3.5、Quaternion

    ++++3.3.6、Time

    ++++3.3.7、Mathf

     

     

     

    ###3.3.1、Component类

    ###3.3.1、Component类

    ++3.3.1、Component类

    ++++立钻哥哥:Component类:gameObjecttransformtagcolliderrendererrigidbodyGetComponent()GetComponentInChildren()GetComponents()GetComponentsInChildren()

    ++++[gameObject]:组件附加的游戏对象;组件总是被附加到游戏对象上

    ++++[transform]:附加到此游戏对象Transform组件(如果没有则为空)

    ++++[tag]:此游戏对象的标签

    ++++[collider]:附加到此游戏对象的Collider(如无附加则为空)

    ++++[renderer]:附加到此游戏对象Renderer组件(如果没有则为空)

    ++++[rigidbody]:附加到此游戏对象Rigidbody组件(如果没有则为空)

    ++++[GetComponent()]:如果游戏对象有附加type类型的组件,则返回,如果没有则为空

    ++++[GetComponentInChildren()]:返回此游戏对象上type类型的组件或任何它的子对象,使用深度优先搜索

    ++++[GetComponents()]:返回此对象type类型的所有组件

    ++++[GetComponentsInChildren()]:返回此游戏对象与其子对象所有type类型的组件

     

     

     

    ###3.3.2、GameObject类

    ###3.3.2、GameObject类

    ++3.3.2、GameObject类

    ++++立钻哥哥:GameObject类:tagnameFindGameObjectsWithTag(string tag)、T GetComponent<T>()、SetActive(bool value)、FindWithTag(string tag)

    ++++通过tag得到游戏物体:

    --static GameObject FindWithTag(string tag);

    --GameObject.FindWithTag(立钻哥哥);

    ++++通过name得到游戏物体:

    --static GameObject Find(string name);

    --GameObject.Find(立钻哥哥);

    ++++[tag]:可读写属性,游戏物体的tag

    ++++[name]:可读写属性,游戏物体的name

    ++++[FindGameObjectsWithTag(string tag)]:静态方法,返回所有tag标识的物体,返回值是个数组

    ++++[T GetComponent<T>()]:泛型实例方法,得到T类型的组件(强烈建议使用)

    ++++[SetActive(bool value)]:实例方法,设置游戏物体是否是活动的

    ++++[FindWithTag(string tag)]:静态方法,得到tag标识的游戏物体

     

     

     

    ###3.3.3、Transform类

    ###3.3.3、Transform类

    ++3.3.3、Transform类

    ++++立钻哥哥:Transform类:任何创建的游戏对象在场景中都会有位置,旋转和缩放最基本的信息,故该组件是必须存在的

    ++++Transform组件作用:1、负责游戏对象的变换(位置,旋转和缩放);2、维持父子关系

    ++++[position]:世界坐标系中transform的位置

    ++++[localPosition]:相对于父物体的位置

    ++++[eulerAngles]:欧拉角,旋转的角度

    ++++[rotation]:世界坐标系中变换的四元数

    ++++[parent]:物体父物体的Transform组件

    ++++[root]:物体最高层次父物体的Transform组件

    ++++[void Translate(Vector3 translation)]:使当前对象朝translation

    ++++[void Rotate(Vector3 eulerAngles)]:按给定的欧拉角进行旋转

    ++++[void RotateAround(Vector3 point, Vector3 axis, float angle)]:绕point点沿axis轴旋转angle度

    ++++[Transform Find(string name)]:通过名字查找子物体

    ++++[void LookAt(Transform target)]:使物体朝向target点

     

     

     

    ###3.3.4、Vector3类

    ###3.3.4、Vector3类

    ++3.3.4、Vector3类

    ++++立钻哥哥:Vector3类是封装了向量运算相关变量和方法的结构体

    ++++Vector类的点乘、叉乘

     

    ++点乘

    ++++立钻哥哥:点乘又称“点积”和“内积”

    ++++几何意义:a*b = |a|*|b|*cos<a, b>:两个向量的单位向量相乘后再乘以二者夹角的余弦值

    ++++代码:float dot = Vector3.Dot(Va, Vb);

    ++++点乘应用:对于标准化过的向量,点乘结果等于两向量夹角的余弦值

    ++++计算两向量夹角:

    float dot = Vector3.Dot(a.normalized, b.normalized);

    float angle = Mathf.Acos(dot) * Mathf.Rad2Deg;

     

    ++叉乘

    ++++立钻哥哥:叉乘又称“叉积”或“外积”

    ++++几何意义:结果为两个向量所组成面的垂直向量,模长为两向量模长乘积再乘夹角的正弦值

    ++++脚本:Vector vector = Vector3.Cross(a, b);

    ++++叉乘应用:创建垂直于平面的向量;判断两条向量相对位置

     

    ++Vector3类

    ++++立钻哥哥:Vector3封装了向量运算相关变量和方法的结构体

    ++++[normalized]:标准化向量,方向不变,长度为1(只读)

    ++++[magnitude]:向量长度(只读)

    ++++[sqrMagnitude]:向量长度平方(只读)

    ++++[forward]:Vector3(0,0,1)的简码,Z轴正方向

    ++++[up]:Vector(0,1,0)的简码,Y轴正方向

    ++++[right]:Vector3(1,0,0)的简码,X轴正方向

    ++++[void Normalize()]:标准化向量,长度为1

    ++++[static Vector3 Lerp(Vector3 from, Vector3 to)]:两个向量之间的夹角

    ++++[static float Distance(Vector3 a, Vector3 b)]:两个向量之间的距离

     

     

     

    ###3.3.5、Quaternion类

    ###3.3.5、Quaternion类

    ++3.3.5、Quaternion类

    ++++立钻哥哥:Quaternion类:四元数

    ++++[identity]:该四元数无旋转,常用在代码创建对象

    ++++[LookRotation()]:创建一个旋转,沿着forward(z轴)并且头部沿着upwards(y轴)的约束注视

    ++++四元数是左乘向量,表示将该向量按照四元数表示的角度旋转

    Vector3 point = new Vector3(0, 0, 10);

    Vector3 newPoint = Quaternion.Euler(0, 30, 0) * point;

     

    ++避免万向节死锁

    ++++立钻哥哥:

    this.transform.rotation *= Quaternion.Euler(0, 1, 0);

    == >可使物体沿自身Y轴旋转;

     

    this.transform.Rotate(Vector3 eulerAngles);

    ==>内部就是使用四元数相乘实现;

     

     

     

     

    ###3.3.6、Time类

    ###3.3.6、Time类

    ++3.3.6、Time类

    ++++立钻哥哥:Time类:时间类

    ++++[time]:从游戏开始到现在所用的时间(只读)

    ++++[deltaTime]:获取上一次Update()方法执行的时间到本次执行Update()方法时间的差值

    ++++[fixedDeltaTime]:在物理和其他固定帧速率进行更新上一帧所消耗的时间,以秒计算

    ++++[timeScale]:表示事件缩放,正常时间为1

     

     

     

    ###3.3.7、Mathf类

    ###3.3.7、Mathf类

    ++3.3.7、Mathf类

    ++++立钻哥哥:Mathf数学类封装了常见数学计算方法的结构体

    ++++[Lerp()]:两个浮点数之间进行插值

    ++++[Clamp()]:返回一个限制值

    ++++[Sin()]:计算并返回浮点型的正弦值

    ++++[Cos()]:计算并发挥浮点型的余弦值

    ++++[Abs()]:计算并返回指定参数的绝对值

    ++++[Max()]:返回两个值之中最大的值

    ++++[Min()]:返回两个值之中最小的值

    ++++[Sqr()]:返回平方根

    ++++[PI()]:圆周率

     

     

     

     

     

    ##3.4、Prefab预制体

    ##3.4、Prefab预制体

    ++3.4、Prefab预制体

    ++++3.4.1、预制体概念

    ++++3.4.2、预制体实例化

     

     

     

    ###3.4.1、预制体概念

    ###3.4.1、预制体概念

    ++3.4.1、预制体概念

    ++++立钻哥哥:Prefab预制体是一个游戏对象及其组件的集合,目的是使游戏对象及资源能够被重复使用,相同的游戏对象可以通过一个预制体来创建,此过程可以理解为实例化

    ++++[预制体的生成]:把一个游戏对象从层级视图拖到工程视窗后就生成一个预制体

     

     

     

    ###3.4.2、预制体实例化

    ###3.4.2、预制体实例化

    ++3.4.2、预制体实例化

    ++++立钻哥哥:预制体实例化:把预制体直接拖到层级视窗上,就会实例化一个游戏对象

    ++++对预制体做出修改后,其所实例化的对象也会做出相应的改动

    ++++通过预设体创建的游戏对象会在Inspector视窗出现Prefab

    --[Select]:点击Select可以选中创建该物体的预设体

    --[Revert]:更改实例化后的游戏物体,点击Revert,会取消更改

    --[Apply]:将该对象的信息同步到预设体,使用该预设体实例化的其他游戏对象也随之改变

     

    ++预制体的使用

    ++++立钻哥哥:Instantiate(),预制体实例化

    static Object Instantiate(Object original, Vector3 position, Quaternion rotation);

    ++++[original]:预制体

    ++++[position]:位置

    ++++[rotation]:旋转

     

     

     

     

     

     

     

    #第4讲:Unity物理系统

    #第4讲:Unity物理系统

    ++++Unity企业内训(第4讲)https://blog.csdn.net/VRunSoftYanlz/article/details/83479776

     

     

     

     

     

     

     

     

     

    ++立钻哥哥推荐的拓展学习链接(Link_Url)

    立钻哥哥推荐的拓展学习链接(Link_Url)

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    ++++Unity企业内训(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82634668

    ++++Unity企业内训(第1讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82634733

    ++++Unity企业内训(第2讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82861180

    ++++Unity企业内训(第3讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82927699

    ++++VR实验:以太网帧的构成https://blog.csdn.net/VRunSoftYanlz/article/details/82598140

    ++++FrameVR示例V0913https://blog.csdn.net/VRunSoftYanlz/article/details/82808498

    ++++计算机组成原理(教材篇)https://blog.csdn.net/VRunSoftYanlz/article/details/82719129

    ++++HTC_VIVE开发基础https://blog.csdn.net/VRunSoftYanlz/article/details/81989970

    ++++Oculus杂谈https://blog.csdn.net/VRunSoftYanlz/article/details/82469850

    ++++Oculus安装使用https://blog.csdn.net/VRunSoftYanlz/article/details/82718982

    ++++VRTK杂谈https://blog.csdn.net/VRunSoftYanlz/article/details/82562993

    ++++VRTK代码结构(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82780085

    ++++VRTK(SceneResources)https://blog.csdn.net/VRunSoftYanlz/article/details/82795400

    ++++Unity5.x用户手册https://blog.csdn.net/VRunSoftYanlz/article/details/81712741

    ++++Unity面试题ABChttps://blog.csdn.net/vrunsoftyanlz/article/details/78630687

    ++++Unity面试题Dhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630838

    ++++Unity面试题Ehttps://blog.csdn.net/vrunsoftyanlz/article/details/78630913

    ++++Unity面试题Fhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630945

    ++++Cocos2dx面试题https://blog.csdn.net/VRunSoftYanlz/article/details/78630967

    ++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818

    ++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502

    ++++Lua快速入门篇(基础概述)https://blog.csdn.net/VRunSoftYanlz/article/details/81041359

    ++++框架知识点https://blog.csdn.net/VRunSoftYanlz/article/details/80862879

    ++++游戏框架(UI框架夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80781140

    ++++游戏框架(初探篇)https://blog.csdn.net/VRunSoftYanlz/article/details/80630325

    ++++设计模式简单整理https://blog.csdn.net/vrunsoftyanlz/article/details/79839641

    ++++专题:设计模式(精华篇)https://blog.csdn.net/VRunSoftYanlz/article/details/81322678

    ++++U3D小项目参考https://blog.csdn.net/vrunsoftyanlz/article/details/80141811

    ++++Unity案例(Vehicle)https://blog.csdn.net/VRunSoftYanlz/article/details/82355876

    ++++UML类图https://blog.csdn.net/vrunsoftyanlz/article/details/80289461

    ++++Unity知识点0001https://blog.csdn.net/vrunsoftyanlz/article/details/80302012

    ++++Unity知识点0008https://blog.csdn.net/VRunSoftYanlz/article/details/81153606

    ++++U3D_Shader编程(第一篇:快速入门篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372071

    ++++U3D_Shader编程(第二篇:基础夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372628

    ++++Unity引擎基础https://blog.csdn.net/vrunsoftyanlz/article/details/78881685

    ++++Unity面向组件开发https://blog.csdn.net/vrunsoftyanlz/article/details/78881752

    ++++Unity物理系统https://blog.csdn.net/vrunsoftyanlz/article/details/78881879

    ++++Unity2D平台开发https://blog.csdn.net/vrunsoftyanlz/article/details/78882034

    ++++UGUI基础https://blog.csdn.net/vrunsoftyanlz/article/details/78884693

    ++++UGUI进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78884882

    ++++UGUI综合https://blog.csdn.net/vrunsoftyanlz/article/details/78885013

    ++++Unity动画系统基础https://blog.csdn.net/vrunsoftyanlz/article/details/78886068

    ++++Unity动画系统进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78886198

    ++++Navigation导航系统https://blog.csdn.net/vrunsoftyanlz/article/details/78886281

    ++++Unity特效渲染https://blog.csdn.net/vrunsoftyanlz/article/details/78886403

    ++++Unity数据存储https://blog.csdn.net/vrunsoftyanlz/article/details/79251273

    ++++Unity中Sqlite数据库https://blog.csdn.net/vrunsoftyanlz/article/details/79254162

    ++++WWW类和协程https://blog.csdn.net/vrunsoftyanlz/article/details/79254559

    ++++Unity网络https://blog.csdn.net/vrunsoftyanlz/article/details/79254902

    ++++C#事件https://blog.csdn.net/vrunsoftyanlz/article/details/78631267

    ++++C#委托https://blog.csdn.net/vrunsoftyanlz/article/details/78631183

    ++++C#集合https://blog.csdn.net/vrunsoftyanlz/article/details/78631175

    ++++C#泛型https://blog.csdn.net/vrunsoftyanlz/article/details/78631141

    ++++C#接口https://blog.csdn.net/vrunsoftyanlz/article/details/78631122

    ++++C#静态类https://blog.csdn.net/vrunsoftyanlz/article/details/78630979

    ++++C#中System.String类https://blog.csdn.net/vrunsoftyanlz/article/details/78630945

    ++++C#数据类型https://blog.csdn.net/vrunsoftyanlz/article/details/78630913

    ++++Unity3D默认的快捷键https://blog.csdn.net/vrunsoftyanlz/article/details/78630838

    ++++游戏相关缩写https://blog.csdn.net/vrunsoftyanlz/article/details/78630687

    ++++UnityAPI.Rigidbody刚体https://blog.csdn.net/VRunSoftYanlz/article/details/81784053

    ++++UnityAPI.Material材质https://blog.csdn.net/VRunSoftYanlz/article/details/81814303

    ++++UnityAPI.Android安卓https://blog.csdn.net/VRunSoftYanlz/article/details/81843193

    ++++UnityAPI.AndroidJNI安卓JNIhttps://blog.csdn.net/VRunSoftYanlz/article/details/81879345

    ++++UnityAPI.Transform变换https://blog.csdn.net/VRunSoftYanlz/article/details/81916293

    ++++UnityAPI.WheelCollider轮碰撞器https://blog.csdn.net/VRunSoftYanlz/article/details/82356217

    ++++JSON数据结构https://blog.csdn.net/VRunSoftYanlz/article/details/82026644

    ++++CocosStudio快速入门https://blog.csdn.net/VRunSoftYanlz/article/details/82356839

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    --_--VRunSoft:lovezuanzuan--_--

    展开全文
  • ET框架是一个十分强大的可以实现全热更的开源双端游戏框架,对于笔者这种人来说,简直就是量身打造,纯C#开发爽的不要不要的。就目前来看,ET框架已经相对稳定,猫大还在不断更新中,但是网上相关资料与技术博客还是...
  • 面向组件编程Unity 怎样获取脚本所在物体的各种组件,例如:transform/BoxCollider
  • Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d面向组建开发的一款游戏引擎。通过一张图片来看看它的属性 你可以在通过代码查看这些属性的区别 Debug.Log("...
  • 哈哈,昨晚弄清楚了U3D的组件到底是怎么个机制,今天中午就通过写博客来梳理一遍吧!1、首先,一个游戏之中会有很多的游戏场景(Scene),游戏场景中有很多的游戏物体(GameObject),包括摄像机、灯光、立方体等。...
  • 在实践中,发现面向组件,状态机,消息驱动。如果整合起来的模型,能够更为自然和简单的进行抽象。当然这些都是以面向对象为基础,更进一步的抽象扩展。本文,先会分别介绍一下,面向组件,状态机,消息驱动的各自...
  • 本书是国内第一本以面向对象和项目流程开发角度,全面系统介绍 Unity3D 的书籍。 本书以具体项目结构开发的角度,结合 Unity3D 层级式的综合开发环境、视觉化编辑、详 细的属性编辑器和动态的游戏预览的特点,在软件...
  •  为了更好地理解游戏的软件架构和对象模型,它获得更好的外观仅有一名Unity3D的游戏引擎和编辑器是非常有用的,它的主要原则。 Unity3D 引擎  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个...
  •  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个platforms.Unity3D由游戏引擎和编辑器。该引擎包含的软件组件,在游戏的研究与开发中最常见的和经常性的任务。发动机所涵盖的主题包括声音,图
  •  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个platforms.Unity3D由游戏引擎和编辑器。该引擎包含的软件组件,在游戏的研究与开发中最常见的和经常性的任务。发动机所涵盖的主题包括
  • Unity3D架构小结

    2019-05-01 15:31:56
    版权声明:本文为博主原创文章...一直以来,我都是使用基于类的面向对象编程,当转到Unity开发后,发现所有的代码都是拖到一个个组件上面去的,早已习惯了的mvc,mvp等架构思想在Unity上却不太适用了。 所以在我前...
  • 对于编程零基础小白来说,Unity3D游戏开发真的是高深到无法踏足的领域吗?我认为并不是这样的。 按照我个人的理解:其实Unity本身并不是一种体系,而是计算机图形学+游戏开发+各种其他系统的一种表现。学习进阶游戏...
  • Unity3D 体系

    2016-07-04 11:56:13
     Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个platforms.Unity3D由游戏引擎和编辑器。该引擎包含的软件组件,在游戏的研究与开发中最常见的和经常性的任务。发动机所涵盖的主题包括
1 2 3 4 5 ... 20
收藏数 1,636
精华内容 654