|
其实我对游戏引擎有一个基础简单理解,那就是不断的进行一个循环,在这个周期循环之中会每一帧的进行一些表现渲染上的处理,处理的结果就是我们看到的游戏画面,当然也会有各种各样的逻辑上的处理。Unity是单线程的游戏引擎,为什么要做这个限制?因为游戏中逻辑更新和画面更新的时间点要求有确定性,必须按照帧序列严格保持同步,否则就会出现游戏中的对象不同步的现象。多线程也能保证这个效果,但如果引入多线程,会加大同步处理的难度与游戏的不稳定性。
unity有提供脚本周期,脚本的生命周期其实最最重要的就是这张图了,简单的可以把这个理解成,这是一个单线程的帧循环,每一次绘制都会重新走一遍生命周期。
image.png
FixedUpdate
FixedUFipdate,是每隔Time.fixedDeltaTime被调用一次。Time.fixedDeltaTime默认是0.02s,可以通过Edit->ProjectSettings->Time来设置。用来处理一些物理相关的内容,例如:给刚体加一个作用力时,你必须应用作用力在FixedUpdate里的固定帧,而不是Update中的帧(两者帧长不同)。
一个最简单的游戏循环大就是这样的,其中的frameTime 相当于,Time.deltaTime,它的时间其实是不固定的
image.png
那么如何实现FixedUFipdate 的固定增量时间呢,实现原理是 一个主循环中设置一个二级循环,以常量时间循环。
image.png
所以我们可以直接设置这个Time.fixedDeltaTime。
LateUpdate
线程,协程 (我们游戏用到了大量的异步操作,这些是怎么实现的吗?)
协程是什么呢?总体来说,对与Unity,它是单线程的设计,它更倾向使用time slicing(时间分片)的协程(coroutine)去完成异步任务,融合到了刚刚提到的生命周期中。
要理解协程,先回顾下线程:线程是操作系统级别的概念,现代操作系统都实现并且支持线程,线程的调度对应用开发者是透明的,开发者无法预期某线程在何时被调度执行。基于此,一般那种随机出现的BUG,多与线程调度相关。
而协程Coroutine是编译器级的,本质还是一个线程时间分片去执行代码段。它通过**相关的代码使得代码段能够实现分段式的执行,显式调用yield函数后才被挂起,重新开始的地方是yield关键字指定的,一次一定会跑到一个yield对应的地方。因为协程本质上还是在主线程里执行的,需要内部有一个类似栈的数据结构,当该coroutine被挂起时要保存该coroutine的数据现场以便恢复执行。
在Unity3D中,协程是可自行停止运行 (yield),直到给定的 YieldInstruction 结束再继续运行的函数。 协程 (Coroutines) 的不同用途:
yield; 在下一帧上调用所有 Update 函数后,协同程序将继续运行。
yield WaitForSeconds(2); 在指定的时间延迟之后,为此帧调用所有 Update 函数之后继续运行
yield WaitForFixedUpdate(); 在所有脚本上调用所有 FixedUpdate 后继续运行
yield WWW 完成 WWW 下载后继续运行。
yield StartCoroutine(MyFunc); 连接协同程序,并等待 MyFunc coroutine 首先结束。
也就是说,将代码段分散在不同的帧中,每次执行一段,下一帧再执行yield挂起的地方。
举个例子: 在OnStart()框架函数中调用startCoroutine(GetHttpData)执行以下代码端,其实是第一次发起网络请求,下一次执行时则走入yield之后的代码段继续执行,从而实现了一个时间分片的”异步”效果,而不是像线程那样在操作系统层面分CPU时间片去执行。
上面我们了解到了其实untiy是一个单线程的,但这些并不意味着无法在Unity中使用多线程,只是需要注意使用的场景。
试想一下,如果在帧序列的主循环单线程中处理大量耗时操作,势必会带来游戏画面的卡顿,帧率的下降。
因此,对于不是画面更新,也不是常规的逻辑更新(指包括AI、物理碰撞、角色控制这些),而是一些其他后台任务,则可以将这个独立出来开辟一个子线程。
所以,在不使用Unity SDK的前提下,确保做好主子线程的同步(采用C#中的delegate等机制),那么是可以合理使用子线程的。
概括起来,结合过往移动端的研发经验,我认为有以下几点可以在子线程中处理:
大量耗时的数据计算
网络请求<b> 复杂密集的I/O操作
Unity3D的NativePlugin中可以新建子线程。通过NativePlugin可以接入移动端iOS与Android中的成熟库,可以是Objective C, Java, C++三种语言交叉混合的方式组成NativePlugin,然后使用Android或者iOS的SDK开辟子线程。
参考:
https://blog.csdn.net/qq_28180261/article/details/64500720 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|