Unity3D中C#的类型系统

第三章 Unity脚本语言的类型系统
3.1C#的类型系统
  1. C#的类型系统时静态、安全、并且在大多数时候是显示的。
  2. C#要求其所有类型全部从System.Object类派生,MonoBehaviour显然也是派生自System.Object
  3. 因为所有的类型都派生自System.Object,因此所有的类型都保证了拥有了一套最基本的方法,即System.Object所声明的方法:4个公共和2个受保护方法。
(1)Equals:若两个对象具有相同的值,则返回true,否则返回false
(2)GetHashCode:返回对象的值的哈希码
(3)ToString:默认返回类型的完整名称,即this.GetType().FullName。但是此方法经常被重写,最典型的例子就是int型等重写该方法以返回其值的字符串形式。
(4)GetType:返回一个从Type类派生的类型实例,以指出调用GetType方法的对象是什么类型。常用于为反射提供与对象类型有关的元数据信息。
(5)MemberwiseCone.
(6)Finalize:虚方法,在对象被标志为应该被作为垃圾回收之后,但在内存真正被收回之前,会调用该方法。因此,如果需要在回收内存前执行清理工作的类型应该重写该方法。

一、C#语言是静态类型
显示类型:便是声明变量时必须显式指定类型。
隐式类型:是指在变量声明的时候不指明其类型,而是允许编译器根据变量的用途来推断变量的类型,但在编译时变量的类型仍然是确定的,也就是说该变量仍然是静态类型的。
在C#3中引入了关键字 var 来表示隐式类型,声明局部变量时使用 var ,表示编译器在编译时需要对该变量进行类型推断。

C#3 仍然是静态语言。虽然作为开发者可以使用var 来简化自己的开发流程,但是在编译器编译的阶段使用var 声明的变量的类型,其实是已经确定好的,只不过这个类型是由编译器推断出的。
所以隐式类型仍然是静态类型
二、C#语言是类型安全的
C#语言是类型安全的,其本质是有关类型操作的一种规范,进不能将一种类型当作另一种类型,除非它们真的存在转换关系。
在C#中,将对象转换为它的实际类型或它的任何基类,可以认为是一种安全的隐式转换,无须任何特殊的语法处理,若要将对象转换成它的某个派生类的话,则要使用显示转换以提供足够的信息给编译器。
3.2C#值类型和引用类型
引用类型总是从托管堆分配,C#要求所有的对象都使用new 操作符创建。new操作 符返回指向对象数据的内存地址。
关于引用类型总结以下4点:
(1)存储引用类型对象的内存空间须从托管堆上分配。
(2)每一个对象都有一些额外的成员为Mono运行时提供操作该对象的信息,因而堆上分配空间时也要考虑到这些成员的空间,同时这些成员必须被初始化。
(3)对象中的其他字段的字节总是0.
(4)由于并没有一个和new操作符相对应的delete操作符存在,因而对象的回收工作主要由垃圾回收机制,也就是GC来处理。那么显而易见的是当为新的对象分配空间时,有可能会面临没有空间可用的情况,那么就会触发垃圾回收。

值类型与引用类型的区别:
值类型的变量直接包含值。也就是说将一个值类型变量赋给另一个值类型变量时,将复制其包含的值。
引用类型变量的赋值只复制对象的引用,不复制对象本身。
值类型的优势优势体现在提上日常开发中常用的、简单的类型的性能。

用Class、Interface、Delegate关键字声明的类型是引用类型
C#中内建的引用类型:Dynamic、Object、String

值类型大体上分为结构和枚举类型两类:
int 、float、Decimal、double、bool、用户自定义的结构、枚举enum。值类型派生与System.ValueType,而System.ValueType本身又派生自System.Object,

值类型的几个特征:
(1)值类型不派生出其他任何类型
(2)值类型不需要从其他类型派生
(3)值类型是不可变的
但String类型也是不可变的,但是它是引用类型。
(4)值类型的传递方式以值的方式。就是说值类型变量在进行传递时,会对值传递实例中的字段进行复制
(5)值类型实例有两种表示方式,分别是未装箱和已装箱。装箱机制是指将值类型转换为引用类型。拆箱就是将引用类型转为值类型。
(6)值类型派生自System.ValueType,,而System.ValueType本身又派生自System.Object,System.ValueType重写了Equals方法和GetHashCode方法。

如何选择值类型而不是引用类型:
1、类型的实例较小时
2、类型的实例较大时,不会作为方法的实参进行传递,或作为方法的返回值返回。
3、由于值类型不能作为基类型来派生新的值类型或引用类型,因此目标类型中不能引入新的虚方法,以及所有的方法都不能是抽象的,最后所有方法都是隐式密封
3.3 Unity3D脚本语言中的引用类型

Unity3D中使用 UnityEngine命名空间来盛放Unity3D自己定义的类型。
UnityEngine.Object类是Unity3D游戏引擎的C#脚本语言中最基本的类,也就是在Unity3D中所有对象的基类 。

UnityEngine.MonoBehaviour类

UnityEngine.Behaviour类处在UnityEngine.MonoBehaviour类和 UnityEngine.Component类之间的一个类,UnityEngine.Behaviour类是一个可以启用(enable)或禁止(disable)的组件,有两个变量enabled和isActiveAndEnabled
UnityEngine.MonoBehaviour类的成员有

特别注意的一点是,不同于平常的C#代码,所有的引用类型使用关键字new来实例化,在Unity3D的脚本语言中凡是继承MonoBehaviour类的类型或MonoBehaviour本身都无法使用new关键字来实例化。
当然,如果是不需要继承MonoBehaviour类型的类,是可以使用new关键字直接创建新的对象的。

Unity3D脚本中执行顺序:
1、编辑器阶段
Reset方法:当脚本第一次添加到游戏对象或当执行Reset命令时会调用Reset方法,用来初始化脚本的各个属性.
2、场景第一次加载阶段
Awake()方法:在Start方法之前调用。换句话说,就是在prefab(预设)刚刚实例化之后便调用该方法。
OnEnable()方法,这个函数在对象可用之后被调用,仅在对象激活时可以用,
场景中所有游戏对象身上的Awake方法和OnEnable方法会在所有的Start、Update等方法之前调用。
3、第一帧更新之前的阶段
就是在Awake之后、Update之前,Unity3D脚本会调用Start方法。
Start()方法:在第一帧更新之前调用。
Start()方法会在所有脚本中的Update()方法之前调用。

Awake()、OnEnable()、Start()三个方法完成了一个Unity3D脚本的初始化工作。
4、执行阶段
该阶段就是当前帧执行完毕,需要开始执行下一帧的阶段。在该阶段可能被触发的事件方法是OnApplicationPause()方法。
OnApplicationPause()方法:当检测到暂停状态时,会在当前帧结束之后调用该方法。
5、更新顺序
Update()方法:每一帧都会调用,
FixedUpdate()方法:基于可靠的定时器,不受帧率的影响。因此,FixedUpdate()方法主要用来处理物理计算的相关逻辑,例如处理刚体。
LateUpdate()方法:也是每一帧都会调用,在Update()方法之后,

协程部分

协程类似多线程的功能,协程功能的实现主要利用了C#语言的迭代器。
正常情况下协程是在Update函数返回时执行的,而协程的主要功能是延缓其执行(yield),直到给定的YieldInstruction完成。
根据应用场景的不同,Unity3D游戏脚本的协程也有几种不同的使用方法。

yield:当 下一帧所有的Update方法被调用之后,协程继续执行。
yield WaitForSeconds:等待指定时间所需的帧数之后(即经过这些帧的Update方法全部被掉用过),协程继续。直观地说,协程会等待指定的时间之后继续执行。可以用来实现延时触发机制。
yield WaitForFixedUpdate:在所有脚本上的所有FixedUpdate被调用之后继续执行。
yield WWW:在WWW加载完成之后继续 执行。
yield StartCoroutine(MyFunc):用于连接协程,将等待MyFunc协程先完成。

协程属于逻辑更新的一部分,因此协程和3个更新方法共同实现驱动Unity3D游戏逻辑的更新和循环。

渲染部分

主要介绍Unity3D中场景渲染的一些时间方法,当游戏脚本被初始化完成,并且进入了正常逻辑更新周期之后,一些渲染事件有可能会调用相应的方法。
OnPreCull()方法:在相机剔除场景前辈调用。剔除取决于物体在相机中是否可见。 OnPreCull仅在剔除执行之前被调用。
OnBecameVisible和OnBecameInvisible 方法:当物体在任何相机中科健或不可见时被调用。
OnWillRenderObject()方法:如果物体可见,它将为每个摄像机调用一次。
OnPreRender()方法:在相机渲染场景之前被调用。
OnRenderObject()方法:在所有固定场景渲染之后被调用。此时可以使用GL类或者Graphics.DrawMeshNow来化自定义的几何体。
OnPostRender()方法:在相机完成场景的渲染后被调用。
OnRenderImage()方法(仅专业版可以用):在场景渲染完成后被调用,用来对屏幕的图像进行处理。
OnGUI()方法:每帧被调用,多次用来回应GUI事件。布局和重绘事件先被执行,接下来是为每一次的输入时间执行布局和键盘、鼠标事件。
OnDrawGizmos()方法:为了可视化的目的,在场景视图中绘制小图标。

3个常用的方法:OnBecameVisible和OnBecameInvisible 、OnGUI()

6、游戏对象销毁阶段
OnDestory()方法:这个方法在所有帧更新之后被调用,在对象存在的最后一帧(对象将销毁来响应Object.Destroy或关闭一个场景)

7、游戏场景退出阶段
游戏对象如果在退出当前游戏场景前未被销毁或禁用,则当收到Unity3D游戏引擎关于退出当前游戏场景的消息时,同样有对应的方法会被调用。这些方法对于场景中所有激活状态的物体都会被调用。
OnApplicationQuit()方法: 在应用退出之前所有游戏对象都会调用这个函数。在编辑器中,当用户停止播放时它将被调用。在webplayer中,当网页关闭时被调用。
OnDisable()方法:当行为不可用或非激活时,这个方法被调用。


3.4 Unity3D脚本语言中的值类型
Vector2、Vector3、Vector4
点乘积:
计算方式:a b=|a| |b|cos<a,b> 其中|a|和|b|表示向量的模,<a,b>表示两个向量的夹角,另外点乘积中,a,b时部分顺序的。
作用:可以粗咯地判断当前物体是否朝向另外一个物体,值需要计算当前物体的transform.forward向量与(target.transform.position)的点乘积即可,大于0则面对另一个物体,否则是背对着。

交叉乘积:
定义: c=a*b,其中a、b、c均为向量,即两个向量的交叉乘积得到的还是向量。
性质:1、c垂直a、b,即向量c垂直与向量a、b所在的平面。
2、模长|c|=|a||b|sin<a,b>.
3、满足右手法则,可以使用交叉乘积的正负值来判断向量a、b的相对位置,即向量b、是出于a的顺时针方向还是逆时针方向。

向量点乘和差乘的区别:


其他的值类型:Color、Color32、Ray、Touch、RaycastHit、Bounds、Rect、Plane
3.5拆箱和装箱
装箱:将值类型强制转化为引用类型
装箱步骤:
1、在托管堆中非配内存
2、将值类型的字段复制到新分配的堆内存中
3、返回对象地址,即对象的引用。值类型成了引用类型
拆箱:将引用类型转为值类型:一定注意只能转型为最初为装箱的值类型。而拆箱需要显示的指定要转型的目标类型这一,与装箱不同。























猜你喜欢

转载自blog.csdn.net/weixin_36455036/article/details/79614737