项目里面一直在用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。
2.如何让游戏中某个游戏对象不受Time.timeScale影响。
动画不受timeScale影响:
http://answers.unity3d.com/questions/217351/animations-ignore-timescale.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
static IEnumerator Play( Animation animation, string clipName, bool useTimeScale,System.Action onComplete ) { if(!useTimeScale) { AnimationState _currState = animation[clipName]; bool isPlaying = true; float _startTime = 0F; float _progressTime = 0F; float _timeAtLastFrame = 0F; float _timeAtCurrentFrame = 0F; float deltaTime = 0F; animation.Play(clipName); _timeAtLastFrame = Time.realtimeSinceStartup; while (isPlaying) { _timeAtCurrentFrame = Time.realtimeSinceStartup; deltaTime = _timeAtCurrentFrame - _timeAtLastFrame; _timeAtLastFrame = _timeAtCurrentFrame; _progressTime += deltaTime; _currState.normalizedTime = _progressTime / _currState.length; animation.Sample (); if (_progressTime >= _currState.length) { if(_currState.wrapMode != WrapMode.Loop) { isPlaying = false; } else { _progressTime = 0.0f; } } yield return new WaitForEndOfFrame(); } yield return null; if(onComplete != null) { onComplete(); } } else { animation.Play(clipName); } } |
粒子特效不受timescale影响
https://gist.github.com/AlexTiTanium/5676482
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using UnityEngine; using System.Collections; public class ParticaleAnimator : MonoBehaviour { private void Awake() { particle = GetComponent<ParticleSystem>(); } // Use this for initialization void Start () { lastTime = Time.realtimeSinceStartup; } // Update is called once per frame void Update () { float deltaTime = Time.realtimeSinceStartup - (float)lastTime; particle.Simulate(deltaTime, true, false); //last must be false!! lastTime = Time.realtimeSinceStartup; } private double lastTime; private ParticleSystem particle; } |
经过我的测试发现timeScale = 0 时, 播放放粒子特效,效率上有很大问题非常的卡。
举个例子啊,刀塔传奇大家都玩过吧?某个角色放技能的时候,其他所有人物动作全部暂停,并且打出去的技能也暂停。等着角色的技能全部放完,别人才恢复正常。 我觉得向做这类游戏,最好就不要 利用timeScale了,不然写起来太蛋疼了。 不过刀塔传奇也没有 1 倍 2倍 3倍速 的功能吧,呵呵。
3.timeScale变化时的声音。
当声音播放的同时去修改timescale的数值你会发现声音播放的很奇怪。如下代码所示,你可以封装一个方法,把IgnoreTimeScale作为参数传进去, 如果忽略timescale的话那么速度就应该是1否则就应该是Time.timeScale。
1 2 3 4 5 6 7 8 |
//添加一个声音组件 AudioSource source = gameObject.AddComponent<AudioSource>(); //设置播放声音的速度。 默认速度是1 ,那如果我们加速了,那就应该是 Time.timeScale source.pitch =IgnoreTimeScale?1:Time.timeScale; //播放声音 source.Play(); |
此时如果修改了Time.timeScale的数值的话,那么正在播放中的声音会非常奇怪。所以当每次播放音频的时候我们需要记录一下这个音频的状态,它是否需要忽略timeScale当前的数值。
1 2 3 4 5 6 7 8 9 10 |
//创建一个音频的字典 private static Dictionary<AudioSource,bool>soundList = new Dictionary<AudioSource, bool>(); //播放声音 source.Play(); //把音频对象加入字典中,value 就是是否忽略timescale soundList.Add(source,IgnoreTimeScale); |
每当timeScale变化的时候调用一下下面这个方法。就是遍历一下当前保存的所有音频对象,从新设置一下他们的播放频率。
1 2 3 4 5 6 7 8 9 10 11 12 |
public static void TimeScaleChanged() { foreach (AudioSource source in soundList.Keys) { if(source != null) { source.pitch = soundList[source]?1:Time.timeScale; } } } |
如果你有更好的建议,欢迎在下面给我留言,谢谢。
- 本文固定链接: https://www.xuanyusong.com/archives/2956
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
Time.timeScale只是影响TIme这个类的计时而已哦 不会影响任何帧速率上的东西喔 Time只是个计时的工具 它不代表游戏时间的
有没有遇到过Time.timeScale不起作用的
我遇到过timeScale不起作用,不过是在IOS包中,unity里面看是正常的
有没有遇到过Time.timeScale不起作用的
受Time.timeScale影响的东西还挺多的,MonoBehaviour.Invoke, InvokeRepeating, yield WaitForSeconds()等等都有。之前写的TimerManager计时器组件使用FixedUpdate做Tick,现在看来得改思路了。这Time.timeScale为0的话计时器就挂了……
可以用 这个 Time.unscaledTime
看了关于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),分享出来求帮助。
在 animator组件里把 UpdateMode 修改为 unscaled Time ,这样就可以在timescale=0时继续动le
帮大忙了,终于知道自己的功能怎么实现了
是
卧槽,我居然不知道有这个设定
大哥。您这里贴的主要是动画和特效不受scaletime的影响。但是这个普遍性还是不够啊,我动画虽然慢了,代码还在跑,就可能出现我还没出手,敌人就已经被砍到了的情况。不知道还有没有更好的方法,能够真正做到局部的时间缩放呢?就算不缩放时间吧,做到局部的时间暂停? 其实我自己有个思路,就是做起来太麻烦了,可以实现局部暂停。就是在所有代码的update里,给一个计时器,当我想要暂停的时候,就开启计时器,所有的update里的函数都暂时不跑,等到暂停时间到了,再开始跑。思路上是可以,但是涉及到的东西稍微多一点,感觉操作就会非常繁琐。同时还要兼顾动画和特效,想着就可怕。官方给的Time.scaleTime是真心好用,就是不能对局部使用。要是能有什么解决办法就真的太好了。
MOMO大神,如果是新动画系统,那怎么实现呢?还是没怎么看懂
LZ,这个static IEnumerator Play( Animation animation, string clipName, bool useTimeScale,System.Action onComplete )要怎么用啊,原帖说要把这个函数放到一个叫AnimationExtensions.cs的里面,我找不到这个CS文件,自己创建一个也不能用。
timescale和update这些函数没关系吧??只是大家都喜欢在这些函数里使用deltatiame,它是受tiemscale控制的。不然你可以试试在update里不要使用deltatime,看它会运行不。
timescale和update没关系
我测试过 你说的不对 音频根本不会变调变速 “此时如果修改了Time.timeScale的数值的话,那么正在播放中的声音会非常奇怪。所以当每次播放音频的时候我们需要记录一下这个音频的状态,它是否需要忽略timeScale当前的数值。“
“timescale不会影响update现实中的执行时间,但是会影响游戏中的执行时间deltatime。scale加倍后,与deltatime相关的位移会加倍,效果就像执行速度加倍一样。”这样理解对不对?
如果使得所有挂有脚本的GameObject上的脚本enable等于false的时候,当然是在控制得当的情况下,貌似也能实现暂停
enable = false的话 只是 update 不走了。。
得看项目用什么来驱动的。。 因为我的项目 大量使用iTween 所以 加速 或者暂停 就直接修改timeScale了。。
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暂停游戏了不就不会刷新渲染屏幕了吗?
虽然我看不懂你展示的数据,但是后面的汉字我看明白了
,意思跟我的一样吧time.timescale只影响fixedUpdate
呦,发现排版出错了。。。恩,其实是两列数据。对滴~
感谢你给我的指正呀,这里 我确实写错了。。 已经把正确的补充在博客里了。
嗯嗯
还是觉得对时间 动画播放重新封装一下舒服,使用Time.timeScale = 0 真的很别扭
我之前总结的是这样的:设置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。这种方法扩展性强,缺点是写起来可能比较繁琐
不管用不用得着 帖子挺用心的 顶一个~
支持momo,一直关注ing。。。
写的很好!期待出越来越多的好文章!
感谢雨凇,写的很详细!