首页 > Unity3D频道 > 【Unity3D研究院之游戏开发】 > Unity3D研究院之Time.timeScale、游戏暂停(七十四)
2014
07-16

Unity3D研究院之Time.timeScale、游戏暂停(七十四)

项目里面一直在用Time.timeScale来做游戏的 1倍 2倍整体加速,今天我仔细看了一下Time.timeScale才发现之前我理解错了一些东西。

Time.timeScale可以控制Update 和LateUpdate 的执行速度,举个例子说明一下。

Time.timeScale=1时,Update、LateUpdate、FixedUpdate 都按正常的时间来执行。

Time.timeScale=2时,Update和 LateUpdate的执行速度是之前的2倍,而FixedUpdate还是按正常时间来执行。

Sorry上面红色这部分确实是写错了,感谢网友在留言处给我的指正,谢谢。

正确的应该是timeScale不会影响Update和LateUpdate的执行速度。因为FixedUpdate是根据时间来的,所以timeScale只会影响FixedUpdate的速度。 再次抱歉。。 谢谢热心网友给我的指正。。 因为我的项目里在处理战斗部分的时候 大量使用 iTween 所以  2  3 倍加速 或者暂停 的功能直接修改timeScale 。 

Time.timeScale也误导了我很久,为什么这么说呢?我原先一直以为Time.timeScale = 0 的话所有的Update都不执行了。今天测试了一下发现原来不是这样的,无论Time.timeScale 等于多说Update和LateUpdate都会去执行,不信你可以自己做个实验看看。

Time.timeScale还会影响Time.time的时间,比如Time.timeScale = 2的话,那么Time.time的增长速度也会变成2倍速度。如果你想取到游戏的实际时间,那么使用Time.timeSinceLevelLoad就可以,前提是必须在Awake()方法以后再取,如果在Awake()方法里面取Time.realtimeSinceStartup会取出一个错误的值,在Start方法里面取的话就正常了。

总之一句话Time.timeScale影响的是Unity的游戏时间缩放比例。Unity里面所有跟时间有关系的东西都是根据timeScale来演算的。仔细想想现在的手游就是个 动画 和 粒子技能特效 还有UI位移特效,所以改他们的速度直接用Time.timeScale就可以完成。还有一个重要的东西就是人物移动 或者 技能移动的速度了, 根据时间的公式,时间 = 路程\速度 ,比如角色从起点跑到中间的一个预期时间, 或者一个技能的火球从攻击到打中目标的预期时间。 凡是处理时间的东东全用Time.time 这样就可以完美让Time.timeScale控制你的游戏了。

下面说说两个大家伙比较关心的话题。

1.游戏暂停

设置 Time.timeScale = 0;即可让游戏暂停。 其实我们暂停的主要是 人物动画,还有技能特效,比如一个火球打了一半。UI方面往往我们不希望暂停,比如暂停界面 有一些UI位移动画或者帧动画, 或者最起码要有个“取消暂停的按钮” 吧。 总不能游戏暂停了我点击按钮 按钮的点击动画 或者特效也暂停了吧。

所有的动画都是基于时间来的,因为Time.timeScale = 0了,所以Time.time也就不会在变化了。换句话来说如果游戏暂停以后想在暂停界面上继续播放一些不受Time.timeScale 影响的动画,那么我们就需要用到Time.realtimeSinceStartup

如果你的项目NGUI的版本还算比较新的话,你会发现在UITweener.cs处理UI动画的基类里面已经增加了一个属性叫public bool ignoreTimeScale = true; 它就是控制控制NGUI 的UI动画是否受到ignoreTimeScale影响。如下图所示,你可以看看NGUI在Update里面的实现,它也是根据时间来判断的。忽略timescale的话就用真实时间,不忽略的话就用Time.time 和Time.deltaTime。

Unity3D研究院之Time.timeScale、游戏暂停(七十四) - 雨松MOMO程序研究院 - 1

 

2.如何让游戏中某个游戏对象不受Time.timeScale影响。

动画不受timeScale影响:

http://answers.unity3d.com/questions/217351/animations-ignore-timescale.html

粒子特效不受timescale影响

https://gist.github.com/AlexTiTanium/5676482

经过我的测试发现timeScale = 0 时, 播放放粒子特效,效率上有很大问题非常的卡。

举个例子啊,刀塔传奇大家都玩过吧?某个角色放技能的时候,其他所有人物动作全部暂停,并且打出去的技能也暂停。等着角色的技能全部放完,别人才恢复正常。 我觉得向做这类游戏,最好就不要 利用timeScale了,不然写起来太蛋疼了。 不过刀塔传奇也没有 1 倍 2倍  3倍速 的功能吧,呵呵。

3.timeScale变化时的声音。

当声音播放的同时去修改timescale的数值你会发现声音播放的很奇怪。如下代码所示,你可以封装一个方法,把IgnoreTimeScale作为参数传进去, 如果忽略timescale的话那么速度就应该是1否则就应该是Time.timeScale。

此时如果修改了Time.timeScale的数值的话,那么正在播放中的声音会非常奇怪。所以当每次播放音频的时候我们需要记录一下这个音频的状态,它是否需要忽略timeScale当前的数值。

每当timeScale变化的时候调用一下下面这个方法。就是遍历一下当前保存的所有音频对象,从新设置一下他们的播放频率。

如果你有更好的建议,欢迎在下面给我留言,谢谢。

 

雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!

--

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠如果您愿意花20块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。

Unity3D研究院之Time.timeScale、游戏暂停(七十四)》有 44 条评论

  1. 室友是菜鸡 说:

    请问一下,我写了一个方法,里面就只有gameObject.transform.Translate(Vector3.down * downSpeed * Time.deltaTime);这个移动语句,里面包含time相关,我在update里面判断timeScale,如果状态=1就执行方法,我想点一个按钮之后将状态改为1,结果状态改为1之后,这一句也还是没有执行。我debug.log了一下,发现状态修改和方法体内的bug执行并没有错。

    看了您的文章之后,我将方法体放到fixedupdate里面执行就好了,可是还是想问一下为什么timeScale=1的时候time语句还是不执行呢?

  2. Jether 说:

    我教你们一个方法,非常简单,在Update里最前面写这个
    if(我们自己做的游戏暂停布尔值==false)
    return;

  3. Jether 说:

    直接弄一个布尔型变量,如果是false就不执行,省得研究Time了(最简单的方法最不容易出错)

  4. Foo 说:

    2018.1版本的官方文档:The Update function is likely to be called more often than usual when game time is slowed down but the deltaTime step reported each frame will simply be reduced。 
    游戏时间变慢时。update会更频繁地被调用。而且是挺明显的加快了。

  5. 啊啊啊 说:

    Time.timeScale只是影响TIme这个类的计时而已哦 不会影响任何帧速率上的东西喔 Time只是个计时的工具 它不代表游戏时间的

  6. 崔明明 说:

    有没有遇到过Time.timeScale不起作用的

  7. 崔明明 说:

    有没有遇到过Time.timeScale不起作用的

  8. 李彦峰 说:

    受Time.timeScale影响的东西还挺多的,MonoBehaviour.Invoke, InvokeRepeating, yield WaitForSeconds()等等都有。之前写的TimerManager计时器组件使用FixedUpdate做Tick,现在看来得改思路了。这Time.timeScale为0的话计时器就挂了……

  9. 看了关于Time.timescale的影响。我正在做一个不能使用Time.timescale来控制动画和粒子 加速 减速 的工具。(Time.timescale的变化影响了更个程序)我碰到一个问题 关于 ParticleSystem 和 EllipsoidParticleEmitter。使用ParticleSystem.Simulate 可以完美的控制 粒子的速度。但是在EllipsoidParticleEmitter 中 使用ParticleEmitter.Simulate 就是无效的,在网上查了关于ParticleEmitter.Simulate,都表示这个方法不工作。但我找到一个特例,就是当Time.timescale = 0 的时候, ParticleEmitter.Simulate 才能和 ParticleSystem.Simulate起到一样的作用。1.分享下我关于Simulate的使用经历。2.我还是没能找到关于ParticleEmitter.Simulate起作用的方法(前提是 不使用Time.timescale),分享出来求帮助。

  10. boomyao 说:

    在 animator组件里把 UpdateMode 修改为 unscaled Time ,这样就可以在timescale=0时继续动le

  11. 大哥。您这里贴的主要是动画和特效不受scaletime的影响。但是这个普遍性还是不够啊,我动画虽然慢了,代码还在跑,就可能出现我还没出手,敌人就已经被砍到了的情况。不知道还有没有更好的方法,能够真正做到局部的时间缩放呢?就算不缩放时间吧,做到局部的时间暂停? 其实我自己有个思路,就是做起来太麻烦了,可以实现局部暂停。就是在所有代码的update里,给一个计时器,当我想要暂停的时候,就开启计时器,所有的update里的函数都暂时不跑,等到暂停时间到了,再开始跑。思路上是可以,但是涉及到的东西稍微多一点,感觉操作就会非常繁琐。同时还要兼顾动画和特效,想着就可怕。官方给的Time.scaleTime是真心好用,就是不能对局部使用。要是能有什么解决办法就真的太好了。

  12. 舆涵 说:

    MOMO大神,如果是新动画系统,那怎么实现呢?还是没怎么看懂

  13. 于谦 说:

    LZ,这个static IEnumerator Play( Animation animation, string clipName, bool useTimeScale,System.Action onComplete )要怎么用啊,原帖说要把这个函数放到一个叫AnimationExtensions.cs的里面,我找不到这个CS文件,自己创建一个也不能用。

  14. 逍遥随风翼 说:

    timescale和update这些函数没关系吧??只是大家都喜欢在这些函数里使用deltatiame,它是受tiemscale控制的。不然你可以试试在update里不要使用deltatime,看它会运行不。

  15. 明轩 说:

    我测试过 你说的不对 音频根本不会变调变速 “此时如果修改了Time.timeScale的数值的话,那么正在播放中的声音会非常奇怪。所以当每次播放音频的时候我们需要记录一下这个音频的状态,它是否需要忽略timeScale当前的数值。“

  16. 斗胆大叔 说:

    “timescale不会影响update现实中的执行时间,但是会影响游戏中的执行时间deltatime。scale加倍后,与deltatime相关的位移会加倍,效果就像执行速度加倍一样。”这样理解对不对?

  17. 黄杰 说:

    如果使得所有挂有脚本的GameObject上的脚本enable等于false的时候,当然是在控制得当的情况下,貌似也能实现暂停

  18. 封忆-NO_1 说:

    Time.timeScale=100时,Update和 LateUpdate的执行速度是之前的100倍,而FixedUpdate还是按正常时间来执行。(有个前提是1秒内你的CPU允许你转100帧,这里说的数字是理想数字)这个不对吧,,,我用10来试验的结果是FixedUpdate加速,其他俩不加速的啊。。。

    • 冯乐乐 说:

      我觉得雨松可能是用Time.time或者Time.deltaTime计时测试的,这是错误的。Time.time是会受Time.timeScale影响的,所以肯定会变。应该用Time.realtimeSinceStartup来看真正的时间才对。我的测试结果是:Time.timeScale = 1 Time.timeScale = 10Update:Time: 0,02 Time: 0.2Deltatime: 0.02 Deltatime: 2Realtime: 0.02 Realtime: 0.02FixedUpdate:Time: 0,02 Time: 0.02Deltatime: 0.02 Deltatime: 0.02Realtime: 0.02 Realtime: 0.002我测试的结果也是不受影响的。这个结果比较符合常理,Update是和游戏还有设备性能相关的,应该不会受timeScale才对,否则用timeScale暂停游戏了不就不会刷新渲染屏幕了吗?

  19. 还是觉得对时间 动画播放重新封装一下舒服,使用Time.timeScale = 0 真的很别扭

  20. 冯乐乐 说:

    我之前总结的是这样的:设置Time.timeScale为0将回暂停所有和帧率无关的事情。这些主要是指所有的物理事件和依赖时间的函数、刚体力和速度等,而且FixedUpdate会被暂停(不是Update)。但是,Update函数本身的执行是不会受Time.timeScale的影响的。Update是依赖你的机器的,它的调用次数和你的机器渲染一样快慢(一些特殊情况除外);性能高的机器,帧率高,Update函数执行次数也就多。因此,当使用Time.timeScale = 0时,游戏看起来是被冻结了,这是因为所有和时间有关的事情都被暂停了。但是,我们的游戏仍在渲染,也就是说Update函数仍在执行。还有一点,Time.timeScale为0时,Time.deltaTime将为0。这意味着,如果你使用Time.deltaTime来控制旋转和位移等,那么Time.timeScale = 0也将使这些物体停止运动。以前看到一种实现暂停的方法是放弃Time.deltaTime,自己实现两个函数:OnPauseGame 和 OnResumeGame。这种方法扩展性强,缺点是写起来可能比较繁琐

  21. 天真汉 说:

    不管用不用得着 帖子挺用心的 顶一个~

  22. 支持momo,一直关注ing。。。

  23. 简单 说:

    写的很好!期待出越来越多的好文章! Unity3D研究院之Time.timeScale、游戏暂停(七十四) - 雨松MOMO程序研究院 - 1

  24. YiNing一 说:

    感谢雨凇,写的很详细! Unity3D研究院之Time.timeScale、游戏暂停(七十四) - 雨松MOMO程序研究院 - 1

留下一个回复

你的email不会被公开。