Update主循环的实现原理
从写一段程序,到写一个app,写一个游戏,到底其中有什么不同呢?一段程序的执行时间很短,一个应用的执行时间很长,仅此而已。
游戏中存在一个帧的概念。
这个概念大家都知道,类比的话,它就是电影胶卷的格。一格出现一段时间,然后换下一格。
电影一秒24格,游戏用的是一秒30帧,60帧。
电影胶片是在镜头前一格一格的放映,游戏逻辑是在update中一帧一帧的执行。
那么Update函数的驱动是如何完成的呢?
这个东西就是主循环
先来看看一个基本的控制台程序
唔,helloworld,这个程序我们已经很熟悉了。一闪而过的那个版本。因为他执行然后马上就结束了。
那么这个版本呢?
你会说,我去,你写了一个死循环。
是的,主循环就是一个死循环。有了这个死循环,一段程序就能逐渐成为一个应用,一个游戏。
让我们把update拆出来,是不是看起来有点熟悉了。
再来个OnStart,是不是更加熟悉了
原来unity的MonoBehaviour就是这样啊。
任何的程序中都存在着主循环,在常用的界面框架中,通常隐藏主循环,留下事件型的接口。
主循环很简单吧,仅仅是看起来这样。
游戏程序通常事件型的框架不多,大部分逻辑需要从主循环层次开始组建,也就是你需要对主循环的理解非常深,能够从主循环上创建很多种模式的逻辑。
我们开始来介绍几个常见的
主循环和定时器
试想如下需求,需要每三秒钟打印一条log,怎么做这个三秒钟的计时?
电影是24格,每秒钟24帧,稳定的,雷打不动。通过数帧就知道个大概。
可是大家都知道游戏的帧率是跳跃的,每一帧的时间不固定。
Unity提供了一个参数,告诉你上一帧开始,到这一帧开始经过的时间,单位为秒 Time.Deltatime;
因为每一帧开始到上一帧开始的间隔给你了。只要把他们累加起来,就是一个计时器。你可以用秒表确认一下这个程序,他的表现和你的秒表一样精准,分毫不差。
这就是一个计时器了,一个用不稳定的帧速率的主循环驱动的计时器。只是他光计时了,啥也没干,我们来让他做点什么。
这个计时器是最基本的一个逻辑,固定帧率在游戏中只是一个理想化状态,大部分情况下无法实现固定帧率。
几乎所有的游戏逻辑都涉及到计时问题,都会涉及到如何在浮动帧率时进行逻辑控制。
时间是连续累加的,请时刻记住这一点。
主循环与缓动
用定时器去驱动数值的变化,在一些情况下,被称为缓动,dotween,itween,名字里有个tween的这类库或者插件,都是做缓动的。
他们包装了各式各样的缓动的模式代码,帮你节约一点时间。
我们来让一个box 3秒钟从A点移动到B点,所有缓动的系统中都采用这样一个考虑方式,零为开始,一为结束。那么我们让我们的timer 几秒完成一个从零到一的过程,这就是一个缓动的周期。
就用我们之前的代码去考虑,我们的timer 加到3秒,然后变小,再到三,再变小,ok。直接给timer+=的时候乘一个系数可以改变timer变化的速度,可以调节为三秒钟完成从零到一,但是我们入门篇讲过,好代码从命名开始,既然他叫做timer,他就不应该从零到一,从零到一的标识的是缓动的进度。
取名为lerp
如上代码就完成了一个缓动逻辑,把这个脚本给一个cube,然后begin end 填入不一样的值,跑起来看看。
无论你用了什么高大上的缓动库,知其然总是有好处的,而这,就是缓动框架背后的事情。
主循环和状态机
入门篇我们就讲了一个时空观的问题,这个用程序的概念就是状态,图灵机、冯诺依曼机,是计算机的基础,这个基础说的就是状态机。
即使从更大的尺度来看,高级语言来看。在顺序执行的程序体系中,状态机依然是编程的基础。
我们前面告诉过大家单步调试,每一个断点,就是一个状态。
程序是由一个一个的状态构成的。
再从更大的尺度看,功能模块和程序结构的角度,状态机依然是功能的基础,我现在处于主菜单还是战斗菜单?我现在是在充值还是还消费?
同级别的功能某一时刻必然处于某一功能中,是我们的设计基础。
游戏框架从哪里开始,必然从状态的分割开始。有些框架提供了一个比状态机更高级一点的模式,导航器,其实也属于状态机,但是导航器记录着之前的状态,可以NavBack。
导航器模式是什么?随便点开一个手机app,点一个功能,再点一个功能,然后按back,back,这就是导航器。
现在由于手游流行起来,游戏界面效法了很多app的设计,所以现在导航器设计是一个非常主流的设计。
由于我们只是一个抛砖引玉的提高过程,我们这里不会去写一个导航器框架出来,我们只是去解释状态机背后的行为。
这个状态代码这么写,有点长,我们分两段来看,一段是update函数
一段是ongui函数
仔细看过这段代码,你也许会说,你骗人,这是个锤子的状态机哦,这就是个if else
这就是个if else,状态机的本质就是switch case,就是 if else,除非,给他一个结构化的设计。
当你的逻辑状态只有两三个的时候,if else,未尝不可。然后我们来把他结构化一下吧。
看看结构化之后的代码
我们抽象出一个表达状态的接口,于是主要的代码变得非常简洁,这就是一个状态机咯。
不过实现代码就不那么简洁了
有这样的设计作为基础,添加再多的状态也不怕啦,不过这也只是一个解释用的代码。
实际操作时肯定比这个面对的问题要更复杂一些。
题外话:JAVA语言,JAVA字节码,JAVA运行时,JAVA基本类库,都叫java。
而微软这边分别叫C#语言,MSIL字节码,dotnet运行时,dotnet framework。其实就是为了怕被告。
Update主循环的实现原理的更多相关文章
- Update主循环、状态机的实现
从写一段程序,到写一个app,写一个游戏,到底其中有什么不同呢?一段程序的执行时间很短,一个应用的执行时间很长,仅此而已. 游戏中存在一个帧的概念. 这个概念大家都知道,类比的话,它就是电影胶卷的 ...
- cocos2d-x游戏引擎核心之三——主循环和定时器
一.游戏主循环 在介绍游戏基本概念的时候,我们曾介绍了场景.层.精灵等游戏元素,但我们却故意避开了另一个同样重要的概念,那就是游戏主循环,这是因为 Cocos2d 已经为我们隐藏了游戏主循环的实现.读 ...
- c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)
c#封装DBHelper类 public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...
- 辛巴学院-Unity-剑英的c#提高篇(一)主循环
这是测试版 辛巴学院:正大光明的不务正业. 最近刚刚离开了我服务了三年多的公司,因为一个无数次碰到的老问题,没钱了. 之前不知道做什么好的时候,机缘巧合之下和哒嗒网络的吴总聊了一下,发现了vr gam ...
- Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器
保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈. 一.游戏主循环GameSchedule 主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的 ...
- PBRT笔记(1)——主循环、浮点误差
PBRT2与3之间的改动 增加了一个功能完备的BRDF模型,支持体积光照与重要性多重路径采样. 次表面散射,基于光线追踪技术,无需预处理. 解决浮点数四折五入的问题 光子映射 样本生成 第一章多了讲并 ...
- MYSQL 的 MASTER到MASTER的主主循环同步
MYSQL 的 MASTER到MASTER的主主循环同步 刚刚抽空做了一下MYSQL的主主同步.把步骤写下来,至于会出现的什么问题,以后随时更新.这里我同步的数据库是TEST1.环境描述. 主 ...
- master线程的主循环,后台循环,刷新循环,暂停循环
InnoDB存储引擎的主要工作都是在一个单独的后台线程master thread中完成的.master thread的线程优先级别最高.其内部由几个循环(loop)组成:主循环(loop).后台循环( ...
- glib简单记录包括字符串,主循环,回调函数和xml解析
一.将最近用到的glib字符串功能整理了下直接用程序记录比较好看懂 #define MAX_LEN 100gchar * demo (char* msg, ...){ gchar * pcfgf ...
随机推荐
- CodeForces 489B BerSU Ball (水题 双指针)
B. BerSU Ball time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- 猜socklen_t的原型
编写tcp时碰到这个类型,感觉他就是int型. 百度了一下: typedef int socklen_t typedef int ssize_t 我去/usr/include 下grep -r soc ...
- CF 148D D Bag of mice (概率dp)
题目链接 D. Bag of mice time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- view如何从action中取得数据和 Html辅助方法
方式:1使用弱类型取,2,使用强类型,两者的差别在于view页面最上方声明的方式 如果使用弱类型接受来自控制器的数据,在view页面里完全不需要有任何的生命,数据可以从ViewData,ViewB ...
- JS中map list 数组的迭代
后台传给前台一个map 前台如何迭代呢 $.post("getSys.jhtml", function(data){ var temp = ""; $.each ...
- 剑指Offer的学习笔记(C#篇)-- 对称的二叉树
题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 一 . 题目分析 递归法. 一.空树判断,单独搞出来. 二.非空树. 递归:一 ...
- 14.插入数据、复制数据--SQL
一.插入完整的行 要求指定表名和插入到新行中的值 INSERT INTO Customers ', 'Toy Land', '123 Any Street', 'New York', 'NY', ', ...
- js json与字符串相互转换
JSON.parse(jsonstr); //可以将json字符串转换成json对象 JSON.stringify(jsonobj); //可以将json对象转换成json对符串
- [软件工程基础]2017.11.05 第九次 Scrum 会议
具体事项 项目交接燃尽图 每人工作内容 成员 已完成的工作 计划完成的工作 工作中遇到的困难 游心 #10 搭建可用的开发测试环境:#9 阅读分析 PhyLab 后端代码与文档:#8 掌握 Larav ...