Unity学习笔记--FixedUpdate真的是固定时间调用一次吗?

news2024/11/25 20:31:15

前言

我相信大家在学习Unity的时候,Update是每一帧调用,而FixedUpdate是固定时间调用一次。
一开始我们对这个知识深信不疑(楼主也是 =.=| )

不过当我们学的更深入时,发现Unity其实是单线程的,所以它的生命周期肯定也是同步的

引出问题

那么疑问就来了,既然是单线程的,那假设我现在机器卡了,可能1秒才调用一次Update,也就是1帧,那么假设FixedUpdate的更新频率是50FPS(0.02s),那么FixedUpdate还会每隔0.02时间调用一次吗?

猜测

由于我们知道Unity是单线程的,那么肯定不会单独给FixedUpdate开一个线程,然后调用它。
所以我们猜测FixedUpdate其实不是每隔固定一个真实世界的时间调用一次

推测

如果我们来重复一下各位测试FixedUpdate时经常采用的方式:打印两次调用之间的时间间隔,或者是计算每次调用的累积时间,但区别在于我直接使用了真实的时间:

void FixedUpdate()
{
    Debug.Log("FixedUpdate realTime: " + Time.realtimeSinceStartup);
}

void Update()
{
    Debug.LogError("Update realTime: " + Time.realtimeSinceStartup);
}

为了以示区别,正常的Log是FixedUpdate,LogError是Update,并且设定整个游戏的更新频率为30FPS。

在这里插入图片描述
(图片来自网络)

通过上图可以发现,FixedUpdate并不是间隔0.02s才调用一次,相反,它有可能在Update之前调用多次。

例如刚启动时,在某次Update之前连续调用了11次FixedUpdate,而之后每次Update调用之前都会调用1~2次FixedUpdate方法,这也很好理解,因为FixedUpdate的频率是50FPS,而我们设定的更新频率为30FPS,FixedUpdate的调用次数势必要多于Update。

所以,FixedUpdate除了用来处理物理逻辑之外并不适合处理其他模块的逻辑,尤其是当大家的潜意识里都笃定它的更新频率是固定的时候。因为这很危险,比如一个需要状态同步的游戏要求按照固定的频率向目标同步状态,如果贸然采用FixedUpdate方法,就会出现上图那样可能在短时间内多次调用的问题。所以最好只在物理逻辑的处理中使用FixedUpdate,而不要滥用。

可变增量时间

ok,那我们来看看游戏引擎的定时器是如何来实现的吧。假设我们手头没有一个现成的游戏引擎,一切都需要自己来实现,那么一个最简单的游戏循环大概就是下面这个样子的。

double lastTime = Timer.GetTime();
...

while (!quit()){

  double currentTime = Timer.GetTime();
  double frameTime = currentTime - lastTime ;

  UpdateWorld(frameTime);
  RenderWorld();

  lastTime = currentTime;
}

这种实现方式使得增量时间和具体的机器设备相关,并且它每一次的时间增量都不一定相同。

当机器十分快时,引擎可能通过线程休眠来保证固定的FPS。

while(timeout > 0.001 && deltaTime<timeout)
{
    //...休眠后计算新的增量时间
}

所以看上去整个游戏保证一个大致的更新频率似乎不难。但是现在问题的关键在于每次更新时的时间增量无法保证相同。而在物理模拟中,保证一个固定的增量时间是十分重要的。这是因为在游戏引擎进行物理模拟时要使用数值积分,而作为最简单的数值积分方法——欧拉法在游戏引擎中大量使用。

由于此时计算的是真实的时间,而真实的增量时间无法保证固定,那换一个思路,我们把参与物理模拟的增量时间当做一个常量可以吗?换句话说,不论游戏的更新频率如何,参与物理模拟的增量时间是一个常数。

固定增量时间

一个最简单的固定增量时间的实现,显然就是将固定的增量时间作为一个常量参数传递给物理模拟模块,这样我们就能够保证物理模拟的增量时间固定,同时还能将物理模拟的更新频率和游戏引擎的更新频率进行解耦——物理的模拟不受引擎的更新频率影响,无论游戏的更新频率是多少,传递给物理模拟的增量时间都是一个常量。

这里还拿Unity引擎来举例子,默认情况下项目的Fixed Timestep的值为0.02s。也就是说物理模拟的频率是50FPS,假设我们的游戏的更新频率是25FPS,那么会发生什么呢?没错,游戏每1次Update时,物理模拟都要推进2次,也就是之前我们看到的在Update之前多次调用了FixedUpdate。那么如果我们的游戏更新频率是100FPS呢?这次就变成了每2次Update调用1次FixedUpdate。

这也就解释了为何有的朋友在做相关的小测试的时候,在每次FixedUpdate内打印Time.deltaTime时输出的都是0.02了,因为在FixedUpdate方法内获取Time.deltaTime并非两次调用FixedUpdate之间真实的时间间隔,而是来自我们在项目的Time设置内设置的值——它是一个与真实时间无关的常量。

那么这种固定增量时间的逻辑如何用代码表示呢?很简单,只需要在主循环的内部,再来一个二级循环。

double  simulationTime = 0;
double  fixedTime = 20;

while (!quit()){

  double  realTime = Timer.GetTime();

  while (simulationTime < realTime){
         simulationTime += fixedTime; 
         UpdateWorld(fixedTime);
  }

  RenderWorld();
}

而Unity的实现显然也是类似的,这个在Unity手册中关于执行顺序的相关章节内可以看到。

在这里插入图片描述

上图标明了FixedUpdate是属于物理模拟模块的,同时在主循环的内部,物理模拟的部分还有一个二级循环。

总结

FixedUpdate其实按照严格意义上来说,不会是每隔一个固定时间调用一次。注意:我说的是调用一次。

例如现在游戏1秒内调用10次Update,也就是0.1秒调用一次,假设FixedUpdate的更新频率是50FPS(0.02s),那么Update执行一次,FixedUpdate应该执行5次

那么就会出现下面的情况

while(!quit())
{
	// 由于Unity的生命周期,所以FixedUpdate会比Update先执行
	FixedUpdate();//第一次
	FixedUpdate();//第二次
	FixedUpdate();//第三次
	FixedUpdate();//第四次
	FixedUpdate();//第五次
	
	Update();
}

其实可以看做Unity自己计算了距离上一次循环隔了多久,然后计算出FixedUpdate实际应该执行多少次。

参考资料:FixedUpdate真的是固定的时间间隔执行吗?聊聊游戏定时器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决d2l包下载不了的问题

目录 关于d2l包 1、在pypi网站的找到d2l包 2、cmd下载文件 3、检测d2l包的下载是否成功 4、在虚拟环境中完成安装 关于d2l包 d2l包是李沐老师等人开发的《动手深度学习》配套的包&#xff0c;最初的时候&#xff0c;我并没有安装的想法&#xff0c;可在代码实现方面&…

如何使用 max_fanout

在 逻辑层级不多&#xff0c;但是延时较高的 net 中&#xff0c;可以使用 max_fanout 来设置扇出&#xff0c; 但是要注意&#xff0c;还要如果驱动与负载不在同一层&#xff0c;一定要约束到负载的input&#xff0c;否则不生效 并且还要在 例化负载模块时加上 (* keep_hiera…

nacos安装及配置

本文介绍nacos的安装、配置&#xff0c;使用mysql存储数据。 1.下载 在github上下载对应的压缩包。地址&#xff1a;https://github.com/alibaba/nacos/releases 本文下载的是2.0.2版本&#xff1a; 2.解压 进入下载文件所在的目录&#xff0c;并执行以下语句&#xff1a; t…

GEE10:Earth Engine Reducers的图像矢栅转换及区域统计

目录1. Raster to Vector Conversion&#xff1a;image.reduceToVectors()2. Vector to Raster Conversion&#xff1a;featureCollection.reduceToImage()3. Grouped reductions3.1 Grouped reduceRegions (aka Zonal Statistics)4. Weighted Reductions1. Raster to Vector C…

SSM整合案例[企业权限管理系统]-学习笔记01【SVN的基本介绍】

Java后端-学习路线-笔记汇总表【黑马程序员】SSM整合案例[企业权限管理系统]-学习笔记01【SVN的基本介绍】【day01】SSM整合案例[企业权限管理系统]-学习笔记02【TortoiseSVN的基本操作】SSM整合案例[企业权限管理系统]-学习笔记03【TortoiseSVN及IDEA下SVN的使用】SSM整合案例…

四旋翼无人机学习第21节--allergo软件中的元器件高亮显示与丝印3D显示设置

1 allergo软件中的元器件高亮显示 在设计PCB的时候&#xff0c;会出现元器件高亮的情况&#xff0c;并且在项目重启后&#xff0c;这种现象依然存在。现在终于找到了原因的所以。点击高亮的元器件&#xff0c;右键选择选择Dehighlight即可。 取消高亮后的元器件显示。 2 解决…

已解决Building wheels for collected packages: lxml

已解决&#xff08;pip安装第三方模块lxml模块报错&#xff09;Building wheels for collected packages: lxml Building wheel for lxml (setup.py) … error error: subprocess-exited-with-error python setup.py bdist_wheel did not run successfully. note: This error o…

Polar vector and axial vector(极矢量和轴向矢量)

Polar vector and axial vector引言Polar vector中文翻译定义第一种第二种第三种性质举例Axial vector中文翻译定义性质举例讨论引言 今天来给大家介绍一下Polar vector和axial vector&#xff0c;即极矢量和轴向矢量。 Polar vector 中文翻译 极矢量 定义 第一种 在基础…

倍增算法讲解——序列、RMQ和LCA

倍增算法 文章目录倍增算法定义倍增在序列上的应用查找例一例二快速幂RMQ&#xff08;区间最值&#xff09;天才的记忆LCA&#xff08;最近公共祖先&#xff09;向上标记法树上倍增法祖孙询问Tarjan算法距离总结定义 倍增 从字面的上意思看就是成倍的增长 ,这是指我们在进行递…

C++系列案例-大数据减法-绘制余弦曲线-兔子数量-快速排序

文章目录关于C的几个经典案例代码大数减法问题绘制余弦曲线兔子数量问题快速排序问题函数运行全部源码关于C的几个经典案例代码 大数减法问题 因为较大整数的相加很可能超出整型的32位限制&#xff0c;或者本身就是超出限制的大数之间的加减运算。 所以我们需要单独写一个能大…

C语言程序设计易混、易错知识点(下篇)

有环的单向链表跟无环的单向链表不可能相交 -正确 有环的单向链表和无环的单向链表不能相交&#xff0c;因为当相交的时候&#xff0c;无环的单向链表也会被迫存在一个环&#xff0c;只不过这个环的”起点“可能不是原来单向链表的头结点 如果两个单向链表相交&#xff0c;那这…

Vmware Pro 17 设置共享文件夹

目录 一、概述 二、在VMware设置共享文件夹详细步骤 一、概述 VMware 是运行在Windows系统上的&#xff0c;很多时候需要将 Windows 系统上的资料或代码复制到运行在VMware上的虚拟机&#xff0c;通常有两种方法可以完成复制&#xff0c;一个是在Vmware软件上设置共享文件夹&…

网络分层模型和应用协议

网络分层模型和应用协议 分层模型 分层模型的意义 当遇到一个复杂问题的时候&#xff0c;可以使用分层的思想把问题简单化。 比如&#xff0c; 你有一杯82年的可乐&#xff0c;想要分享给你的朋友张富贵&#xff0c;但你们已经很久没有联系&#xff0c;要完成这件事&#xf…

《深入浅出计算机组成原理》学习笔记 Day2

文章目录指令篇1. 从高级语言到机器指令1.1 CPU的作用1.2 代码如何变为机器码1.3 指令的分类2. 指令跳转2.1 CPU 是如何执行指令2.2 条件和循环的本质3. 函数调用3.1 栈的作用3.2 Stack Overflow指令篇 1. 从高级语言到机器指令 计算机或者说CPU本身并没有能力去理解这些高级…

配置远程服务器时候sftp的配置以及注意事项【在本地配置sftp】

我之所以不用PutTy是因为这个工具有问题&#xff0c;在我的电脑上怎么也安装不上&#xff0c;也找了很多办法根本没用。如这个 我试过修改权限以及各种安装办法连安装都不行。 所以才决定直接使用vscode自带的上传工具上传到服务器。 想要上传到服务器&#xff0c;需要使用vsc…

2023牛客寒假算法基础集训营1 -- G-鸡格线(map + 内置二分写法)

题目如下&#xff1a; 示例1 输入 3 5 0 2 114514 2 1 1 2 2 2 1 1 3 1 2输出 114516 114551 3445思路 or 题解&#xff1a; 通过 f(x)round(10∗x)f(x) round(10*\sqrt{x})f(x)round(10∗x​) 我们可得到&#xff1a; 经过至多 111111 次 0 -> 01~99 -> 99100 ~ i…

如何利用jar命令把前端代码打进jar包

目录背景介绍简单介绍几个常用的jar命令参数查询一个文件在jar包中的位置将文件解压到当前目录把一个目录打包进jar把一个文件打包进jar更新jar的shell脚本update.sh命令执行过程部分截图背景介绍 前后端分离是目前主流的开发模式&#xff0c;部署的时候也是利用类似nginx实现…

C++之多态

文章目录一、多态的理解二、多态的定义及实现1.多态的构成条件2.虚函数3.虚函数的重写/覆盖4. C11 的 override 和 final5.重载、重写/覆盖、隐藏/重定义三、抽象类四、多态的原理1.虚函数表2.多态的原理3.动态绑定与静态绑定五、单继承和多继承关系的虚函数表1.单继承中的虚函…

【Git】IDEA 集成 Git

7、IDEA 集成 Git 7.1、配置 Git 忽略文件 1、Eclipse 特定文件 2、IDEA 特定文件 3、Maven 工程的 target 目录 问题 1:为什么要忽略他们&#xff1f; 答&#xff1a;与项目的实际功能无关&#xff0c;不参与服务器上部署运行。把它们忽略掉能够屏蔽 IDE 工具之间的差异。 …

联合变换相关器摄远物镜光学设计

联合变换相关器摄远物镜光学设计 联合变换相关器工作原理 随着科学技术的飞速发展&#xff0c;光学相关探测器件由最初的匹配滤波器发展到今天的联合变换相关器&#xff0c;联合变换相关器与范得耳-卢格特相关器相比&#xff0c;具有灵活性好、识别精度高等特点&#xff0c;所…