前言:记录了总6w字的面经知识点,文章中的知识点若想深入了解,可以点击链接学习。由于文本太多,按类型分开。这一篇是 Unity 常问问题总结,有帮助的可以收藏。
1. 生命周期
Awake —> OnEnable —> Start —> FixedUpdate —>Update —> LateUpdate—> OnGUl —> OnDisable —> OnDestroy
详细介绍
1. Awake
Awake用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次,Awake在所有对象被初始化之后调用,
当脚本设置为不可用时,运行时Awake方法仍然会执行一次。
所以你可以安全的与其他对象对话或用诸如GameObject.FindWithTag 这样的函数搜索它们。每个游戏物体上的Awake以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息,Awake总是在Start之前被调用。它不能用来执行协同程序。
2. OnEnable
当对象变为可用或激活状态时被调用事件监听。
3. Start
Start在behaviour的生命周期中只被调用一次。它和Awake的不同是Start只在脚本实例被启用时调用。你可以按需调整延迟初始化代码。Start总是在Awake之后执行。这允许你协调初始化顺序。
4. Update
Update每帧调用一次用于更新游戏场景和状态,比较适合做控制。
5. FixedUpdate
每隔固定物理时间间隔调用一次用于物理状态的更新,和Update不同的是FixedUpdate逻辑帧,Update是渲染帧。如果帧率很低,可以每帧调用该函数多次;如果帧率很高,可能在帧之间完全不调用该函数。
FixedUpdate 内应用运动计算时,无需将值乘以 Time.deltaTime。这是因为 FixedUpdate 的调用基于可靠的计时器(独立于帧率)。
详细请看:FixedUpdate真的是固定的时间间隔执行吗?聊聊游戏定时器 - 慕容小匹夫 - 博客园0x00 前言 有时候即便是官方的文档手册也会让人产生误解,比如本文将要讨论的Unity引擎中的FixedUpdate方法。 This function is called every fixed fhttps://www.cnblogs.com/murongxiaopifu/p/7683140.html
6. LateUpdate
每帧调用一次(在 update 之后调用) 用于更新游戏场景和状态,和摄像机相关的更新。
官网上例子是摄像机的跟随,都是所有的Update操作完才进行摄像机的跟进,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。
7. OnGUI
OnGUI 渲染和处理 OnGUI 事件。
8. OnDisable
OnDisable 当对象变为不可用或非激活状态时被调用事件移除。
9. OnDestroy
OnDestroy 当对象被销毁时调用。
2. 如何让已经存在的GameObject在LoadLevel后不被卸载掉
DontDestroyOnLoad(transform.gameObject);
3. 碰撞
物体发生碰撞的必要条件
两个物体都必须带有碰撞器Collider,其中一个物体还必须带有Rigidbody刚体。
碰撞器与触发器
1.碰撞器是触发器的载体,而触发器只是碰撞器身上的一个属性。
2. 当ls Trigger=false时,碰撞器根据物理引擎引发碰撞,产生碰撞的效果,可以调用OnCollisionEnter/Stay/Exit函数;
3.当ls Trigger=true时,碰撞器被物理引擎所忽略,没有碰撞效果,可以调用OnTriggerEnter/Stay/lExit函数。
4. 如果既要检测到物体的接触,又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域,这时就可以用到触发器。
4. 协程(进程/线程)
1. 概念
进程
保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,不同进程间可以进行进程间通信,上级挂靠单位是操作系统。一个应用程序相当于一个进程,操作系统会以进程为单位,分配系统资源(CPU 时间片、内存等资源),进程是资源分配的最小单位。
线程
线程从属于进程,也被称为轻量级进程,是程序的实际执行者。线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程只有一个进程。
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程
协程是伴随着主线程一起运行的一段程序。
注意点:
协程与协程之间是并行执行,与主线程也是并行执行,同一时间只能执行一个协程提起协程,自然是要想到线程,因为协程的定义就是伴随主线程来运行的!
一个线程可以拥有多个协程,协程不是被操作系统内核所管理,而完全是由程序所控制。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
协成是单线程下由应用程序级别实现的并发。
2.线程与协程的区别
协同程序与多线程情况下的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针,但与其它协同程序共享全局变量等很多信息。
协程(协同程序): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。
线程: 同一时间可以同时执行多个线程。开辟多条线程开销很大。线程适合多任务同时处理。
1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程实际上是在一个线程中,只不过每个协程对CPU进行分时,协程可以访问和使用unity的所有方法和component。
2.线程,多线程是阻塞式的,每个IO都必须开启一个新的线程,但是对于多CPU的系统应该使用thread,尤其是有大量数据运算的时刻,但是IO密集型就不适合;而且thread中不能操作unity的很多方法和component。
线程和协同程序的主要不同在于:在多处理器情况下,从概念上来讲多线程程序同时运行多个线程;而协同程序是通过协作来完成,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只在必要时才会被挂起。
2. 协程作用
在Unity中只有主线程才能访问Unity3D的对象、方法、组件。当主线程在执行一个对资源消耗很大的操作时,在这一帧我们的程序就会出现帧率下降,画面卡顿的现象!
那这个时候我们就可以利用协程来做这件事,因为协程是伴随着主线程运行的,主线程依旧可以丝滑轻松的工作,把脏活累活交给协程处理就好了!简单来说:协程是辅助主线程的操作,避免游戏卡顿。
3. 操作
3.1定义协程
IEnumerator Test(string str)
{
//代码块
Debug.Log("协程被启动了!"+ str);
yield return null;
//代码块
}
3.2 启动协程
1. Startcoroutine (string methodName):通过协程的方法名(字符串形式)启动。
2. StartCoroutine (string methodName,object values):带参数的通过方法名(字符串形式)进行调用。
3. Startcoroutine (IEnumerator routine):通过调用方法的形式启动。
3.3 停止携程
1.stopcoroutine (string methodName):通过方法名(字符串)来关闭协程。
2.stopCoroutine(IEnumerator routine):通过调用方法的形式来关闭协程。
3.stopCoroutine(Coroutine routine):通过指定的协程来关闭。
4.stopAllCoroutine() 的作用是停止所有该脚本中启动的协程。
void StopTest()
{
//第一种方式:通过调用方法的形式来关闭协程
StopCoroutine(Test1());
//第二种方式:通过方法名(字符串)来关闭协程
StopCoroutine("Test1");
//第三种方式:通过指定的协程来关闭
Coroutine a = StartCoroutine(Test1());
StopCoroutine(a);
//关闭该脚本中启动的所有协程!
StopAllCoroutines();
}
4. 底层原理
协程是通过迭代器来实现功能的,通过关键字IEnumerator来定义一个迭代方法。
注意:提起IEnumerator就会想到IEnumerable,可千万不能搞混了!
StartCoroutine 接受到的是一个 IEnumerator ,这是个接口,并且是枚举器或迭代器的意思。
yield 是 C#的一个关键字,也是一个语法糖,背后的原理会生成一个类,并且也是一个枚举器,而且不同于 return,yield 可以出现多次。
yield 实际上就是返回一次结果,因为我们要一次一次枚举一个值出来,所以多个 yield 其实是个状态模式,第一个 yield 是状态 1,第二个 yield 是状态 2,每次访问时会基于状态知道当前应该执行哪一个 yield,取得哪一个值。
从程序的角度讲,协程的核心就是迭代器。想要定义一个协程方法有两个因素,第一:方法的返回值为 IEnumerator 。第二,方法中有 yield关键字。当代码满足以上两个条件时,此方法的执行就具有了迭代器的特质,其核心就是 MoveNext方法。方法内的内容将会被分成两部分:yield 之前的代码和 yield 之后的代码。yield之前的代码会在第一次执行MoveNext时执行, yield之后的代码会在第二次执行MoveNext方法时执行。而在Unity中,MoveNext的执行时机是以帧为单位的,无论你是设置了延迟时间,还是通过按钮调用MoveNext,亦或是根本没有设置执行条件,Unity都会在每一帧的生命周期中判断当前帧是否满足当前协程所定义的条件,一旦满足,当前帧就会抽出CPU时间执行你所定义的协程迭代器的MoveNext。注意,只要方法中有yield语句,那么方法的返回值就必须是 IEnumerator ,不然无法通过编译。
详细请看:
https://blog.csdn.net/xiaoyaoACi/article/details/119957547?csdn_share_tail=%7B"type"%3A"blog"%2C"rType"%3A"article"%2C"rId"%3A"119957547"%2C"source"%3A"qq_35787977"%7Dhttps://blog.csdn.net/xiaoyaoACi/article/details/119957547?csdn_share_tail=%7B:,:,:,:%7D
测试:
解释:a:Start函数正常运行
b:Update函数正常运行
c: 进入协程
d:协程挂起,正常运行Update函数
b:Update函数正常运行
c: 进入协程
d:协程挂起,正常运行Update函数
e: 因为协程是yield return null等待一帧后,第一帧的协程由挂起,变成正常运行,输出e。
5. Invoke与InvokeRepeating
1. Invoke
Invoke() 方法是 Unity3D 的一种委托机制文章来源:https://www.toymoban.com/news/detail-783945.html
如: Invoke("Test", 5); 它的意思是:5 秒之后调用 Test() 方法;文章来源地址https://www.toymoban.com/news/detail-783945.html
到了这里,关于Unity游戏开发客户端面经——Unity(初级)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!