Coroutine的分段时间累计误差

Unity中可以用Coroutine进行分段延时处理。比如在游戏中经常用到的进度条




我最近就做了一个这样的进度条,利用Coroutine函数隔一段时间更新进度条的进度,这样实现进度条的功能。就是用进度条来表示获取PowerUp(中文是宝物,法宝?)后该PowerUp持续多长时间。

    private IEnumerator updatePowerUpProgress()
    {
        inGamePowerUpData.startTime = Time.time;
        float progress = getCurrentProgress();
        float progressStep = 0.05f / inGamePowerUpData.duration;
        while (progress < 1) {
            progress += progressStep;
            setCurrentProgress(progress);
            yield return inGamePowerUpProgressWaitForSeconds;//这个inGamePowerUpProgressWaitForSeconds在外面已经定义为 new WaitForSeconds(0.05f);
        }
        //deactivate the powerup
    }


这里要注意两点。一方面我们不能在外面利用inGamePowerUpData.duration表示的时间来对该PowerUp进行消除(deactivate),因为这个duration的时间虽然是我们指定的,但是在updatePowerUpProgress()这个函数分段执行完成后,时间肯定是要大于这个duration的。因为一来updatePowerUpProgress本身的执行是需要时间的,另外系统延时调用做不到那么精确,往往会因为CPU任务切换过渡导致延时更长。所以我们不应该期望在duration时间过后把PowerUp消除掉,而应该在updatePowerUpProgress内部,等所有的调用结束,也即while循环以后再消除PowerUp.

另一方面,假设我们要处理暂停操作。就是说当用户玩游戏,获取了powerup,进度条出现,然后用户暂停。这时候我们要重新计算Duration,以便下次用户开始游戏后进度条能正常运行。一般是可以这样做的:

void calcuateNewDuration() { duration -= Time.time - startTime; }

这样下次用户暂停时,程序停止执行updatePowerUpProgress,并重新计算duration,等用户再开始游戏时,程序重新调用updatePowerUpProgress就可以了。

但是注意到涉及到进度条,考虑分段延时后这样做就有可能出现很诡异的现象。就是当进度条临近结束的时候用户暂停,然后等用户开始游戏后会发现,原本快结束的进度条尽然沿反方向递增!看起来很诡异。

其实这也是因为分段计时的累计误差导致的。因为进度条临近结束时,实际执行时间是略大于duration的:

Time.time - startTime > duration
这时候用户暂停,然后调用calcuateNewDuration重新计算duration必然会导致duration为负值。这样下次用户开始后程序调用到updatePowerUpProgress的代码,就会使得progress的进度相反了!!

所以,我们应该改写一下calculateNewDuration这个方法:

	public void calculateNewDuration_PowerUp(float reverseProgress)
	{
		_duration = reverseProgress * _originalDuration;
	}

这里_originalDuration指的是一开始付给这个进度条的duration。传入的参数reverseProgress = 1 - 用户暂停时的progress。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值