一.Unity常用事件执行顺序测试
上图解释
1.Reset():只会在editor模式下触发
2.Awake():即在脚本初始化的时候执行一次
3.OnEnable():脚本依附在GameObject上后,场景被启动时,只有在.SetActive(true)情况才会执行
4.Start():脚本开始运作执行一次
5.FixedUpdate():不受帧率的影响,按固定时间执行,常用于运动
6.Update():每一秒执行相应的次数,这里的次数即帧数,是根据硬件设备以及内部函数复杂度决定的,可能上一秒60帧,这一秒就是80帧,不唯一
7.LateUpdate():和Update()在同一帧执行
接着注册一个脚本,编写如下代码
在Unity中运行如下:
所以执行顺序:Awake>Start>FixedUpdate>Update>LateUpdate
二.C# const 关键字
const是一个C#语言的关键字,它限定一个变量不允许被改变
const 一般修饰的变量为只读变量
const 的值是固定的
const是在编译时可被完全计算的,所以 const int a = b+1;,b是一个变量,显然不能被编译
const可以声明多个常数 public const int x = 1,y =2;
const不允许使用static修饰符
三.Unity场景跳转的另一种方式
之前我学习到的跳转场景是建立两个Scene,通过库SceneManagement调用函数
今天我学到了一种新的跳转场景的方式,利用SetActive方法来隐藏或显示所用的场景。
首先新建两个Panels,在其中一个Panels中添加一个Button
注册一个脚本,起名为Scene Manager,将脚本挂载道Canvas上(也可以挂到空物体上)打开脚本,编写如下代码
将Panels1和Panels挂载道GameObject类型数组中
接着,在Panel1中的Button中添加一个Onclick,将Canvas拖拽进去之后,选择SceneManager.panel1;之后运行就可以了
SetActive
在 Unity 中,要激活游戏对象的方法就是使用SetActive(),就是说通过此方法让游戏对象显示或者隐藏。
格式:
GameObject.SetActive(value);
说明:
(1)GameObject 是定义 GameObject 游戏对象的变量名
(2)value 是让物体显示或者隐藏,类型是bool
四.Unity 切割图片
首先选择一张导入的图片,在Inspector面板中,将图片格式改为Sprite2D and UI ,然后在Sprite Mode中选择multiple,然后选择Sprite Editor。
点击Slice,选择Automatic,然后Slice一下,最后点击右上角的Aplay,一张图片就会被自动切割好了
五.unity摄像机中clear flags属性介绍
Clear Flags 清除标记
每个相机在渲染时会存储颜色和深度信息。屏幕的未绘制部分是空的,默认情况下会显示天空盒。当你使用多个相机时,每一个都将自己的颜色和深度信息存储在缓冲区中,还将积累大量的每个相机的渲染数据。当场景中的任何特定相机进行渲染时,你可以设定清除标记以清除缓冲区信息的不同集合。可以通过下面四个选项之一来完成Skybox 天空盒
这是默认设置。在屏幕上空的部分将显示当前相机的天空盒。如果当前相机没有设置天空盒,它会默认使用渲染设置(在Edit->Render Settings里)中选择的天空盒。然后它将退回使用背景颜色。
Solid Color 纯色
屏幕上的任何空的部分将显示当前相机的背景颜色。
Depth Only 仅深度
如果你想绘制一个玩家的枪而不让它在环境内部得到裁剪,你要设置一个深度为0的相机来绘制环境,还要另一个深度为1的相机单独绘制武器。该武器相机的清除标记应设置为仅深度。这将保持环境的图形显示在屏幕上,但会丢弃所有关于每个对象在三维空间中的位置的信息。当枪被绘制出来,不透明的部分将完全覆盖任何已绘制的事物,而不管枪到墙之间如何接近。
Don’t Clear 不清除
该模式不清除任何颜色或深度缓存。其结果是,每帧绘制在下一帧之上,造成涂片效果。这不是用于游戏的典型方式,最好是与自定义着色器一起使用。
主要学习一下Depth Only:
个人理解为,假设一款FPS射击游戏,如果为武器单独添加一个Camera,并且调整Depth值,使其大于原来的Camera的Depth,这样这把武器便会永远显示在场景中,而不会因为距离太近或者太远导致武器被裁剪掉。
六.Unity中List数据类型的使用
List<T>类是 ArrayList 类的泛型等效类。该类使用大小可按需动态增加的数组实现 IList<T> 泛型接口。
泛型的好处:它为使用 c#语言编写面向对象程序增加了极大的效力和灵活性。不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以性能得到提高。
一.List的基础用法
a.T为列表中元素类型,现在以string类型作为例子
如:List<string> mList = new List<string>();
b.增加元素:List. Add(T item) 添加一个元素
如:mList.Add("aa");
c.插入元素:Insert(int index, T item); 在index位置添加一个元素
如:mList.Insert(1, "aa");
d.删除元素: List. Remove(T item) 删除一个值
如:mList.Remove("aa");
List. RemoveAt(int index); 删除下标为index的元素
如.:mList.RemoveAt(0);
List. RemoveRange(int index, int count); 从下标index开始,删除count个元素
如.:mList.RemoveRange(3, 2); //超出删除的范围会出错
注:删除某元素后,其后面的元素下标自动跟进
七,static关键字
一.静态类
静态类与非静态类的重要区别在于静态类不能实例话,也就是说,不能使用new关键字创建静态类类型的变量。在声明一个类时使用static关键字,意义是:
防止用代码来实例化该静态类
防止在类的内部声明任何实例字段或方法。
特性:
1.仅包含静态成员
2.无法实例化
3.静态类的本质,是一个抽象的密封类,所以不能被继承,也不能被实例化
4.不能包含实例构造函数。
5.如果一个类下面的所有成员,都需要被共享,那么可以被这个类定义为静态类
静态类与私有构造函数区别
1.私有构造器方式仍然可以从类的内部对类进行实例化,而静态类禁止从任何地方实例化类,其中包括从类自身内部。
2.使用私有构造器的类中,是允许有实例成员的,编译器不允许静态类有任何实例成员。
3.使用静态类的优点在于,编译器能够执行检查以确保不致偶然地添加实例成员,编译器将保证不会创建此类的实例。
4.C#编译器会自动把它标记为sealed。这个关键字将类指定为不可扩展;换言之,不能从它派生出其他类。
二.静态成员
1、通过static关键字修饰,是属于类,实例成员属于对象,在这个类第一次加载的时候,这个类下面的所有静态成员会被加载。
2、静态成员只被创建一次,所以静态成员只有一份,实例成员有多少个对象,就有多少份。
3、类加载的时候,所有的静态成员就会被创建在“静态存储区”里面,一旦创建直到程序退出,才会被回收。
4、成员需要被共享的时候,方法需要被反复调用的时候,就可以把这些成员定义为静态成员。
5、在静态方法中,不能直接调用实例成员,因为静态方法被调用的时候,对象还有可能不存在。
6、this/base 关键字在静态方法中不能使用,因为有可能对象还不存在。
7、可以创建这个类的对象,制定对象的成员在静态方法中操作。
8、在实例方法中,可以调用静态成员,因为这个时候静态成员肯定存在。
9、非静态类可以包含静态的方法、字段、属性或事件;
10、无论对一个类创建多少个实例,它的静态成员都只有一个副本;
11、静态方法和属性不能访问其包含类型中的非静态字段和事件,并且不能访问任何对象的实例成员;
12、静态方法只能被重载,而不能被重写,因为静态方法不属于类的实例成员;
13、虽然字段不能声明为 static const,但 const 字段的行为在本质上是静态的。这样的字段属于类,不属于类的实例。
三.什么时候适合用静态变量
静态变量适合存储一些全局都用得到的公共数据,由于静态的变量不会随对象的回收而释放内存,若是大量滥用则会使内存空间被挤占,代码结构混乱复杂,难于维护等问题。
四.为什么单例模式中要使用静态变量
类的静态成员变量就是指的类共享的对象,而单例模式的对象设成静态就是为了让该类所有成员共享同一个对象,所以从语义上是合适的;
从语法考虑,常见的单例模式都是通过一个静态方法(如getInstance)返回其单例,因为静态方法的内部不能直接使用非静态变量,所以返回的这个实例就是静态的。
八,Unity设计模式之单例模式
单例模式是一个基本的设计模式。使用类来实现单例模式可以确保在任何时间只有一个实例对象。当对象不需要在游戏中多次复制时,推荐使用这种方法。这样就可以像控制GameManager、AudioController一样来控制类。
一、单例模式优点
单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问;
意味着在内存中,只存在一个实例,减少了内存开销;
二、单例模式特点
只存在唯一一个实例;
提供统一对外访问接口,使得全局可对该单例的唯一实例进行访问;
自行实例化(私有构造函数,不允许外界对其进行实例化)。
三、单例模式使用
资源管理器,资源对象数据的加载和卸载(无状态不需要实例化的对象);
单一客户端连接服务器等;
生命周期在游戏中永不消毁的对象。
四、最简单的单例程序
每当食物被蛇吃掉之后,用单例生成食物。
九,position与localPosition
position是根据世界原点为中心
localPosition是根据父节点为中心,如果没有父节点,localPosition和position是没有区别的
在Unity中无法对transform.position直接赋值
transform.position.x=1;//错误
编译器显示,无法修改其返回值,因为它不是变量
解释:
Vector3是一个结构体,而position是一个自动实现的属性
在C#中,结构体是值类型的,值类型在通过方法传递的时候,所传递的只是值的副本。
C#的属性可以说是两个分别名为get 和set的方法
而当我们写出形如transform.position.x = 1;这样的代码时,是在通过get方法得到position,然后修改position的x字段的值。但是,由于position是结构体类型的,get得到的也只是position的一个副本,而对这个副本所作出的任何修改,都对原positon没有任何影响,因此这样的修改是毫无意义的。编译器会禁止这样的修改操作。
正确的写法因该是
transform.localPosition = new Vector3(x, y ,z);
十.Transform.Setparent()
Setparent()函数有两个重载:
(重载,简单说,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。)
public void SetParent(Transform parent);
public void SetParent(Transform parent, bool worldPositionStays);
第一个是我们常用的只有一个参数的函数,第二个是加了一个是否保持世界坐标系的布尔型变量;
如果为true,就保持之前的位置、旋转量、缩放值。而为false,保持局部坐标的位置、旋转、缩放。
意思是将foodHolder设为food的父物体。
十一,理解GameObject与Transform的区别与关联
GameObject是一个类型,所有的游戏物件都是这个类型的对象
gameobject是一个对象,指的是这个脚本所附着的游戏物件
Transform是一个类,用来描述物体的位置,大小,旋转等信息
transform是Transform类的对象,依附于每一个物体,也是当前游戏对象的组件
transform与gameObject
含义:
transform:当前游戏对象的transform组件
gameObject:当前游戏对象的实例
区别:
在unity中每个游戏对象都是一个gameobject. 每个gameobject都包含各种各样的组件,但从这点可以看出transform是gameobject的一个组件,控制着gameobject的位置,缩放,和旋转,而且每个gameobject都有而且必有一个transform组件
gameobject.find用来获取场景中那个我们需要查找的对象(object). 而transform.find方法则是获取当前对象的子对象下我们需要获取的目标对象位置信息。
gameobject.transform与transform.gameobject
gameobject.transform,是获取当前游戏对象的transform组件.
所以在start函数中 gameobject.transform 和this.transform,指向的都是同一个对象。即:gameobject.transform == this.transform == transform
transform.gameobject:可以这么理解为:获取当前transform组件所在的gameobect
所以在start()函数中transform.gameobject == this.gameobject == gameobect
所以他们可以无限的引用下去
意思就是:
gameobject.transform == this.transform == gameobject.transform.gameobject.tranform ==
tranform.gameobect.transform
十二,鼠标点击Cube控制按钮旋转移动
SwitchModeEnum枚举类型定义了旋转和移动
SwitchMoveAxis枚举类型定义了坐标x,y,z
[SerializeField] 强制unity去序列化一个私有域
这是一个内部的unity序列化功能,有时候我们需要Serialize一个private或者protect的属性 ,会在Inspector面板显示出来
OnMouseDown()方法必须在cube上添加一个碰撞器,否则代码无效
十三.Random.Range()方法
整数类型:Random.Range(min,max); 返回一个随机整数,在min(包含)和max(不包含)之间
小数类型:Random.Range(minf,maxf)时,返回一个随机浮点数,在minf(包含)和maxf(包含)之间,此时包括临界值。
eg:
public Sprite[] foodSprites; //定义一个数组
int index = Random.Range(0, foodSprites.Length); //随机生成数组中的值。
十四.Invoke和InvokeRepeating方法
Invoke 和 InvokeRepeating 是 MonoBehaviour 中的两个内置的延时方法
示例:
在场景中创建一个游戏对象 , 命名为Invoker
创建一个Create Empty,用来存放脚本InvokerSp
在Start方法中,调用Invoke方法,Invoke方法有两个参数,一个是我们要调用的方法名称字符串,一个是以秒为单位的延迟时间。这行代码的作用是经过2秒后调用SpawnObject方法。(只有无参数并且类型为void的方法,才可以使用Invoke调用)
经过2秒后,Invoker会被实例化在指定的位置。
InvokeRepeating
InvokeRepeating方法可以用来反复的调用一个方法
InvokeRepeating中的三个参数分别是:要调用的方法名称的字符串,调用方法之前的延迟时间,每次后续调用之间的延迟时间。
该代码的意思是,在场景中实例化一个tar物体,两秒后tar物体开始沿着Z轴运动,运动距离为1.0f,每一秒重复运动一次(因为每隔一秒都会调用一次SpawnObject方法)
CancelInvoke
用来停止InvokeRepeating方法的调用
用Invoke方法在10秒后调用stop方法中的CancelInvoke方法,CancelInvoke方法即停止调用SpawnObject方法。