详解Unity中Time类的用法与深入探究

这篇具有很好参考价值的文章主要介绍了详解Unity中Time类的用法与深入探究。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在游戏世界中,时间无疑是最为重要的参数,它是游戏世界能否正常运转的关键。一旦它出错,轻则卡顿,重则游戏世界崩坏。在使用Unity引擎创造的世界中,Time类无疑是必须要掌握的一个类,它是控制时间的关键,是造物主最为重要的权柄,有了它,我们就可以肆意的玩弄我们所创造的游戏世界,一言万年。

很中二的前言hhh,但Time类真的非常重要,本篇主要讲解一下Time类的各个API,以及它们对Unity各项系统的影响。

Unity版本[2019.4.10f1] 梦小天幼 & 禁止转载

视频讲解:
【详解Unity】Time类与深入探究


一、Time类基础

1.Time类总览

大概浏览一遍即可,后续讲解到某个属性再翻回来看

变量 释义
总时间
Time.time 从游戏开始到现在所用的时间
Time.unscaledTime 从游戏开始到现在所用的时间(不受timeScale影响)
Time.fixedTime 从游戏开始到现在所用的时间
Time.fixedUnscaledTime 从游戏开始到现在所用的时间(不受timeScale影响)
Time.realtimeSinceStartup 游戏开始以来的实际时间
Time.timeSinceLevelLoad 自最后一个非添加场景(non-additive scene)完成加载以来的时间
增量时间
Time.deltaTime 帧间隔时间
Time.unscaledDeltaTime 帧间隔时间(不受timeScale影响)
Time.fixedDeltaTime 固定间隔帧时间
Time.fixedUnscaledDeltaTime 固定间隔帧时间(不受timeScale影响)
Time.smoothDeltaTime 经过平滑处理的Time.deltaTime
其他
Time.frameCount 总帧数
Time.timeScale 时间流逝尺度,1正常速度,2则2倍速
Time.inFixedTimeStep 在FixedUpdate()中调用返回true,否则返回false
Time.maximumDeltaTime 最大增量时间
Time.maximumParticleDeltaTime 粒子更新的最大增量时间
Time.captureDeltaTime 捕获增量时间
Time.captureFramerate Time.captureDeltaTime的倒数

2.何为Time.deltaTime

我们在学习Unity过程中,最先接触到的参数应该就是这个Time.deltaTime了,在Update中,我们的移动、旋转一般都要乘以一个Time.deltaTime,用以保证我们的速度是平均的、可控的。

因为Update是每帧调用一次,写在这个函数中的功能代码自然也是每帧调用一次,如果写死了,比如【transform.Translate(transform.forward)】,那么结果就是一秒执行了N次这句代码,移动速度就不可控了,这是就需要乘以一个Time.deltaTime。

unscaleddeltatime,详解Unity,unity,游戏引擎

Time.deltaTime简单来说,就是指 “前后两帧的间隔时间” ,So我们假设1秒钟内Update被调用了5次,那么帧间隔时间就是 1/5=0.2。

    //如图所示,假设Update每秒执行5次,那么这段代码则表示一秒移动了5米,很显然这不是我们想要的
    void Update(){
        transform.Translate(transform.forward); 
    }

    //如图所示,假设Update每秒执行5次,而Time.deltaTime的值是0.2
    //那么每次Update移动的距离就是0.2,一共执行了五次,五次移动距离一起刚好1米
    void Update(){
        transform.Translate(transform.forward * Time.deltaTime); 
    }

Update的执行次数是不固定的,用户电脑越强,它的1秒内执行次数越高,但是只要我们乘以了Time.deltaTime,就能保证它的移动速度是平均的。因为Time.deltaTime也是根据当前帧率计算出来的。

3.何为timeScale | 时间加速与减速

Time.timeScale属性用于控制游戏世界的时间流速,默认为1,正常状态,如果设置为2,则是两倍速,以此类推。必须大于等于0且小于100。

unscaleddeltatime,详解Unity,unity,游戏引擎

Time.timeScale之所以能控制两个立方体的旋转速度,是因为两个立方体的旋转代码中用到了Time.deltaTime,如果我们将旋转角度写死,那么Time.timeScale任它有天大能耐也无法控制的。

//正方体的自转代码
public class 自转 : MonoBehaviour
{
    public float speed;
    private void Update()
    {
        transform.Rotate(new Vector3(0, speed * Time.deltaTime, 0));
    }
}

这就意味着,timeScale并不是万能的,如果我们向让它去控制游戏世界中的一切,那么我们必须要按照Unity定下的规则办事,也就是在需要自己实现的运动功能代码部分乘以一个Time.deltaTime。

那么这里又引出一个问题,如果我不想被timeScale控制,但是我又要保证我的物体运动是平均可控的,怎么办?

那就引入一个新的属性 — Time.unscaledDeltaTime

该属性和Time.deltaTime没什么区别,但是当timeScale变更时,Time.unscaledDeltaTime是不受影响的。

4.获取时间

对于获取时间这块,Unity为我们提供了很多选择,我直接把上面的表格复制下来了,我们可以看到,对于获取时间足足有6个选择。

变量 释义
总时间
Time.time 从游戏开始到现在所用的时间
Time.unscaledTime 从游戏开始到现在所用的时间(不受timeScale影响)
Time.fixedTime 从游戏开始到现在所用的时间,固定更新
Time.fixedUnscaledTime 从游戏开始到现在所用的时间,固定更新(不受timeScale影响)
Time.realtimeSinceStartup 游戏开始以来的实际时间
Time.timeSinceLevelLoad 自最后一个非添加场景(non-additive scene)完成加载以来的时间

最重要的就是Time.time啦,该属性会返回从游戏开始到现在所用的时间,以秒为单位,如果大家想要计算玩家从本次已经运行游戏多长时间了,就可以使用该属性来计算。

但是请注意! Time.time是受到Time.timeScale的影响的,如果你的游戏用到了Time.timeScale,那么这时就需要将受缩放影响的时间和不受缩放影响的时间区分开了,由此,Unity为我们提供了Time.unscaledTime。

unscaleddeltatime,详解Unity,unity,游戏引擎

这样的话我们可以使用Time.time来计算游戏世界内的时间流逝,如果这个世界被时停了,那么时间也理应被时停,对吧?

对于现实世界而言,我们使用Time.unscaledTime,毕竟该属性不受Time.timeScale影响。

除此之外,还有下面四个属性

unscaleddeltatime,详解Unity,unity,游戏引擎

其中Time.fixedUnscaledTime、Time.realtimeSinceStartup是和Time.unscaledTime一样,不受Time.Scae影响
而Time.fixedTime、Time.timeSinceLevelLoad是受到Time.Scale影响的。

那么它们的不同之处在什么地方呢?

受Scale影响

  • Time.time 由Time.deltaTime累加更新
  • Time.fixedTime 由Time.fixedDeltaTime累加更新
  • Time.timeSinceLevelLoad 自最后一个非添加场景(non-additive scene)完成加载以来的时间
    上述三个是保持同步的

不受Scale影响

  • Time.unscaledTime 由Time.unscaledDeltaTime累加更新
  • Time.fixedUnscaledTime 由Time.fixedUnscaledDeltaTime累加更新
  • Time.realtimeSinceStartup 从系统计时器获取时间更新
    上述三个也是保持同步的
  • 一旦timeScale为0,则fixedUnscaledTime停止更新,但timeScale一旦恢复为1,则fixedUnscaledTime与unscaledTime同步。
  • 一旦通过编辑器暂停游戏,timeScale、fixedUnscaledTime都会停止更新,但realtimeSinceStartup会继续更新,直到编辑器停止暂停,则三个参数同步。

5.Time.captureDeltaTime

该参数主要用于减慢游戏的帧率,保证Unity在帧与帧之间完成截图,更多的使用情况是完成一系列的截图,组成视频,从而达成录像的目的。

默认该值为0,如果不启用该值就直接开始截图,可能会出现卡顿的情况,也就是最终合成的视频可能无法保持恒定的帧速率,所以想要录制流畅的视频,务必使用它!

下面这张动态图展示了录制一组图片的整个过程,但是表现不是很明显,可以结合下面给出的源码看,这就是一个案例应用
unscaleddeltatime,详解Unity,unity,游戏引擎

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class 截图 : MonoBehaviour
{
    //存放截图文件夹的名字
    public string folder = "Test截图";
    //截图需保持的帧率
    public int frameRate = 25;
    public Button startBtn;
    public Button stopBtn;
    public bool key = false;

    public void Update
    {
        if(key)
        {
            Shot();
        }
    }

    //点击开始按钮
    public void StartSS()
    {
        // 设置播放帧率
        Time.captureDeltaTime = 1.0f / frameRate;
        //创建文件夹
        System.IO.Directory.CreateDirectory(folder);
        key = true;
    }

    //点击结束按钮
    public void StopSS()
    {
        key = false;
        //结束录制后,记得将该值置零
        Time.captureDeltaTime = 0;
    }

    //录制函数
    public void Shot()
    {
        // 添加文件名到文件夹名称(格式为“0005.png”)
        //Test截图/0001.png
        string name = string.Format("{0}/{1:D04}.png", folder, Time.frameCount);

        // 捕获截图 PNG文件保存至XX路径
        ScreenCapture.CaptureScreenshot(name);
    }
}

6.关于timeAsDouble

上述列表中还有六个参数的双精度版本的参数我没有写入,因为这是2021LTS版新增的内容,因为比较简单,所以不作赘述。
详情参阅:https://docs.unity3d.com/cn/current/Manual/WhatsNew2021LTS.html

Time.timeAsDouble引入了各种属性,使您可以在项目中使用双精度时间。这对于构建长时间运行的应用程序(如专用游戏服务器)的创作者特别有用。


二、Time与生命周期函数的循环

有关生命周期函数的调用顺序我之前出过一篇文章,详情请移步(https://blog.csdn.net/weixin_43147385/article/details/123928964?spm=1001.2014.3001.5502)
接下来主要是讲TimeScale对生命周期函数的影响。

下图为生命周期函数调用关系图,供参考
unscaleddeltatime,详解Unity,unity,游戏引擎

我们首先把循环流程图搬出来,供后续讲解参考(该图从Unity文档找的,我重新画了一下)
unscaleddeltatime,详解Unity,unity,游戏引擎

1.Time.time和Time.UnscaledTime的时间为何不相同?

在timeScale总为1的情况下,按理说,time和UnscaledTime应该是相同的,除非timeScale不为1,它们才会就此不同。但实际上从系统运行一开始,这俩参数就不一致了。
unscaleddeltatime,详解Unity,unity,游戏引擎

若想深究起原因,就不得不谈谈这两个参数都是依靠谁来进行更新的,如何进行更新的。

上面已经提过这个问题,time依靠deltaTime更新,UnscaledTime则依靠UnscaledDeltaTime更新。

它们对总时长累加一次,Update就更新一次,但是这个累加是有限制的,这个限制就是maximumDeltaTime,该参数默认为0.33。

但该参数的限制仅对deltaTime生效,仔细看上面给出的循环流程图,进行到第二步时就会判断deltaTime是否大于maximumDeltaTime,若大于,则直接返回maximumDeltaTime,若小于就进行下一步。

所以差异就在这个地方,当我在启动Unity时,它会卡顿两秒才成功启动,这两秒钟内是Unity内部在调用资源,但当我按下按钮一瞬间后,实际上time就已经开始计时了,只不过屏幕还没有刷新出来,而Unity在卡顿的时候,帧与帧之间的间隔时间会很大,导致deltaTime的值变得很大,但是maximumDeltaTime的存在就是为了防止这种事情发生,所以time被限制住了,而UnscaledTime则没有被限制住,所以实际上UnscaledTime才是真正的Unity从运行开始到现在的时间。

unscaleddeltatime,详解Unity,unity,游戏引擎

2.timeScale为0时会影响哪个周期函数?

这里我们做一个小案例即可明了
unscaleddeltatime,详解Unity,unity,游戏引擎

从上图中我们可以很清晰的看出,当timeScale为0时,FixedUpdate停止了刷新,而Update和LateUpdate则没有停。其原因我们可以在循环流程图中得到解答。

unscaleddeltatime,详解Unity,unity,游戏引擎

每当deltaTime被添加到Time.time中时就会检查一次,fixedTime和time是否差距过大,如果不大就持续更新Update,如果差距大于fixedDeltaTime则累加一次fixedTime,然后更新一次FixedUpdate。

So,当timeScale为0时,deltaTime受此影响变为0,循环依旧运行,但time也一直在累加,但是一直都是加0,所以time与fixedTime的差距始终小于fixedDeltaTime,所以始终更新Update,而无法满足更新FixedUpdate的条件。

3.物理更新为什么要放到FixedUpdate中呢?

我们经常听别人说,物理相关的一定要放到FixedUpdate中,但是为什么这么写呢?

通过上一段我们已经了解,timeScale会影响FixedUpdate,其实答案已经很明了了。

我们假设有一架不停发射的机枪,架在主角必经之路,这时如果主角打开了设置界面,世界是不是需要暂停?需要等待主角关掉设置界面。那么这个时候机枪怎么办?

我们假设机枪代码如下:

public class 机枪 : MonoBehaviour
{
    public GameObject bullet;
    public float force_ = 40;
    private void Update()
    {
        GameObject g;
        g = GameObject.Instantiate(bullet);
        g.AddComponent<Rigidbody>();
        g.GetComponent<Rigidbody>().AddForce(transform.forward * force_);
    }
}

这里使用了Update,那么时停过程中,Update是不会暂停的,So,机枪会不断生成子弹,但子弹并不会发射,因为代码给子弹添加了力,这里是由物理系统控制的。所以这里我们换成FixedUpdate,一旦时停,代码也会停止运行。



三、总结和参考资料

1.总结

最后总结,来一张全参数的变化图,还挺好玩的,你们可以自己去做一下.
unscaleddeltatime,详解Unity,unity,游戏引擎

挑重要的说
关于time的总结

  • time和fixedTime和timeSinceLevelLoad总是同步
  • unscaledTime和fixedUnscaledTime和realtimeSinceStartupas总是同步

关于deltaTime的总结

  • deltaTime受到timeScale影响
  • deltaTime最大值受到maximumDeltaTime影响
  • unscaledDeltaTime不受timeScale影响
  • fixedDeltaTIme不受timeScale影响
  • fixedUnscaledDeltaTime受到timeScale影响,会按照反比改变
  • smoothDeltaTime总是会在deltaTime和unscaledDeltaTime计算出一个平衡值

关于对周期函数影响的总结

  • FixedUpdate会受到timeScale影响,为0时会停止运行,为2时为2倍速运行
  • Update不会受到timeScale影响

2.参考资料

[1].Unity官方.Unity官方文档-Time类
[2].Unity官方.Unity官方文档-Time类API
[3].SerenaHaven.Unity——Time.timeScale详解
[4].Unity官方.New in Unity 2021 LTS
[5].天生爱赞美.Unity关于Time.timeScale详解文章来源地址https://www.toymoban.com/news/detail-715410.html

到了这里,关于详解Unity中Time类的用法与深入探究的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入浅出 Spring:核心概念和基本用法详解

    个人主页:17_Kevin-CSDN博客 收录专栏;《Java》 在 Java 企业级应用开发中,Spring 框架已经成为了事实上的标准。它提供了一种轻量级的解决方案,使得开发者能够更轻松地构建灵活、可扩展的应用程序。在本文中,我们将探讨 Spring 框架的一些核心概念和基本用法,以此更好地

    2024年03月20日
    浏览(55)
  • 【C++深入浅出】STL之string用法详解

    目录 一. 前言 二. STL概要 2.1 什么是STL 2.2 STL的六大组件 2.3 STL的缺陷 三. string类概述 3.1 什么是string类 3.2 为什么要使用string类 四. string类的使用 4.1 包含头文件 4.2 构造函数 4.3 赋值运算符重载 4.4 容量操作 4.5 访问/遍历操作 4.6 查找修改操作 4.7 子串操作 ​4.8 非成员函数  

    2024年02月05日
    浏览(48)
  • Echarts x轴为time的用法

    \\\'time\\\' x轴的格式: x轴设置type为time(不需要转换X轴显示的文字) 正常情况下还应该定义一个x轴的起始范围,数据格式如: 然后series中的 data也应该设置为二维数组类型如 : 具体实现代码: 动态获取: 显而易见的我们需要: (1)max,min的时间 (2)时间和数据的二维数组。

    2024年02月05日
    浏览(76)
  • srand(time(0))函数的用法介绍

    我们知道在C语言中, rand()函数 可以用来产生随机数,但是这不是真真意义上的随机数,是一个 伪随机数 ,是根据一个数,我们可以称它为 种子 ,为基准以某个递推公式推算出来的一系数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正

    2024年02月06日
    浏览(35)
  • String 类的基本用法及String 类的常见操作

    作者:月亮嚼成星~ 博客主页:月亮嚼成星~的博客主页 专栏:Java SE基础 工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器——牛客网 点击免费注册和我一起刷题吧 总结: 构造字符串的三种方式: 1)使用常量串 2)直接使用new String对象 3)利用字符数组 St

    2024年02月02日
    浏览(40)
  • 深入探究for...range语句

    在Go语言中,我们经常需要对数据集合进行遍历操作。对于数组来说,使用for语句可以很方便地完成遍历。然而,当我们面对其他数据类型,如map、string 和 channel 时,使用普通的for循环无法直接完成遍历。为了更加便捷地遍历这些数据类型,Go语言引入了for...range语句。本文将

    2024年02月08日
    浏览(46)
  • 探究WPF中文字模糊的问题:TextOptions的用法

    有网友问WPF中一些文字模糊是什么问题。之前我也没有认真思考过这个问题,只是大概知道和WPF的像素对齐(pixel snapping)、抗锯齿(anti-aliasing)有关,通过设置附加属性 TextOptions.TextFormattingMode 或者 TextOptions.TextRenderingMode 来解决。这次我也查了下资料,了解了这几个附加属

    2024年03月12日
    浏览(45)
  • 深入浅出:探究过完备字典矩阵

    在数学和信号处理的世界里,我们总是在寻找表达数据的最佳方式。在这篇博文中,我们将探讨一种特殊的矩阵——过完备字典矩阵,这是线性代数和信号处理中一个非常有趣且实用的概念。 首先,我们先来理解一下字典矩阵的概念。在数学上,字典矩阵基本上就是一组向量

    2024年03月17日
    浏览(34)
  • Flink的KeyedProcessFunction基于Event Time和Process Time的定时器用法实例分析

    在Flink底层,我们可以不定义任何具体的算子(比如 map,filter,或者 window),而只是提炼出一个统一的【处理】(process)操作——它是所有转换算子的一个概括性的表达,可以自定义处理逻辑,所以这一层接口就被叫作【处理函数】(process function)。在处理函数中,我们直

    2024年01月19日
    浏览(40)
  • 深入探究Selenium定位技巧及最佳实践

    在使用Selenium进行Web自动化测试时,准确地定位元素是非常重要的一步。Selenium提供了多种元素定位方法,本文将深入探究这八大元素定位方法,帮助读者更好地理解和应用Selenium的定位技巧。 1. ID定位 ID是元素在HTML中的唯一标识符,因此使用ID进行定位是最直接、最快速的方

    2024年01月21日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包