Unity面向组件开发
##1、Unity组件开发
++1.1、工程与应用程序
++++新创建的Unity工程,在其目录文件夹中包含4个文件夹。
-- Assets: 里面存放的是项目所需要的资源;
-- Library: 里面存放的是所需要的库文件;
-- ProjectSettings: 里面存放的是工程设置文件;
-- Temp: 里面存放的是临时文件;
++1.2、Unity工程开发框架
++++工程,场景,游戏对象和组件的关系
-- 一个工程里面有多个场景,相当于一个游戏有多个关卡;
-- 一个场景里面有多个游戏对象,相当于游戏中的不同元素;
-- 每个游戏对象又有一个或者多个组件,游戏对象想要实现什么样的功能只需要加上相对应的组件即可;
++1.3、Unity面向组件开发思想
++++Unity面向组件开发,游戏物体想要实现什么样的功能,只需要添加相对应的组件即可,此时会在Inspector面板中显示出来,一些属性值可以可视化的更改。
-- Transform组件,决定物体的位置,旋转和缩放。
-- Mesh Filter组件,选择网格。
-- Box Collider组件,用来给物体添加碰撞器。
-- Mesh Renderer组件,可以给物体添加材质,纹理以及渲染的方式。
++1.4、脚本组件的使用
++++脚本组件开发工具
-- Unity自带脚本编辑器,创建Mono应用程序,适用于Linux、Mac OS X和Windows的继承开发环境,支持C#、BOO和JavaScript等高级编程语言。
-- 微软公司的开发工具包,包括了整个软件生命周期中需要的大部分工具,如团队开发工具、集成开发环境等等。
-- 在Unity中通过菜单设置修改默认的脚本编辑器: 【Edit】=>【Preferences】=>【External Tools】=>【External Script Editor】
++++脚本组件
-- 脚本是一种特殊的组件,它用于添加到游戏对象上以实现用户自定义的一些功能。
++++脚本的创建
-- 在Project视窗Asset文件夹中点击右键,创建C#脚本,然后把创建的脚本拖到游戏物体上即可。
++++脚本的使用
-- 双击创建的脚本组件,即可打开脚本
using UnityEngine;
using System.Collections;
pulbic class CubeScript : MonoBehaviour{
//注:类名与脚本组件名一致,并自动的继承MonoBehaviour类,类名与脚本名不一样会出错。
}
++2、Unity脚本组件
++2.1、Unity脚本类
++++Unity中的常用脚本类就可以简单的分成如下四大类:
Unity脚本类 --宏观控制类
-- 游戏对象类
-- 组件类
-- 资源类
++++宏观控制类: 主要作用是针对Unity程序中的某一方面进行宏观控制。包括应用程序类(Application)、输入类(Input)、图形输出类(GUI)、物理引擎类(Physics)、资源类(Resources)、时间类(Time)等。
++++游戏对象(GameObject)类: 表示当前脚本挂在的游戏对象。
++++组件(Component)类: 脚本开发中的组件类往往可以和图形界面界面中的检视面板对应起来。 每一个游戏对象的细节设置与操控都需要借助组件类来完成。
++++资源类: 资源一般都是在图形界面导入进来之后直接使用。
++2.2、MonoBehaviour类
++++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、常用类
API(Application Programming Interface)应用程序编程接口,是一些预先定义的函数。Unity引擎提供了丰富的组件和类库,为开发者提供了非常大的便利,熟练掌握和使用这些API对于游戏开发效率提高很重要。
++3.1、Component类
++++gameObject :组件附加的游戏对象。组件总是被附加到游戏对象上。
++++transform :附加到此游戏对象Transform组件(如果没有则为空)。
++++tag :此游戏对象的标签。
++++collider :附加到此游戏对象的Collider(如无附加则为空)。
++++renderer :附加到此游戏对象Renderer组件(如果没有则为空)。
++++rigidbody :附加到此游戏对象Rigidbody组件(如果没有则为空)。
++++GetComponent :如果游戏对象有附加type类型的组件,则返回,如果没有则为空。
++++GetComponentInChildren :返回此游戏对象上type类型的组件或任何它的子对象,使用深度首先搜索。
++++GetComponents :返回此对象type类型的所有组件。
++++GetComponentsInChildren :返回此游戏对象与其子对象所有type类型的组件。
++3.2、GameObject类
++++脚本中得到游戏对象
-- 通过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.3、Transform类
++++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.4、Vector3类
++++点乘
又称“点积”或“内积”。
公式:各分量乘积和 [x1,y1,z1]*[x2,y2,z2] = x1x2 + y1y2 + z1z2
几何意义: a*b = |a|*|b|cos<a,b> 两个向量的单位向量相乘后再乘以二者夹角的余弦值。
API: float 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.5、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.6、Time类
++++time :从游戏开始到现在所用的时间(只读)
++++deltaTime :获取上一次Update()方法执行的时间到本次执行Update()方法时间的差值
++++fixedDeltaTime :在物理和其他固定帧速率进行更新上一帧所消耗的时间,以秒计算
++++timeScale :表示事件缩放,正常时间为1
++3.7、Mathf类
++++在C#脚本中,Mathf是封装了常见数学计算方法的结构体。
--Lerp :两个浮点数之间进行插值
--Clamp :返回一个限制值
--Sin :计算并返回浮点型的正弦值
--Cos :计算并返回浮点型的余弦值
--Abs :计算并返回指定参数的绝对值
--Max :返回两个值之中最大的值
--Min :返回两个值之中最小的值
--Sqr :返回平方根
--PI :圆周率
++拓展1:《Translate》
++++(1)Space.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);
移动方向为(单向量):目标在世界坐标系的方向向量
++++(2)Space.world
同理
++拓展2:《理解Gameobject, gameObject, Transform, transform的区别和关联》
++++1)GameObject与gameObject
--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>(),也是可以的。
++++2)Transform与transform
--Transform是一个类,用来描述物体的位置,大小,选择等等信息。
--transform是Transform类的对象,依附于每一个物体。也是当前游戏对象的一个组件(每个对象都会有这个组件)
++++transform与gameObject
--1>二者的含义
---transform: 当前游戏对象的transform组件
---gameObject: 当前游戏对象的实例
--2>二者的联系和区别
---在unity中每个游戏对象都是一个gameObject,monodevelop中的gameObject就代表着本脚本所依附的对象。 每个gameObject都包含各种各种的组件,但从这点可以看出transform是gameObject的一个组件,控制着gameObject的位置,缩放和旋转,而且每个gemeObject都有而且必有一个transform组件。
---gameObject.Find()用来获取场景中那个我们需要查找的对象(object),而transform.Find()方法则是获取当前对象的子对象下我们需要获取的目标对象位置信息。
---注意:在update()中尽量不适用find()方法,影响性能。
--3>gameObject.transform与transform.gameObject
---gameObject.transform,是获取当前游戏对象的transform组件。
所以在start函数中gameObject.transform和this.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 在from到to之间插值。
++++举例:
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.time从0趋向于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是目标位置,按照数字t在from到to之间插值
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和向量to在xy平面上,其实这并不影响讲解插值原理。
++++图中可以看出当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,返回from和to的平均数。
--具体实现代码如下:
/*
Summary:两个向量之间的线性插值
Param: from,向量from,to,向量to,t
*/
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()中,希望通过每隔一段时间去执行一些逻辑(比如最常见的修改GameObject的Transform),就需要使用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之后就好了呢?
---Transform的Translate方法接受的参数,实际上是一个唯一,而不是速度。
---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+bi,i是虚数部分)
++++在Unity里,transform组件有一个变量名为rotation,它的类型就是四元数。(实际上,四元数的x,y,z和R的三个值从直观上来讲没什么关系,当然会存在一个表达式可以转换)
++++三种旋转方式(矩阵旋转、欧拉旋转、四元数旋转)的优缺点:
--矩阵旋转
---优点:
----旋转轴可以是任意向量;
---缺点:
----旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素。
----而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费。
--欧拉旋转
---优点:
----很容易理解,形象直观;
----表示更方便,只需要3个值(分别对应x,y,z轴的旋转角度);(?它还是转换到了3额3*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:《多种移动方式参考》
++++1、transform.position
transform.position += Vector3.forward * Time.deltaTime * 5;
++++2、Translate:
transform.Translate(Vector3.forward * 5 * Time.deltaTime, target.transform);
++++3、Lerp:
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);
++++6、Vector3.MoveTowards();
transform.position = Vector3.MoveTowards(transform.position, target.position, 5f * Time.deltaTime);
++++7、SmoothDamp();
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知识点0001:https://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--_--