赞
踩
什么时游戏引擎?
游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些交互式实时图像应用程序的核心组件。这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在于让游戏设计者能容易和快速地做出游戏程序而不用从零开始。
游戏引擎对于我们的意义
1、降低做游戏的门槛
2、提升游戏开发的效率
如何降低开发门槛?
以前做游戏:物理、数学、计算机图形学、计算机原理、操作系统等等与多种程序语言。
现在做游戏:游戏引擎的使用和一种程序语言。
如何提升开发效率?
以前做游戏:图形渲染、物理系统、离子系统、寻路系统、多平台开发等等与上层逻辑。
现在做游戏:游戏引擎和上层逻辑。
如何学习游戏引擎?
1、学习引擎用于开发的主要语言。
2、学习引擎的软件操作。
3、学习引擎提供的API和核心系统
如何学习Unity?
Unity相当于就是一个游戏开发工具包,我们只要学会使用工具包中的各个工具即可,而使用这些工具的媒介就是我们已经学习完毕的C#程序语言。
软件下载
Unity官网(访问较慢)
中国官网
注册一个账号,然后下载。
版本选择
1、长期支持版:又称LTS版,适用于希望长时间保持稳定版本的用户。
2、补丁程序版:bug修复版本。
3、Beta版本:包含还未正式发布的新功能。
最新的不是最好的!不管是学习还是开发,都建议使用最稳定的版本。
注意:
一般情况下,Unity版本向下兼容,高版本开低版本工程,问题不大,低版本开高版本工程,会出现兼容问题。
关于版本号:
大版本号.小版本号.bug处理版本号(版本类型后缀) 例如:
2019.4.17f1
2017.2.4p1
2020.2.0b14
软件安装
1、点击“从Unity Hub下载”
2、获取许可证
①打开“偏好设置”
②点击“许可证”–>“添加许可证”–>“获取免费的个人版许可证”。
③在项目中为自己的项目选择合适位置。
④安装编辑器
勾选
Assets: 工程资源文件夹(美术资源,脚本等)
Library: 库文件夹(Unity自动生成管理)
Logs: 日志文件夹,记录特殊信息(Unity自动生成管理)
obj: 编译产生中间文件(Unity自动生成管理)
Packages: 包配置信息(Unity自动生成管理)
ProjectSettings: 工程设置信息(Unity自动生成管理)
场景窗口和层级窗口是息息相关的,层级窗口中看到的内容就是场景窗口中的显示对象。
窗口布局:
推荐使用2 by 3
布局
Hierarchy层级窗口:
我们可以在Hierarchy窗口中,创建或拖入各种游戏对象。比如:模型、光源、图片、UI等内容。层级窗口中显示的就是一个场景中的所有对象。
Scene场景窗口:
我们可以在Scene窗口中,查看所有游戏对象,设置所有游戏对象。
关于Unity中的3D世界坐标轴:
红色为X轴正向
绿色为Y轴正向
蓝色为Z轴正向
以屏幕为参照物,垂直屏幕向内为Z正方向,平行屏幕向右为X正方向,平行屏幕向上为Y正方向。
Game游戏窗口: 游戏画面窗口,玩家能看到的画面内容。其中显示的内容,是场景中摄像机拍摄范围内的游戏对象。
Project工程窗口: 工程资源窗口,所有的工程资源都会在该窗口中显示,显示的内容为Assets文件夹中的所有内容,主要用来管理资源脚本文件。
默认文件夹Scenes:里面有一个默认空场景
Packages:官方拓展包
资源类型:
图片格式:jpg、png、tga
模型格式:fbx、max、maya
音效:wav、mp3、ogg
文本:txt、json、bytes
视频:mp4
Inspector检查窗口: 查看场景中游戏对象关联的C#脚本信息。
Console控制台窗口: 用于查看调试信息的窗口,报错、警告、测试打印都可以显示在其中。
默认未开启可以在Window->General中开启
或使用快捷键:Ctrl + Shift + C
工具栏
1、文件操作:新建工程、新建场景、工程打包等。
2、编辑操作:对象编辑操作相关,工程设置、引擎设置相关
3、资源操作:基本等同于Project窗口中右键相关功能。
4、对象操作:基本等同于Hierarchy窗口中右键相关功能。
5、脚本操作:Unity自带的脚本,可以添加各系统中的脚本。
6、窗口:可以打开Unity各核心系统的窗口。
7、帮助:检查更新,查看版本等等功能。
父子关系
1、子对象会随着父对象的变化而变化。
2、子对象Inspector窗口中Transform信息是相对父对象的。
3、Scene上方
的作用
Unity引擎本质上是一个软件,使用它时是处于运行中的。我们是在一个运行中的软件里制作游戏的,Unity开发的本质就是在Unity引擎的基础上,利用反射和引擎提供的各种功能,进行的拓展开发。
场景中对象的本质是什么?
GameObject类对象是Unity引擎提供给我们的作为场景中所有对象的根本,在游戏场景中出现一个对象,不管是图片、模型、音效、摄像机等等都是依附于GameObject对象的。
Transform是什么?
GameObject对象作为一个出现在舞台(3D场景)中的演员,必须有一个表示自己所在位置的信息。Transform就是一个必不可少的剧本,它的本质就是发了一本表示位置的剧本给演员,用于设置和得到演员在世界中的位置角度缩放等信息。
反射机制的体现
除了Transform这个表示位置的标配剧本外,我们可以为这个演员(GameObject)关联各种剧本(C#脚本)让它按照我们剧本中(代码逻辑中)的命令来处理事情。而为演员添加剧本的这个过程,就是在利用反射new一个新的剧本对象和演员(GameObject)对象进行关联,让其按我们的命令做事。
例如:
1、修改Inspector面板中Transform的内容,前提是Unity帮助我们实现了对象查找和关联。
利用反射:已知对象,类名,变量名,通过反射为该对象设置变量值。
2、新建一个脚本后,添加给一个指定的GameObject对象。
利用反射:已知类名,可以获取所有公共成员,故可以在Inspector面板上创建各公共字段信息。
游戏场景基本知识点
1、游戏场景的保存
2、游戏场景的新建
3、多个游戏场景叠加显示
4、游戏场景的本质
游戏场景文件,后缀为.unity,它的本质就是一个配置文件,Unity有一套自己识别处理它的机制,但是本质就是把场景对象相关信息读取出来,通过反射来创建各个对象关联各个脚本对象。
预设体:
将组合对象拖入Assest即可成为预设体。
资源包:
在project窗口中右键,点击import package或者export package进行导入导出。
创建规则:
1、不在VS中创建脚本了。
2、可以放在Assets文件夹下的任何位置(建议同一文件夹管理)。
3、类和文件名必须一致,不然不能挂载(因为反射机制创建对象,会通过文件名去找Type)。
4、建议不要使用中文名命名。
5、没有特殊需求,不用管命名空间。
6、创建的脚本默认继承MonoBehavior。
MonoBehavior基类:
1、创建的脚本默认都继承MonoBehaviour继承了它才能够挂载在GameObject上。
2、继承了MonoBehavior的脚本不能new只能挂!
3、继承了MonoBehavior的脚本不要去写构造函数,因为我们不会去new它,写构造函数没有意义。
4、继承了MonoBehavior的脚本可以在一个对象上挂多个(如果没有加DisallowMultipleComponent特性)。
5、继承MonoBehavior的类也可以再次被继承,遵循面向对象继承多态的规则。
不继承MonoBehavior的类:
1、不继承Mono的类,不能挂载在GameObject上。
2、不继承Mono的类,想怎么写怎么写,如果要使用需要自己new。
3、不继承Mono的类一般是单例模式的类(用于管理模块)或者数据结构类(用于存储数据)。
4、不继承Mono的类,不用保留默认出现的几个函数。
脚本执行顺序:
默认脚本内容:
从这里打开可以修改默认脚本内容。
Editor\Data\Resources\ScriptTemplates
帧的概念:
游戏的本质就是一个死循环,每一次循环处理游戏逻辑就会更新一次画面,之所以能看到画面在动是因为切换画面的速度到达一定时人眼就认为画面是流畅的,一帧就是执行一次循环。
Unity底层已经帮助我们做好了死循环,利用Unity生命周期函数做好的规则来执行我们的游戏逻辑。
fps(Frames Per Second):
即每秒钟帧数,一般我们说的60帧30帧,意思是1秒更新60次、30次画面。
1s = 1000ms
60帧:1帧为1000ms/60 ≈ 16.66ms
30帧:1帧为1000ms/30 ≈ 33.33ms
游戏卡顿的原因:
跑1帧游戏逻辑中的计算量过大,或者CPU不给力,不能在一帧的时间内处理完所有游戏逻辑。
生命周期函数的概念:
所有继承MonoBehavior的脚本,最终都会挂载到GameObject游戏对象上。生命周期函数就是该脚本对象依附的GameObject对象从出生到消亡整个生命周期中会通过反射自动调用的一些特殊函数。
Unity帮助我们记录了一个GameObject对象依附了哪些脚本,会自动的得到这些对象,通过反射去执行一些固定名字的函数。
生命周期函数的访问修饰符一般为private和protected,因为不需要在外部自己调用生命周期函数,都是Unity自己帮助我们调用的。
//出生时调用,类似构造函数,一个对象只会调用一次 void Awake() { //在Unity中打印信息的两种方式 //1、没有继承MonoBehavior类的时候 Debug.Log("123"); Debug.LogError("出错了"); Debug.LogWarning("警告"); //2、继承了MonoBehavior有一个线程的方法,可以使用 print("123"); } //依附的GameObject对象每次激活时调用 void OnEnable() { } //从自己被创建出来后,第一次帧更新之前调用,一个对象只会调用一次 void Start() { } //物理帧更新,固定间隔时间执行,间隔时间可以设置 void FixedUpdate() { } //逻辑帧更新,每帧执行 void Update() { } //每帧执行,于Update之后执行 //一般用来处理摄像机位置更新相关内容的 void LateUpdate() { } //依附的GameObject对象每次失活时调用 void OnDisable() { } //对象销毁时调用,依附的GameObject对象被删除时 void OnDestroy() { }
生命周期函数继承多态。
为什么不建议在继承Mono的类写构造函数呢?
1.Unity的规则就是,继承MonoBehavior的脚本不能new只能挂载
2.生命周期函数的Awake是类似构造函数的存在,当对象出生就会自动调用
3.写构造函数反而在结构上会破坏Unity设计上的规范
不同对象的生命周期函数是在同一个线程中执行的吗?
Unity中所有对象上挂载的生命周期函数都是在一个主线程中按先后执行的。
理解:Unity会主动把场景上的对象,对象上挂载的脚本都统统记录下来,在主线程的死循环中,按顺序按时机的通过反射,执行记录的对象身上挂载的脚本的对应生命周期函数。
Inspector显示的可编辑内容就是脚本的成员变量。
1、私有和保护无法显示编辑
2、让私有的和保护的也可以被显示
//加上强制序列化字段特性
[SerializeFiedld]
//所谓序列化就是把一个对象保存到一个文件或数据库字段中去
3、公共的可以显示编辑。
4、若使公共的也不让其显示编辑。
[HideInInspector]
5、大部分类型都能显示编辑。
6、让自定义类型可以被访问。
//加上序列化特性,字典怎样都不行
[System.Serializable]
一些辅助特性:
1、分组说明特性Header,为成员分组
[Header("分组说明")]
public int age;
public bool sex;
2、悬停注释Tooltip,为变量添加说明。
[Tooltip("说明内容")]
public int miss;
3、间隔特性Space,让两个字段间出现间隔。
[Space()]
public int crit;
4、修饰数值的滑条范围Range
[Range(最小值,最大值)]
public float luck;
5、多行显示字符串,默认不写参数显示3行,写参数就是对应行。
[Multiline(4)]
public string tips;
6、滚动条显示字符串,默认不写参数就是超过3行显示滚动条。
[TextArea(3,4)]
public string myLife;
7、为变量添加快捷方法ContexMenuItem。
//参数1:显示按钮名
//参数2:方法名,不能有参数
[ContextMenuItem("重置钱","方法名")]
public int money;
public void test()
{
money = 99;
}
8、为方法添加特性能够在Inspector中执行。
[ContextMenu("哈哈哈哈");
private void TestFun()
{
print("测试方法");
}
注意:
1、Inspector窗口中的变量关联的就是对象的成员变量,运行时改变他们就是在改变成员变量。
2、拖拽到GameObject对象后,再该表脚本中变量默认值,界面上不会改变。
3、运行中修改的信息不会保存。
重要成员:
1、获取依附的GameObject
print(this.gameObject.name);
2、获取依附的GameObject的位置信息,得到对象位置信息。
print(this.transform.position);//位置
print(this.transform.eulerAngles);//角度
print(this.transform.lossyScale);//缩放大小
this.gameObject.transform;
3、获取脚本是否激活
this.enabled = true;
重要方法:
得到依赖对象上挂载的其他脚本
1、得到自己挂载的单个脚本
//根据脚本名获取
this.GetComponent("Lesson3_Test");
//根据Type获取
this.GetComponent(typeof(Lesson3_Test));
//根据泛型获取,建议使用泛型获取,因为不用二次转换
this.GetCompoent<Lesson3_Test>();
2、得到自己挂载的多个脚本
Lesson3[] array = this.GetComponents<Lesson3>();
3、得到子对象挂载着的脚本(它默认也会找自己身上是否挂载该脚本)
//该参数是:默认不传为false,意思就是如果子对象失活是不会去找这个对象上是否有某个脚本的。
//如果为true即使失活也会找
this.GetComponentInChildren<Lesson3_Test>(false);
this.GetComponentsInChildren<Lesson3_Test>(true);
4、得到父对象挂载的脚本
this.GetComponentInParent<Lesson3_Test>();
5、尝试获取脚本
Lesson3_Test l3t;
if(this.TryGetComponent<Lesson3_Test>(out l3t))
{
}
//名字
this.gameObjcet.name;
//是否激活
this.gameObject.activeSelf;
//是否是静态
this.gameObject.isStatic;
//层级
this.gameObject.layer;
//标签
this.gameObject.tag;
//transform
this.transform;
this.gameObject.transform.position;
创建自带几何体:
GameObject.CreatePrimitive(PrimitiveType.Cube);
查找对象(无法找到失活的对象):
//若场景中存在多个满足条件的对象,则无法准确确定找到的是谁
//1、查找单个对象,通过对象名查找
//效率较低,因为他会在场景中所有对象查找
GameObject obj2 = GameObject.Find("chx");
//通过tag来查找对象
GameObject obj3 = GameObject.FindWithTag("Player");
GameObject obj3 = GameObject.FindGameObjectWithTag("Player");//同上,效果一样
//2、查找多个对象
GameObject[] objs = GameObject.FindGameObjectWithTag("Player");
//找到场景中挂载的某一个脚本对象
Lesson o = GameObject.FindObjectOfType<Lesson4>();
实例化对象(克隆对象)的方法:
//实例化对象它的作用是根据一个GameObject对象创建出一个和它一模一样的对象
//准备用来克隆的对象
//1、直接是场景上的某个对象
//2、可以是一个预设体对象
public GameObject obj;
GameObject.Instantiate(obj);
删除对象的方法:
GameObject.Destory(obj);
//第二个参数,代表延迟几秒钟删除
GameObject.Destroy(obj5,5);
//Destroy不仅可以删除对象,还可以删除脚本
GameObject.Destroy(this);
删除对象有两种作用
1、是删除指定的一个游戏对象
2、是删除一个指定的脚本对象
注意:这个Destroy方法不会马上移除对象,只是给这个对象加了一个移除标识。一般情况下它会在下一帧把这个对象移除并从内存中移除。
如果没有特殊需求,就是一定要马上移除一个对象的话GameObject.DestroyImmediate(myObj);
,建议使用上面的Destroy方法,因为是异步的,降低卡顿的几率。
过场景不移除:
默认情况在切换场景时,场景中对象都会被自动删除掉,如果希望某个对象过场景不被移除,使用如下方法。
GameObject.DontDestroyOnLoad(this.gameObject);
创建空物体:
GameObject obj6 = new GameObject();
GameObject obj7 = new GameObject("空物体");
GameObject obj8 = new GameObject("空物体",typeof(Lesson2),typeof(Lesson1));
为对象添加脚本:
Lesson1 les1 = obj6.AddComponent(typeof(Lesson1)) as Lesson1;
Lesson2 les2 = obj6.AddComponent<Lesson2>();
得到脚本的成员方法和继承mono类得到脚本的方法一模一样
标签比较:
if(this.gameObject.CompareTag("Player"))
{
}
设置激活失活:
obj6.SetActive(false);
时间相关内容,主要用于游戏中参与位移、记时、时间暂停等。
时间缩放比例:
//时间停止
Time.timeScale = 0;
//回复正常
Time.timeScale = 1;
//2倍速
Time.timeScale = 2;
帧间隔时间:
最近的一帧用了多长时间。
//受Scale影响
Time.deltaTime;
//不受Scale影响的帧间隔时间
Time.unscaleDeltaTime;
游戏开始到现在的时间:
主要用来在单机游戏中计时。
//受scale影响
Time.time;
//不受scale影响
Time.unscaledTime;
物理帧间隔时间:
//受scale影响
Time.fixedDeltaTime;
//不受scale影响
Time.fixedUnscaledDeltaTime;
帧数:
从开始到现在游戏跑了多少帧。
Time.frameCount;
Vector3主要是用来表示三维坐标系中的一个点或者一个向量。
声明:
Vector3 v = new Vector();
v.x = 10;
v.y = 10;
v.z = 10;
//只传x,y,默认z是0
Vector3 v2 = new Vector3(10,10);
Vector3 v3 = new Vector3(10,10,10);
Vector3 v4;
v4.x = 10;
v4.y = 10;
v4.z = 10;
基本运算:
Vector3 v1 = new Vector3(1,1,1); Vector3 v2 = new Vector3(2,2,2); print(v1 + v2); print(v1 - v2); print(v1 * 10); print(v1 / 2); //常用 Vector3.zero;//000 Vector3.right;//100 Vector3.left;//-100 Vector3.forward;//001 Vector3.back;//00-1 Vector3.up;//010 Vector3.down;//0-10 //计算两个点之间的距离的方法 Vector3.Distance(v1,v2);
//相对世界坐标系
//如果对象有父子关系,并且父对象位置,不在原点,那么和面板上肯定就是不一样的
this.gameObject.transform;
//相对父对象
//即以面板坐标为准来进行设置
this.transform.localPosition;
//对象当前的各朝向
//对象当前的面朝向
this.transform.forward;
//对象当前的头顶朝向
this.transform.up;
//对象当前的右手边
this.transform.right;
位移:
理解坐标系下的位移计算公式:
路程 = 方向 * 速度 * 时间
//方式一 自己计算
this.transform.position = this.transform.position + this.transform.forward * 1 * Time.deltaTime;
//方式二 API
//参数一:表示位移多少 路程 = 方向 * 速度 * 时间
//参数二:表示相对坐标系 默认该参数是相对于自己坐标系的
//相对于世界坐标系的z轴动
this.transform.Translate(Vector3.forward * 1 * Time.deltaTime,Space.World);
//相对于世界坐标的自己的面朝向动
this.transform.Translate(this.transform.forward * 1 * Time.deltaTime,Space.World);
//相对于自己的坐标系下的自己的面朝向向量移动(一定不会这样让物体移动)
this.transform.Translate(this.transform.forward * 1 * Time.deltaTime,Space.Self);
//相对于自己的坐标系下的z轴正方向移动
this.transform.Translate(Vector3.forward * 1 * Time.deltaTime,Space.Self);
角度相关:
//相对世界坐标角度
this.transform.eulerAngles;
//相对父对象角度
this.transform.localeulerAngles;
//注意:设置角度和设置位置一样,不能单独设置xyz,要一起设置,如果我们希望改变的角度是面板上显示的内容,则就是改变相对父对象的角度
this.transform.eulerAngles = new Vector3(10,10,10);
旋转相关:
//API计算
//自转
//第一个参数相当于是旋转的角度,每一帧
//第二个参数默认不填就是相当于对于自己的坐标系进行的旋转
this.transform.Rotate(new Vector3(0,10,0) * Time.deltaTime,Space.World);
//相对于某个轴转多少度
//参数一:相对于哪个轴进行转动
//参数二:转动的角度是多少
//参数三:默认不填,就是相对于自己的坐标系进行旋转,如果填,可以填写相对于世界坐标系进行旋转
this.transform.Rotate(Vector3.up,10 * Time.deltaTime,Space.World);
//相对于某一个点转
//参数一:相当于哪一个点转圈圈
//参数二:相对于哪一个点的哪一个轴转
//参数三:转的度数:旋转速度 * 时间
this.transform.RotateAround(Vector3.zero,Vector3.up,10 * Time.deltaTime);
缩放:
//相对世界坐标系
this.transform.lossyScale;
//相对本地坐标系(父对象)
this.transform.localScale;
Unity没有提供关于缩放的API,之前的旋转位移都提供了对应的API,但是缩放并没有,如果你想要让缩放发生变化,只能自己去写。
看向:
让一个对象的面朝向可以一直看向某一个点或者某一个对象。
//看向一个点,相对于世界坐标系
this.transform.LookAt(Vector3.zero);
//看向一个对象,就传入一个对象的Transform信息
public Transform lookAtObj;
this.transform.LookAt(lookAtObj);
获取和设置父对象:
//获取父对象
this.transform.parent.name;
//设置父对象 断绝父子关系
this.transform.parent = null;
//设置父对象 认爸爸
this.transform.parent = GameObject.Find("Father2").transform;
//通过API来进行父子关系的设置(SetParent)
this.transform.SetParent(null);//断绝父子关系
//参数一:我的父亲
//参数二:是否保留世界坐标的位置、角度、缩放信息
this.transform.SetParent(GameObject.Find("Father2").transform,true);//认爸爸
抛妻弃子:
//和自己所有的儿子断绝关系
this.transform.DetachChildren();
获取子对象:
//按名字查找儿子
//找到儿子的transform信息
//1、能找失活对象
//2、能找到自己的儿子,找不到自己的孙子
//3、效率比GameObject高,但是需要知道父亲是谁才能找
this.transform.Find("Cube");
//遍历儿子
//如何得到有多少个儿子
//1、失活的儿子也算数量
//2、孙子不算数量
this.transform.childCount;
//通过索引号得到对应的儿子
//1、若编号超出范围则报错
//2、返回值是transform
this.transform.GetChild(0);
儿子的操作:
public Transform son;
//判断自己的爸爸是谁
son.IsChildOf(this.transform);
//得到自己作为儿子的编号
son.GetSiblingIndex();
//把自己设置为第一个儿子
son.SetAsFirstSibling();
//把自己设置为最后一个儿子
son.SetAsLastSibling();
//把自己设置为指定编号儿子(若超出范围,则设置为最边上的编号)
son.SetSiblingIndex(3);
世界坐标转本地坐标
//世界坐标系的点转换为相对本地坐标系的点
this.transform.InverseTransformPoint(Vector3.forward);//受到缩放影响
//世界坐标系的方向转换为相对本地坐标系的方向
//不受缩放影响
this.transform.InverseTransformDirection(Vector3.forward);
//受缩放影响
this.transform.InverseTransformVector(Vector3.forward);
本地坐标转世界坐标
//本地坐标系的点转换为相对世界坐标系的点
//受到缩放影响
this.transform.TransformPoint(Vector3.forward);
//本地坐标系的方向转换为相对世界坐标系的方向
//不受缩放影响
this.transform.TransformDirection(Vector3.forward);
//受缩放影响
this.transform.TransformVector(Vector3.forward);
鼠标在屏幕位置
//屏幕坐标的原点,在屏幕的左下角,往右是x轴正方向,往上是y轴正方向
Input.mousePosition;
检测鼠标输入
//鼠标按下一瞬间进入
//0左键 1右键 2中键
Input.GetMouseButtonDown(1);
//鼠标抬起一瞬间进入
Input.GetMouseButtonUp(1);
//鼠标长按按下抬起都会进入
Input.GetMouseButton(1);
//中键滚动
//返回值的y -1下 0不动 1上
Input.mouseScrollDelta;
检测键盘输入
//键盘按下
Input.GetKeyDown(KeyCode.W);
//传入字符串的重载
//传入字符串必须为小写
Inut.GetKeyDown("q");
//键盘抬起
Input.GetKeyUp(KeyCode.W);
//键盘长按
Input.GetKey(KeyCode.W);
检测默认轴输入
我们学习鼠标键盘输入,主要是用来控制玩家,比如旋转位移等等。所以Unity提供了更方便的方法来帮助我们控制对象的位移和旋转。
//键盘AD按下时,返回-1到1之间的变换
Input.GetAxis("Horizontal");
//键盘SW按下时,返回-1到1之间的变换
Input.GetAxis("Vertical");
//鼠标横向移动时,-1到1 左 右
Input.GetAxis("Mouse X");
//鼠标纵向移动时,-1到1 左 右
Input.GetAxis("Mouse Y");
GetAxisRaw
方法和GetAxis
使用方式相同,只不过前者的返回值只会是 -1 0 1不会有中间值。
其它
//是否有任意键或鼠标长按
Input.anyKey;
//是否有任意键或鼠标按下
Input.anyKeyDown;
//这一帧的键盘输入
Input.inputString;
//得到连接的手柄的所有按钮名字 Input.GetJoystickNames(); //某一个手柄键按下 Input.GetButtonDown("Jump"); //某一个手柄键抬起 Input.GetButtonUp("Jump"); //某一个手柄键长按 Input.GetButton("Jump"); //移动设备触摸相关 if(Input.touchCount > 0) { Touch t1 = Input.touches[0]; //位置 print(t1.position); //相对上次位置的变化 print(t1.deltaPosition); } //是否启用多点触控 Input.MultiTouchEnabled = false; //陀螺仪(重力感应) //是否开启陀螺仪 必须开启才能正常使用 Input.gyro.enabled = true; //重力加速度向量 Input.gyro.gravity; //旋转速度 Input.gyro.rotationRate; //陀螺仪当前的旋转四元数 Input.gyro.attitude;
静态属性:
//当前屏幕分辨率
Screen.currentResolution;
//屏幕窗口当前宽高
Screen.width;
Screen.height;
//屏幕休眠模式
Screen.sleepTimeout = SleepTimeout.NeverSleep;
以下不常用:
//运行时是否全屏模式 Screen.fullScreen = true; //独占全屏 FullScreenMode.ExclusiveFullScreen //全屏窗口 FullScreenMode.FullScreenWindow //最大化窗口 FullScreenMode.MaximizeWidow //窗口模式 FullScreenMode.Windowed //移动设备屏幕转向相关 //允许自动旋转为左横向 Home键在左 Screen.autorotateToLandscapeLeft = true; //允许自动旋转为右横向 Home键在右 Screen.autorotateToLandscapeRight = true; //允许自动旋转转到纵向 Home键在下 Screen.autorotateToPortrait = true; //允许自动旋转转到纵向倒着看 Home键在上 Screen.autorotateToPortraitUpsideDown = true; //指定屏幕显示方向 Screen.orientation = ScreenOrientation.Landscape;
静态方法:
//设置分辨率 一般移动设备不使用
//参数三 是否全屏
Screen.SetResolution(1920,1000,false);
Clear Flags(如何清除背景?)
1、skybox
天空盒
2、Solid Color
颜色填充
3、Depth only
只画该层,背景透明
4、Don't Clear
不移除,覆盖渲染
Culling Mask(选择性渲染部分层级)
可以指定只渲染对应层级的对象
projection
一、Perspective
透视模式
1、FOV Axis
视场角轴
决定了光学仪器的视野范围。
2、Field view
视口大小
3、Physical Camera
物理摄像机,勾选后可以模拟真实世界中的摄像机、焦距、传感器尺寸、透镜移位等等。
Focal Length
(焦距)Sensor Type
(传感器类型)Sensor Size
(传感器尺寸)Lens Shift
(透镜移位)Gate Fit
(闸门配合)orthographic
(正交摄像机,一般用于2D游戏制作)Size
(摄制范围)Clipping Planes(裁剪平面距离)
Depth(渲染顺序上的深度)
数字越小越先被渲染
Target Texture(渲染纹理)
可以把摄像机画面渲染到一张图上,主要用于制作小地图,在Project右键创建Render Texture。
Occlusion Culling(是否启用剔除遮挡)
以下仅作了解:
Viewport Rect
:视口范围,屏幕上将绘制该摄像机试图的位置,主要用于双摄像机游戏,0~1相当于宽高百分比。
Redering path
:渲染路径
Allow HDR
:是否允许高动态范围渲染
Allow MSAA
:是否允许抗锯齿
Allow Dynamic Resolution
:是否允许动态分辨率呈现
Target Display
:用于哪个显示器,主要用来开发有多个屏幕的平台游戏
重要的静态成员:
1、获取摄像机
//主摄像机的获取
//若想通过这种方式,快速获取摄像机,那么场景上必须有一个,tag为MainCamera的摄像机
Camera.mian.name;
//获取摄像机的数量
Camera.allCamerasCount;
//得到所有摄像机
Camera[] allCamera = Camera.allCameras;
2、渲染相关委托
//摄像机剔除前处理的委托函数
Camera.onPreCull += (c) =>
{
};
//摄像机渲染前处理的委托
Camera.onPreRender += (c) =>
{
};
//摄像机渲染后处理的委托
Camera.onPostRender += (c) =>
{
};
重要成员
1、界面上的参数,都可以在Camera中获取到
例如:
Camera.main.depth = 10;
2、世界坐标转屏幕坐标
Vector3 v = Camera.main.WorldToScreenPoint(this.transform.position);
2、屏幕坐标转世界坐标
//如果不改z轴,默认为0
//转换过去的世界坐标系的点永远都是一个点,可以理解为视口相交的焦点
//如果改变了z那么转换过去世界坐标的点就是相对于摄像机前方多少的单位的横截面积上的世界坐标点
Vector3 v = Input.mousePosition;
v.z = 5;
obj.position = Camera.main.ScreenToWorldPoint(v);
Type(光源类型)
1、Spot
(聚光灯)
Range
(发光范围距离)Spot Angle
(光锥角度)2、Directional
(方向光(环境光))
3、Point
(点光源)
4、Area
(面光源)
Color(颜色)
Mode(光源模式)
1、Realtime
(实时光源)
每帧实时计算,效果好,性能消耗大
2、Baked
(烘焙光源)
事先计算好,无法动态变化
3、Mixed
(混合光源)
预先计算+实时运算
Intensity(光源亮度)
Shadow Type
1、NoShadows
(关闭阴影)
2、HardShadows
(生硬阴影)
3、SoftShadow
(柔和阴影)
Cookie(投影遮罩)
Draw Halo(球形光环开关)
Flare(耀斑)
Culling Mask(剔除遮罩层,决定哪些层的对象受到该光源影响)
Indirect Multiplier(改变间接光的强度)
1、低于1:每次反弹会使光更暗
2、大于1:每次反弹会使光更亮
RealtimesShadows
1、Strength
:阴影暗度0-1之间,越大越黑
2、Resolution
:阴影贴图渲染分辨率,越高越逼真,消耗越高
3、Bias
:阴影推离光源的距离
4、Normal Bias
:阴影投射面沿法线收缩距离
5、Near Panel
:渲染阴影的近裁剪面
Render Mode(渲染优先级)
1、Auto
(运行时确定)
2、Important
(以像素质量为单位进行渲染,效果逼真,消耗大)
3、Not Important
(以快速模式进行渲染)
Environment
1、Skybox Material
(天空盒材质)
可以改变天空盒
2、Sun Source
(太阳来源)
不设置会默认使用场景中最亮的方向光代表太阳
3、Environment Lighting
(环境光设置)
①Source
(环境光光源颜色)
Skybox
:天空和材质作为环境光颜色Gradient
:可以为天空、地平线、地面单独选择颜色和他们之间混合Intensity Multiplier
(环境光亮度)Ambient Mode
(全局光照模式)Realtime
(已弃用)Baked
OtherSettings(其他设置)
Fog(雾开关)
1、Color
(雾颜色)
2、Mode
(雾计算模式)
①Linear
(随距离线性增加)
Start
:离摄像机多远开始有雾End
:离摄像机多远完全遮挡②Exponential
(随距离指数增加)
Density
:强度②Exponential Squared
(随距离比指数更快的增加)
Density
:强度Halo Texture(光源周围挥着光的纹理)
Halo Strength(光环可见性)
Flare Fade Speed(耀斑淡出时间,最初出现之后淡出的时间)
Flare Strength(耀斑可见性)
Spot Cookie(聚光灯剪影纹理)
碰撞产生的必要条件:
①两个物体都有碰撞器
②至少一个物体有刚体
RigidBody组件信息
1、Mass
(质量):质量越大惯性越大
2、Drag
(空气阻力):根据力移动对象时影响对象的空气阻力大小,0表示没有空气阻力
3、Angular Drag
:根据扭矩旋转对象时影响对象的空气阻力大小,0表示没有空气阻力
4、Use Gravity
:是否受重力影响
5、Is Kinematic
:如果启用此选项,则对象将不会被物理引擎驱动,只能通过(Transform
)对其进行操作。对于移动平台,或者如果要动画化附加了HingeJoint
的刚体,此属性将非常有用。
6、Interpolate
(插值运算):让刚体物体移动更平滑
None
:不应用插值运算Interpolate
:根据前一帧的变换来平滑变换Extrapolate
:插值运算,根据下一帧的估计变换来平滑变换7、Collsion Detection
(碰撞检测模式):用于防止快速移动的对象穿过其它对象而不检测碰撞
①Discrete
(离散检测)
②Continuous
(连续检测)
Continuous Dynamic
)的刚体将在测试与该刚体的碰撞时使用连续碰撞检测(此属性对物理性能有很大的影响,如果没有快速对象的碰撞问题,请将其保留为Discrete设置)③Continuous Dynamic
(连续动态检测)【性能消耗高】
Continuous
)和连续动态(Continuous Dynamic
)碰撞的游戏对象使用连续碰撞检测④Continuous Speculative
(连续推测检测)
8、Constraints
(约束):对刚体运动的限制
Freeze Position
:有选择地停止刚体沿世界X、Y和Z轴的移动Freeze Rotation
:有选择地停止刚体围绕局部X、Y和Z轴旋转碰撞器表示物体的体积(形状),刚体会利用体积进行碰撞计算,模拟真实的碰撞效果,产生力的作用。
3D碰撞器种类
1、盒状
2、球状
3、胶囊
4、网格
5、轮胎
6、地形
共同参数
1、Is Trigger
是否是触发器,如果启用此属性,则该碰撞体将用于触发事件,并被物理引擎忽略。主要用于进行没有物理效果的碰撞检测。
2、Material
物理材质,可以确定碰撞体和其他对象碰撞时的交互(表现)方式
3、Center
碰撞体在对象局部空间中心点位置
常用碰撞器
1、BoxCollider
(盒状碰撞器)
Size
:碰撞体在X、Y、Z方向上的大小2、Sphere Collider
(球状碰撞器)
Radius
:球形碰撞体的半径大小3、Capsule Collider
(胶囊碰撞器)
Radius
:胶囊体的半径Height
:胶囊体的高度Direction
:胶囊体在对象局部空间中的轴向异形物体使用多种碰撞器组合
刚体对象的子对象碰撞器信息参与碰撞检测
不常用碰撞器
1、Mesh Collider
(网格碰撞器)
Convex
:勾选此复选框可启用Convex
。如果启用此属性,该Mesh Collider
将与其他Mesh Collider
发生碰撞。Convex Mesh Collider
最多255个三角形。若该对象加了刚体,则必须勾选此复选框。
Cooking Options
:启用或禁用影响物理引擎对网格处理方式的网格烹制选项
①None
:禁用下方列出的所有Cooking Options
②Everything
:启用下方列出的所有Cooking Options
③Cook for Faster Simulation
:使物理引擎烹制网格以加快模拟速度。启用此设置后,这会运行一些额外步骤,以保证生成的网格对于运行性能最佳的。这会影响物理查询和接触生成的性能 。禁用此设置后,物理引擎会使用更快的烹制速度,并尽可能快速生成结果。因此,烹制的Mesh Collider
可能不是最佳的
④Enable Mesh Cleaning
:使物理引擎清理网格,。启用此设置后,烹制过程会尝试消除网格的退化三角形以及其他几何瑕疵。此过程生成的网格更适合于在碰撞检测中使用,往往可生成更准确的击中点
⑤Weld Colocated Vertices
:使物理引擎在网格中删除相等的顶点。启用此设置后,物理引擎将合并具有相同位置的顶点。这对于运行时发生的碰撞反馈十分重要
Mesh
:引用需要用于碰撞的网格
2、Wheel Collider
(环状碰撞器)
Mass
:车轮的质量
Radius
:车轮的半径
Wheel Damping Rate
:应用于车轮的阻尼值
Suspension Distance
:车轮悬梁的最大延伸距离(在局部空间中测量)。悬架始终向下延伸穿过局部Y轴
Force App Point Distance
:此参数定义车轮上的受力点。此距离应该是距车轮底部静止位置的距离(沿悬架行程方向),以米为单位。当forceAppPointDistance = 0
时,受力点位于静止的车轮底部。较好的车辆会使受力点略低于车辆质心
Suspension Spring
:悬架尝试通过增加弹簧力和阻尼力来到达目标位置
Forward Spring
:车轮向前滚动时轮胎摩擦的特性
Sideways Friction
:车轮侧向移动时轮胎摩擦的特性
注意:不必通过转动或滚动WheelColleder
对象来控制汽车;附加了WheelCollider
的对象应始终相对于汽车本身固定
3、Terrain Collider
(地形碰撞器)
Terrain Data
:地形数据
Enable Tree Colliders
:选中此属性时,将启用树碰撞体
Dynamic Friction
已在移动时使用的摩擦力。通常为0到1之间的值。值为0就像冰一样,值为1将对象迅速静止(除非用很大的力或重力推动对象)
Static Friction
当对象静止在表面上时使用的摩擦力。通常为0到1之间的值。值为0就像冰一样,值为1将导致很难让对象移动。
Bounciness
表面的弹性如何?值为0将不会反弹。值为1将在反弹时不产生任何能量损失,预计会有一些近似值,但可能只会给模拟增加少量能量。
Friction Combine
两个碰撞对象的摩擦力的组合方式
1、Average:对两个摩擦值求平均值
2、Minimum:使用两个值中的最小值。
3、Maximum:使用两个值中的最大值。
4、Multiply:两个摩擦值相乘。
unce Combine
两个碰撞对象的弹性的组合方式。其模式与Friction Combine模式相同。
注意: 碰撞和触发响应函数属于特殊的生命周期函数,也是通过反射调用
物理碰撞检测响应函数
//碰撞触发接触时会自动执行这个函数 private void OnCollisionEnter(Collision collision) { //关键参数 //1、碰撞到的对象碰撞器的信息 collision.collider //2、碰撞对象的依附对象(GameObject) collision.gameObject //3、碰撞对象的依附对象的位置信息 collision.transform //4、触碰点数相关 collision.contactCount //接触点具体的坐标 ContactPoint[] pos = collision.contacts; } //碰撞结束分离时会自动执行的函数 private void OnCollisionExit(Collision collision) { } //两个物体相互接触摩擦时会不停的调用该函数 private void OnCollisionStay(Collision collision) { }
触发器检测响应函数
//触发开始的函数,当第一次接触时会自动调用
private void OnTriggerEnter(Collider other)
{
}
//触发结束的函数
private void OnTriggerExit(Collider other)
{
}
//当两个对象水乳相融的时候会不停的调用
private void OnTriggerStay(Collider other)
{
}
什么时候会响应函数?
1、只要挂载的对象能和别的物体产生碰撞或者触发,那么对应的这6个函数,就能够被响应。
2、6个函数不是说我都得写,我们一般是根据需求来进行选择书写。
3、如果是一个异性物体,刚体在父对象上,如果通过子对象上挂脚本检测碰撞是不行的,必须挂载到这个刚体父对象上才行。
碰撞和触发器函数都可以写成虚函数,在子类重写逻辑
一般会把想要重写的碰撞和触发函数写成保护类型的,没有必要写成public,因为不会自己手动调用,都是untiy通过反射帮助我们自动调用的。
刚体添加力的方法
Rigidbody rigidBody; //1、首先应该获取刚体组件 rigidBody = this.GetComponent<Rigidbody>(); //2、添加力 //相对世界坐标 rigidBody.AddForce(Vector3.forward * 10);//世界坐标系z轴正方向加了一个力 //相对本地坐标 rigidBody.AddRelativeForce(Vector3.forward * 10); //在世界坐标系方法中让对象相对于自己的面朝向移动 rigidBody.AddForce(this.transform.forward * 10); //3、添加扭矩力,让其旋转 //相对世界坐标系 rigidBody.AddTorque(Vector3.up * 10); //相对本地坐标系 rigidBody.AddRelativeTorque(Vector3.up * 10); //4、直接改变速度 //相对于世界坐标系 rigidBody.velocity = Vector3.forward * 3; //5、模拟爆炸效果 //力大小,位置,半径 rigidBody.AddExplosionForce(10,Vector3.zero,10);
力的几种模式
动量定理:Ft = mv
v = Ft / m
t:时间
m:质量
v:速度
1、Acceleration
:给物体增加一个持续的加速度,忽略其质量
v
=
F
t
/
m
F
:
(
0
,
0
,
10
)
t
:
0.02
s
m
:默认为
1
v
=
10
∗
0.02
/
1
=
0.2
m
/
s
每物理帧移动
0.2
m
/
s
∗
0.02
=
0.004
m
v = Ft / m\\ F:(0,0,10)\\ t:0.02s\\ m:默认为1\\ v = 10 * 0.02 / 1 = 0.2m/s\\ 每物理帧移动0.2m/s * 0.02 = 0.004m\\
v=Ft/mF:(0,0,10)t:0.02sm:默认为1v=10∗0.02/1=0.2m/s每物理帧移动0.2m/s∗0.02=0.004m
2、Force
:给物体添加一个持续的力,与物体的质量有关
v
=
F
t
/
m
F
:
(
0
,
0
,
10
)
t
:
0.02
s
m
:
2
k
g
v
=
10
∗
0.02
/
2
=
0.1
m
/
s
每物理帧移动
0.1
m
/
s
∗
0.02
=
0.002
m
v = Ft / m\\ F:(0,0,10)\\ t:0.02s\\ m:2kg\\ v = 10 * 0.02 / 2 = 0.1m/s\\ 每物理帧移动0.1m/s * 0.02 = 0.002m\\
v=Ft/mF:(0,0,10)t:0.02sm:2kgv=10∗0.02/2=0.1m/s每物理帧移动0.1m/s∗0.02=0.002m
3、Impulse
:给物体添加一个瞬间的力,与物体的质量有关,忽略时间,默认为1
v
=
F
t
/
m
F
:
(
0
,
0
,
10
)
t
:
默认为
1
m
:
2
k
g
v
=
10
∗
1
/
2
=
5
m
/
s
每物理帧移动
5
m
/
s
∗
0.02
=
0.1
m
v = Ft / m\\ F:(0,0,10)\\ t:默认为1\\ m:2kg\\ v = 10 * 1 / 2 = 5m/s\\ 每物理帧移动5m/s * 0.02 = 0.1m\\
v=Ft/mF:(0,0,10)t:默认为1m:2kgv=10∗1/2=5m/s每物理帧移动5m/s∗0.02=0.1m
4、VelocityChange
:给物体添加一个瞬时速度,忽略质量,忽略时间
v
=
F
t
/
m
F
:
(
0
,
0
,
10
)
t
:
默认为
1
m
:默认为
1
v
=
10
∗
1
/
1
=
10
m
/
s
每物理帧移动
10
m
/
s
∗
0.02
=
0.2
m
v = Ft / m\\ F:(0,0,10)\\ t:默认为1\\ m:默认为1\\ v = 10 * 1 / 1 = 10m/s\\ 每物理帧移动10m/s * 0.02 = 0.2m\\
v=Ft/mF:(0,0,10)t:默认为1m:默认为1v=10∗1/1=10m/s每物理帧移动10m/s∗0.02=0.2m
力场脚本(Constant Force)
刚体休眠
if(rigidBody.IsSleeping())
{
rigidBody.WakeUp();
}
常用格式
1、wav
2、mp3
3、aiff
音频文件属性设置
1、Force To Mono
:多声道转单声道
Normalize
:强制为单声道时,混合过程中被标准化2、Load In Background
:在后台加载时,不阻塞主线程
3、Ambisonic
:立体混响声,非常适合360度视频和XR
应用程序,如果音频文件包含立体混响声编码的音频,请启用此选项
4、LoadType
:加载类型
Decompress On Load
:不压缩形式存在内存,加载快,但是内存占用高,适用于小音效Compress in memory
:压缩形式存在内存,加载慢,内存小,仅适用于较大音效文件Streaming
:以流形式存在,使用时解码。内存占用最小,cpu消耗高,性能换内存5、Preload Audio Data
:预加载音频,勾选后进入场景就加载,不勾选,第一次使用时才加载
6、Compression Format
:压缩方式
PCM
:音频以最高质量存储Vorbis
:相对PCM压缩的更小,根据质量决定ADPCM
:包含噪音,会被多次播放的声音,如碰撞声7、Quality
:音频质量,确定要应用于压缩剪辑的压缩量。不适用于PCM/ADPCM/HEVAG
格式
8、Sample Rate Setting
:PCM
和ADPCM
压缩格式允许自动优化或手动降低采样率
Preserve Sample Rate
:此设置可保持采样率不变(默认值)Optimize Sample Rate
:此设置根据分析的最高频率内容自动优化采样率Override Sample Rate
:此设置允许手动覆盖采样率,因此可有效地将其用于丢弃频率内容AudioSource(音频源)
1、AudioClip
(声音剪辑文件,音频文件)
2、Output
(默认将直接输出到场景中的音频监听器,可以更改为输出到混音器)
3、Mute
(静音开关)
4、Bypass Effect
(开关滤波器效果)
5、Bypass Listener Effects
(快速开关所有监听器)
6、Bypass Reverb Zones
(快速开关所有混响区)
7、Play On Awake
(对象创建时就播放音乐,也就是开关启动游戏就播放)
8、Loop
(循环)
9、Priority
(优先级)
10、Volume
(音量大小)
11、Pitch
(音高)
12、Stereo Pan
(2D声音立体声位置,相当于左右声道)
13、Spatial Blend
(音频受3D空间的影响程度)
14、Reverb Zone Mix
(到混响区的输出信号量)
15、3D Sound Settings
(和Spatial Blend参数成正比使用)
①Doppler Level
:多普勒效果等级
②Spread
:扩散角度设置为3D立体声还是多声道
③Volume Rolloff
:声音衰减速度
Logarithmic Rolloff
:靠近音频源时,声音很大,但离开对象时,声音降低的非常快Linear Rolloff
:与音频源的距离越远,听到的声音越小Custom Rolloff
:音频源的音频效果是根据曲线图的设置变化的④Min/Max Distance
:最小距离内,声音保持最大响度。最大距离外,声音开始减弱。
AudioListener(音频监听脚本)
AudioSource audioSource;
audioSource = this.GetComponent<AudioSource>();
代码控制播放停止
if(Input.GetKeyDown(KeyCode.P))
{
audioSource.Play();
}
if(Input.GetKeyDown(KeyCode.s))
{
audioSource.Stop();
}
if(Input.GetKeyDown(KeyCode.Space))
{
audioSource.Pause();
}
audioSource.unPause();
audioSource.playDaleyed(5);//延迟播放
如何检测音效播放完毕
audioSource.isPlaying//bool
如何动态控制音效播放
1、直接在要播放音效的对象上挂载脚本控制播放
2、实例化挂载了音效源脚本的对象,用的较少
Instantiate(obj);
3、用一个AudioSource来控制播放不同的音效
public AudioClip clip;
AudioSource aus = this.gameObject.AddComponent<AudioSource>();
aus.clip = clip;
aus.Play();
获取设备麦克风信息
Microphone.devices;
开始录制
//参数一:设备名,传空使用默认设备
//参数二:超过录制长度后,是否重头录制
//参数三:录制时长
//参数四:采样率
public AudioClip clip;
clip = Microphone.Start(null,false,10,44100);
结束录制
Microphone.End(null);
获取音频数据用于存储或者传输
//用于存储数组数据的长度是用声道数 * 剪辑长度
floatp[] f = new float[clip.channels * clip.samples];
clip.GetData(f,0);//第二个参数是偏移的位置
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。