当前位置:   article > 正文

Unity下利用 timeScale和 unscaledDeltaTime实现部分静帧

unscaleddeltatime

话题铺垫

看图说话

这里写图片描述

这里写图片描述
想必用Unity开发的朋友们都知道一个知识点,Time.timeScale 用于控制整个游戏运行时的时间缩放,使用它可以调整时间的流动速度,设置为0时间静默,设置为1时间按照我们真实世界的时间速度流逝。
问题往往没有这么简单,我们在实际的开发过程中会遇到各种需求。最容易想到的一个需求就是战斗中的譬如大招技能的静默问题,描述起来就是,对于特定目标时间正常流动,而对于其他物体时间静止。难点就在于Time.scale 是一个全局的状态变量,它对游戏世界里面的所有物体的时间都有效,设置 Time.timeScale 为0,所有的物体的动画和粒子特效都将不会按照时间轴进行播放了。

需求情景

要想解决这个问题,我们直观的思路就是找到另外一个让时间轴“复苏”的属性,它可以让动画和粒子按照时间轴正常播放。庆幸的是Unity 给我们提供了这样的设计。

解决方案

废话说了这么多,我们迅速干活。以我方角色大招技能正常播放,其他物体动画特效静止为例,实现方案如下:

案例实操

先简单附上核心代码,后续有时间把Example补上。

模拟Animation组件的时间轴

  • 利用AnimationState.normalizedTime在判断当前动画模拟播放的进度
  • 利用Time.unscaledDeltaTime这个API来计时,因为它不受timeScale的影响
    /// <summary>
    /// 模拟动画时间轴
    /// </summary>
    /// <param name="anim"></param>
    /// <param name="clipName"></param>
    /// <returns></returns>
    private IEnumerator SimulateAnimationTimeline(Animation anim, string clipName)
    {
        //获取到动画状态组件
        AnimationState animState = anim[clipName];
        if (!animState)
        {
            Debug.LogErrorFormat("can't get clip -> {0} from animation -> {1}", clipName, anim.name);
            yield break;
        }
        animState.normalizedTime = 0f;
        float timer = 0f;
        //随着动画时间轴的行进,归一化动画时间会逐步增加
        while (animState.normalizedTime < 1f)
        {
            //动画取样
            anim.Sample();
            //持续未缩放时间片段
            yield return Time.unscaledDeltaTime;
            timer += Time.unscaledDeltaTime;
            animState.normalizedTime += timer/anim.clip.length;
        }
    }
  • 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

模拟Animator组件的时间线

Animator直接提供了对忽略timeScale的支持

    private void SimulateAnimatorTimeline(Animator animator)
    {
        animator.updateMode = IgnoreTimeScale ? AnimatorUpdateMode.UnscaledTime : AnimatorUpdateMode.Normal;
    }
  • 1
  • 2
  • 3
  • 4

模拟粒子系统的时间线

    /// <summary>
    /// 模拟粒子时间轴
    /// </summary>
    /// <param name="particleGo"></param>
    /// <param name="timePeriod"></param>
    private void SimulateParticleTimeline(GameObject particleGo, float timePeriod)
    {
        ParticleSystem[] allPS = particleGo.GetComponentsInChildren<ParticleSystem>();
        for (int i = 0; i < allPS.Length; i++)
        {
            var ps = allPS[i];
            ps.Simulate(timePeriod, false, true, false);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

模拟Dotween这个Tween插件的时间线

比如dotween的缓动函数,是利用了Unity的Time.deltaTime的,所以受到Time.timeScale的影响。如果在静帧的时候,我们需要利用dotween来模拟缓动动画,如摄像机动画,就可以这样来模拟

针对序列Sequence

    private void SimulateDotweenTimeline(Sequence seq)
    {
        seq.SetUpdate(true);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

针对Tweener

    private void SimulateDotweenTimeline(Tweener tweener)
    {
        tweener.SetUpdate(true);
    }
  • 1
  • 2
  • 3
  • 4
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/744685
推荐阅读
相关标签
  

闽ICP备14008679号