unity3d中面向组件 - CSDN
  • 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--_--

    展开全文
  • unity3d中Transform组件 Rotate()和rotation变量详解

    万次阅读 多人点赞 2018-03-26 09:48:47
    Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d面向组建开发的一款游戏引擎。通过一张图片来看看它的属性 你可以在通过代码查看这些属性的区别 Debug.Log("...

    Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d是面向组建开发的一款游戏引擎。通过一张图片来看看它的属性

     

     

     你可以在通过代码查看这些属性的区别

    复制代码
            Debug.Log("position " + transform.position); //世界坐标的位置
            Debug.Log("localPosition " + transform.localPosition); //相对于父位置的坐标 即把父物体当作自己的中心
    
            Debug.Log("eulerAngles " + transform.eulerAngles);//世界坐标欧拉⾓度
    
            Debug.Log("localEulerAngles " + transform.localEulerAngles);//相对于⽗级的变换的旋转欧拉⾓度
    
            Debug.Log("localScale " + transform.localScale);//相对于父位置的缩放
    
            Debug.Log("localRotation " + transform.localRotation);//相对于父位置的旋转
    
            Debug.Log("rotation " + transform.rotation);//世界坐标的旋转
    复制代码

     

     

    上面提到了父位置?那是什么意思呢?

    现在创建两个cube 命名为cube1和cube2 把cube2作为cube1的子对象,如图。

     

    可以看到,cube1的坐标(1,0,0) cube2的坐标为(0,0,5)

    那么通过transform.localPosition获取cube2的坐标则为(0,0,5)

    如果用transform.position获取cube2的坐标则为(1,0,5)

    那么写个脚本测试下。写个脚本挂载到cube2上

    在脚本的Start方法中如下写

    void Start()
        {
            Debug.Log("cube2的世界坐标为:" + transform.position);
            Debug.Log("cube2的本地坐标为:" + transform.localPosition);
        }

     

     

    运行后看结果

    因为:cube2把父对象(Cube1)当作了自己的的中心。所以是(0,0,5),那它的世界坐标则为(1,0,5),知道了这个position那localRotation也是同样的道理

    但有没有注意到。这里的欧拉角(eulerAngles),rotation和Rotate(),都是用于旋转,那他们有什么区别呢。刚开始我也是犯糊涂

    Rotate()方法需要一个vector3三维向量,rotation是用四元素旋转(Quaternion)

    来看看圣典上面的解释:

     

     

     

     

     欧拉角(eulerAngles)旋转很好理解。当你改变Transform组建中的 x,y,z的角度。就是改变其欧拉角

    现在来看看rotation属性和Rotate()方法之间有什么区别

    我认为通过测试是对两者差异的最好理解。

    先看Rotate()方法

    在场景中创建一个Capsule,写个脚本。代码如下

    复制代码
    void Update()
        {
           
            transform.Rotate(Vector3.up  * 5);
    
        }
    复制代码

     

     

     运行看看效果:

    可以看到对象是旋转一直是在累加5,如果你感觉不出来。我这里调试。一帧一帧给你看

     

    然后用旋转同样的角度。测试rotation属性

    复制代码
        void Update()
        {
    
            transform.rotation = Quaternion.Euler(Vector3.up  * 5);
    
        }
    复制代码

     

     

     同样看效果

     

     从上图可以看出,Capsule旋转到5就不动了。也就是每次旋转都是同样的值,

    所以:我的理解是:

    Rotate()方法是:旋转多少度。在原有的基础上累加,即旋转了多少角度。又旋转了多少角度,是在原有的基础上在旋转

    rotation属性是:旋转到某个角度,就是是在update中每帧都执行(我这里测试是放在了update中)。但每次旋转到的角度动是5,所以是旋转到5度。一直都是

    比如你只想让他旋转到多少,用rotation;假如想让他一直转,可以用Rotate

    rotation直接改变了数值,以达到旋转效果

    Rotate应用一个的旋转角度每秒1度慢慢的旋转物体

     

    当然:rotation()还可以通过插值旋转,

    关于插值的理解:

    http://www.unitymanual.com/blog-42778-2524.html?_dsign=7036aadd

    展开全文
  • Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d面向组建开发的一款游戏引擎。通过一张图片来看看它的属性 你可以在通过代码查看这些属性的区别 Debug...

    Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d是面向组建开发的一款游戏引擎。通过一张图片来看看它的属性

     

     

     你可以在通过代码查看这些属性的区别

            Debug.Log("position " + transform.position); //世界坐标的位置
            Debug.Log("localPosition " + transform.localPosition); //相对于父位置的坐标 即把父物体当作自己的中心
    
            Debug.Log("eulerAngles " + transform.eulerAngles);//世界坐标欧拉⾓度
    
            Debug.Log("localEulerAngles " + transform.localEulerAngles);//相对于⽗级的变换的旋转欧拉⾓度
    
            Debug.Log("localScale " + transform.localScale);//相对于父位置的缩放
    
            Debug.Log("localRotation " + transform.localRotation);//相对于父位置的旋转
    
            Debug.Log("rotation " + transform.rotation);//世界坐标的旋转

     

     

    上面提到了父位置?那是什么意思呢?

    现在创建两个cube 命名为cube1和cube2 把cube2作为cube1的子对象,如图。

     

    可以看到,cube1的坐标(1,0,0) cube2的坐标为(0,0,5)

    那么通过transform.localPosition获取cube2的坐标则为(0,0,5)

    如果用transform.position获取cube2的坐标则为(1,0,5)

    那么写个脚本测试下。写个脚本挂载到cube2上

    在脚本的Start方法中如下写

    void Start()
        {
            Debug.Log("cube2的世界坐标为:" + transform.position);
            Debug.Log("cube2的本地坐标为:" + transform.localPosition);
        }

     

     

    运行后看结果

    因为:cube2把父对象(Cube1)当作了自己的的中心。所以是(0,0,5),那它的世界坐标则为(1,0,5),知道了这个position那localRotation也是同样的道理

    但有没有注意到。这里的欧拉角(eulerAngles),rotation和Rotate(),都是用于旋转,那他们有什么区别呢。刚开始我也是犯糊涂

    Rotate()方法需要一个vector3三维向量,rotation是用四元素旋转(Quaternion)

    来看看圣典上面的解释:

     

     

     

     

     欧拉角(eulerAngles)旋转很好理解。当你改变Transform组建中的 x,y,z的角度。就是改变其欧拉角

    现在来看看rotation属性和Rotate()方法之间有什么区别

    我认为通过测试是对两者差异的最好理解。

    先看Rotate()方法

    在场景中创建一个Capsule,写个脚本。代码如下

    void Update()
        {
           
            transform.Rotate(Vector3.up  * 5);
    
        }

     

     

     运行看看效果:

    可以看到对象是旋转一直是在累加5,如果你感觉不出来。我这里调试。一帧一帧给你看

     

    然后用旋转同样的角度。测试rotation属性

        void Update()
        {
    
            transform.rotation = Quaternion.Euler(Vector3.up  * 5);
    
        }

     

     

     同样看效果

     

     从上图可以看出,Capsule旋转到5就不动了。也就是每次旋转都是同样的值,

    所以:我的理解是:

    Rotate()方法是:旋转多少度。在原有的基础上累加,即旋转了多少角度。又旋转了多少角度,是在原有的基础上在旋转

    rotation属性是:旋转到某个角度,就是是在update中每帧都执行(我这里测试是放在了update中)。但每次旋转到的角度动是5,所以是旋转到5度。一直都是

    比如你只想让他旋转到多少,用rotation;假如想让他一直转,可以用Rotate

    rotation直接改变了数值,以达到旋转效果

    Rotate应用一个的旋转角度每秒1度慢慢的旋转物体

     

    当然:rotation()还可以通过插值旋转,

    关于插值的理解:

    http://www.unitymanual.com/blog-42778-2524.html?_dsign=7036aadd

     

    转载于:https://www.cnblogs.com/nsky/p/4581668.html

    展开全文
  • Unity3DUnity3D LineRender组件的研究

    千次阅读 2020-03-09 13:53:26
    Unity3D研究院之游戏对象的访问绘制线与绘制面详解(十七) 前言 发现网上很多教程都是如何用LineRender组件画线,但是这个组件还有很多其他的功能属性也是很有趣的,下面就让我们来看看吧 用途 LineRender组件...

    ##参考文章
    Unity3D研究院之游戏对象的访问绘制线与绘制面详解(十七)

    ##前言
    发现网上很多教程都是如何用LineRender组件画线,但是这个组件还有很多其他的功能属性也是很有趣的,下面就让我们来看看吧

    ##用途
    LineRender组件主要的用途就是画线,将这个组件加载到对象上,然后设置路径,跟线的材质,就能在Game视图下显示线段了。

    ##画线
    要了解在Unity中的画线方式,可以参考我另一篇文章
    https://blog.csdn.net/q764424567/article/details/78630798

    ##使用LineRender画线

    • 在一个对象上加上LineRender组件

    这里写图片描述

    • 附上材质Materials

    这里写图片描述

    • 设置一下路径Positions

    这里写图片描述

    • 效果就是这个样子的

    这里写图片描述

    ##LineRender组件的属性

    • Cast Shadows
      投影,可以选择
      On 开
      Off 关
      Two Sided两个侧面
      Shadows Only只显示阴影

    • Recevice Shadows
      接收阴影效果

    • Motion Vectors
      移动的轨迹
      Camera Motion Only 只有相机移动
      Per Object Motion 每一个对象移动也会跟着移动
      Force No Motion强制移动

    • Materials
      可以设置线段的材质,可以设置成一个纯色材质,像这样的
      这里写图片描述
      也可以制作一个带透明的箭头
      这里写图片描述
      这里写图片描述
      这张图片也上传上来吧
      这里写图片描述
      这张是没有水印的
      https://pan.baidu.com/s/165kbJjzorUOeMMt0GJN_qA
      注意导入图片的格式设置成下面这样
      这里写图片描述
      不然可能效果显示不出来

    • Lightmap Parameters
      这个的话就是可以用自己的光照参数
      这里写图片描述

    • Positions
      路径设置,这个可以用代码控制

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    public class nav : MonoBehaviour
    {
        private NavMeshAgent m_Agent;
        public GameObject m_Target;
        private LineRenderer m_LineRender;
        // Use this for initialization
        void Start()
        {
            m_Agent = GetComponent<NavMeshAgent>();
            m_LineRender = GetComponent<LineRenderer>();
            //m_Agent.SetDestination(m_Target.transform.position);
        }
    
        // Update is called once per frame
        void Update()
        {
            //设置目标点
            m_Agent.SetDestination(m_Target.transform.position);
            //储存路径
            Vector3[] path = m_Agent.path.corners;
            //设置顶点的数量
            m_LineRender.positionCount = path.Length;
            //设置线段
            for (int i = 0; i < path.Length; i++)
            {
                m_LineRender.SetPositions(path);
            }
        }
    }
    
    
    • Use World Space
      就是使用世界坐标系还是使用自身坐标系

    • Loop
      重复

    • Width
      设置线段的宽细

    • Color
      设置线段的颜色,可以影响到材质

    • Corner Vertices
      角顶点,就是转弯的点有几个,这个可以不用设置

    • End Cap Vertices
      后盖顶点

    • Alignment
      对齐方式,Local本地,就是根据自身的坐标系对齐,View视图对齐

    • Texture Mode
      材质模式

    • Light Probes
      灯光探针

    • Reflection Probes
      反射探针

    展开全文
  • Transform组件是每个游戏对象必须有的一个组建,因为你创建一个空物体,它也有该组建,因为unity3d面向组建开发的一款游戏引擎。通过一张图片来看看它的属性。 你可以在通过代码查看这些属性的区别 Debug....
  • 今天呢,我们来说说Unity3D中的角色控制,这篇文章并非关注于Unity3D中的某项具体内容,而是博主在经过大量的实践后所得的感悟。今天的文章从内容上可以分为2种模式、1个组件、1种模型,希望对大家学习Unity3D起到...
  • Unity3d 引擎原理详细介绍

    万次阅读 2014-03-25 13:22:52
     为了更好地理解游戏的软件架构和对象模型,它获得更好的外观仅有一名Unity3D的游戏引擎和编辑器是非常有用的,它的主要原则。 Unity3D 引擎  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个...
  • 最近看了一个Unity3d官网的Native 2d的一个Demo,发现Unity3d是一个纯面向对象的游戏引擎, 面向对象的程度,让我惊叹。 正常的,对象之间完全是独立工作,比如一个普通的ARPG游戏,一个人物拥有武器,可以攻击...
  • 本书是国内第一本以面向对象和项目流程开发角度,全面系统介绍 Unity3D 的书籍。 本书以具体项目结构开发的角度,结合 Unity3D 层级式的综合开发环境、视觉化编辑、详 细的属性编辑器和动态的游戏预览的特点,在软件...
  • 就目前来看,ET框架已经相对稳定,猫大还在不断更新,但是网上相关资料与技术博客还是很少,主要还是靠自己摸索,边用边琢磨;公司的游戏项目正是采用的ET框架开发,目前已经上线一个月;笔者使用ET的时间也不长,...
  • Unity 的Transform组件

    千次阅读 2017-08-01 19:44:14
    Transform组件是每个游戏对象必有的一个组件,因为Unity 3D面向组件开发的一款游戏引擎,这个组件掌管了游戏对象在三维空间的位置,旋转,缩放等。 Transform常用属性: position 在世界坐标...
  • 关于Unity 2018的实体组件系统(ECS)一

    万次阅读 多人点赞 2018-07-18 14:30:34
    孙广东 2018.5.19     首先来自ECS的概念。... 其模式遵循组合优于继承原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有...
  • Unity的开发模式核心:节点和组件组件可以加载到任何节点上,每个组件都有 gameobject 属性,可以通过这个属性获取到该节点,即游戏物体。 也就是说游戏物体由节点和组件构成,每个组件表示物体的一种特性(能力)...
  • 在使用unity3d之前,我已经知道组件设计的概念,我们某个项目实际上也是基于组件的,虽然底层引擎只是设计了一个最简单的组件框架,遗憾的是其他部分,并没有按照多少组件的意思来组织代码.这个组件失败的地方在于,没有...
  •  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个platforms.Unity3D由游戏引擎和编辑器。该引擎包含的软件组件,在游戏的研究与开发最常见的和经常性的任务。发动机所涵盖的主题包括声音,图形,
  • 最近看了看一个C#游戏开发的公开课,在该公开课使用面向对象思想与Unity3D游戏开发思想结合的方式,对一个简单的赛车游戏场景进行了实现。原本在C#很方便地就可以完成的一个小场景,使用Unity3D的设计思想(即...
  • 作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分系列文章的前言,然后第二部分介绍了这个系列文章我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity创建和使用Shader,为后面...
1 2 3 4 5 ... 20
收藏数 2,468
精华内容 987
热门标签
关键字:

unity3d中面向组件