timeScale减速对动画影响的处理方法(转)

《刀塔传奇》相信做游戏开发的都知道,如果不知道说明你是一个闭关修炼的千年老妖怪了  哈哈哈
在此开个小小玩笑,现在步入正题
在《刀塔传奇》中,某个角色在释放技能的时候,其他所有角色以及怪物的动画,特效全部都会停止下来。当角色的技能全部放完,整个画面才恢复正常。
为了实现以上功能我通过网上收集以及自己摸索整理出了一套解决方案,现在分享出来相信对大家有用。
首先,来了解下timeScale(暂停),
暂停是游戏中经常出现的功能,
unity3D中对于暂停的处理并不是很理想。一般的做法是将Time.timeScale设置为0。

timeScale表示游戏中时间流逝快慢的尺度。这个参数是用来做慢动作效果的。
对于将timeScale设置为0的情况,仅只有一个补充说明。
在实际使用中,通过设置timeScale来实现慢动作特效,是一种相当简洁且不带任何副作用的方法.
但是当将timeScale设置为0来实现暂停时,由于时间不再流逝,所有和时间有关的功能都将停止,有些时候这正是我们想要的,因为毕竟是暂停。
但是副作用也随之而来,在暂停时各种动画和粒子效果都将无法播放(因为是时间相关的),FixedUpdate也将不再被调用。
那么我又如何通过timeScale来实现上面的效果呢?
刚好realtimeSinceStartup 与 timeScale 就无关,也就是说realtimeSinceStartup 不受timeScale 的影响。
因此realtimeSinceStartup 也就成了解决在暂停下的动画和粒子效果的救命稻草。对于Unity动画,
在每一帧,根据实际时间寻找相应帧并采样显示的方法来模拟动画,
下面来看一段代码

[C#] 纯文本查看 复制代码

public static IEnumerator Play( this Animation animation, string clipName, bool ignoreTimeScale, Action onComplete )
{
//We don‘t want to use timeScale, so we have to animate by frame..
if(ignoreTimeScale)
{
AnimationState _currState = animation[clipName];
bool isPlaying = true;

float _progressTime = 0F;
float _timeAtLastFrame = 0F;
float _timeAtCurrentFrame = 0F;
bool _inReversePlaying = false;

float _deltaTime = 0F;
animation.Play(clipName);
_timeAtLastFrame = Time.realtimeSinceStartup;

while (isPlaying) {
_timeAtCurrentFrame = Time.realtimeSinceStartup;
_deltaTime = _timeAtCurrentFrame - _timeAtLastFrame;
_timeAtLastFrame = _timeAtCurrentFrame; 

_progressTime += _deltaTime;

_currState.normalizedTime = _inReversePlaying ? 1.0f - (_progressTime / _currState.length)
: _progressTime / _currState.length;
animation.Sample();

if (_progressTime >= _currState.length) {
switch (_currState.wrapMode) {
case WrapMode.Loop:
//Loop anim, continue.
_progressTime = 0.0f;
break;
case WrapMode.PingPong:
//PingPong anim, reversing continue.
_progressTime = 0.0f;
_inReversePlaying = !_inReversePlaying;
break;
case WrapMode.ClampForever:
//ClampForever anim, keep the last frame.
break;
case WrapMode.Default:
//We don‘t know how to handle it.
//In most time, this means it‘s a Once anim.
//Animation should be played with wrap mode specified.
Debug.LogWarning("A Default Anim Finished. Animation should be played with wrap mode specified.");
isPlaying = false;
break;
default:
//Once anim, kill it.
isPlaying = false;
break;
}
}
yield return new WaitForEndOfFrame();
}
yield return null;

if(onComplete != null) {
onComplete();
}
} else {
if (onComplete != null) {
Debug.LogWarning("onComplete will not be called when you set \"ignoreTimeScale\" to true. Use Unity‘s animation handler instead!)");
animation.Play(clipName);
}
}
}

注:上面这段代码只对Animation有效,那针对Animator我们又如何在timeScale =0的情况下正常播放动画呢?

[C#] 纯文本查看 复制代码

 public void animatorPlay(Animator _animator)
{
_animator.updateMode = AnimatorUpdateMode.UnscaledTime;
//你要做的事情
}

其实我们也可以在面板中直接这样设置

通过上面简单的代码与面板中简单设置,就可以使Animator也具有不受timeScale的影响了这样是不是非常简单呢?

对于粒子效果,同样进行计时,
并通过粒子系统的Simulate方法来模拟对应时间的粒子状态来完成效果,
比如对于Legacy粒子,使Emitter在timeScale=0暂停时继续有效发射并显示效果:

[C#] 纯文本查看 复制代码

public class UnpauseParticleSystem : MonoBehaviour
{
        private float _timeAtLastFrame;
        private ParticleSystem _particleSystem;
        private float _deltaTime;
        
        public void Awake() {
                _timeAtLastFrame = Time.realtimeSinceStartup;
                _particleSystem = gameObject.GetComponent<ParticleSystem>();
        }

        public void Update() {
                _deltaTime = Time.realtimeSinceStartup - _timeAtLastFrame;
                _timeAtLastFrame = Time.realtimeSinceStartup;
                if (Time.timeScale == 0 ) {
                        _particleSystem.Simulate(_deltaTime,false,false);
                        _particleSystem.Play();
                }
        }

}

运行效果如下

开始时 timeScale =1, 2个coube 和人物以及特效 都能顺畅播放。
 
当我点击暂停按钮 时 timeScale =0,全部暂停了

我给cube2加上 针对粒子的一个代码

大家就会发现 在timeScale =0的情况下,我的特效可以顺利正常播放,不受timeScale 的暂停效果,其他都还是暂停的。

我给了一个空对象,绑定了一个代码,来控制cube2的Animation也同样不受影响,结果如下

(gif图点击查看)现在,在timeScale =0的情况下,我的Animation动画与特效都能正常播放了,不受timeScale 的暂停效果,其他都还是暂停的。

给我的人物特效同样加上一个 针对粒子的一个代码,以及上面设置我人物Animator动画的方法

同样我人物的Animator与特效都能正常播放了,不受timeScale 的暂停效果,其他都还是暂停的。

时间: 2024-10-08 06:18:30

timeScale减速对动画影响的处理方法(转)的相关文章

UIImageView帧动画相关属性和方法-15-05-04

UIImageView帧动画相关属性和方法 •@property(nonatomic,copy) NSArray *animationImages; Ø需要播放的序列帧图片数组(里面都是UIImage对象,会按顺序显示里面的图片) Ø •@property(nonatomic) NSTimeInterval animationDuration; Ø帧动画的持续时间 • •@property(nonatomic) NSInteger animationRepeatCount; Ø帧动画的执行次数(

delphi 2010是动画GIF的支持方法

下面delphi 2010是动画GIF的支持方法:  1.在窗体上放一个Image1控件.注意:这时设置其Picture属性,加载一幅动画GIF是不会动画显示的.  2.在窗体的FormCreate事件或其他事件(如按钮的点击事件)中写如下代码:  Image1.AutoSize := True; Form1.Autosize := True; Image1.Picture.LoadFromFile('C:\Gif89a.gif'); TGIFImage(Image1.Picture.Graph

坑爹小问题-table改变frame动画影响cell

反正就是很坑爹.简单说就是这样吧,做一个简单的聊天界面,对话框左一个右一个那样子.(界面可以脑补微信)底下的键盘弹起来时候,展示对话的table的frame要相应的缩小,隐藏键盘又要恢复.就这么简单一个代码: 1 - (void)keyboardFrameChange:(NSNotification *)sender 2 { 3 NSDictionary *userInfo = sender.userInfo; 4 CGRect keyboardFrame; 5 [[userInfo value

Swift - 动画效果的实现方法总结(附样例)

在iOS中,实现动画有两种方法.一个是统一的animateWithDuration,另一个是组合出现的beginAnimations和commitAnimations.这三个方法都是类方法. 一,使用animateWithDuration来实现动画 (1)此方法共有5个参数: duration:动画从开始到结束的持续时间,单位是秒 delay:动画开始前等待的时间 options:动画执行的选项.里面可以设置动画的效果.可以使用UIViewAnimationOptions类提供的各种预置效果 a

JQuery动画animate的stop方法使用详解

JQuery动画animate的stop方法使用详解 animate语法: 复制代码 代码如下: $(selector).animate(styles,speed,easing,callback) 复制代码 代码如下: <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Testing</title> <link rel="styl

WPF编程,通过Path类型制作沿路径运动的动画另一种方法。

原文:WPF编程,通过Path类型制作沿路径运动的动画另一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/details/87358989 上一篇文章给了一个这方面的例子,那个文章里是通过后台按钮事件进行动画的开始.停止.继续等. 这里给出的是通过前台XAML来实现. 1.前台 定义路径.定义运动的主体,这里是一圆. <Path Stroke="Black" StrokeThickness

IOS开发-UIView之动画效果的实现方法(合集)

http://www.cnblogs.com/GarveyCalvin/p/4193963.html 前言:在开发APP中,我们会经常使用到动画效果.使用动画可以让我们的APP更酷更炫,最重要的是优化用户体验,但取决于动画的质量.像QQ.微信.新浪微博等APP,动画效果就很好了,至少我很喜欢它们的动画,让我使用起来感觉很顺畅,心情很开朗.本文会介绍UIView效果的实现方法,非核心动画. 一.使用UIView类实现动画 基本写法,代码必须放在Begin和Commit之间: [UIView beg

cocos2dx中创建动画的三种方法

1.最最原始的方法,先创建动画帧,再创建动画打包(animation),再创建动画(animate) 第一步: 创建动画帧:CCSpriteFrame,依赖于原始的资源图片(xx.png,xx.jpg) CCSpriteFrame *frame1=CCSpriteFrame::create("1.png"); CCSpriteFrame *frame2=CCSpriteFrame::create("2.png"); CCSpriteFrame *frame3=CCS

多个动画暂停问题 (stop()方法的使用)

今天模仿某网站的导航栏效果 最终结果 做这个效果遇到的点: 1.给每个a绑定事件太麻烦,用了事件委托,由于刚看jq所以查到了 $('.list').delegate('a','mouseover',function(event){} 方法 2.给这个小滑块设定抖动效果,更动感一些 用了两个animate算上最终定位用了三个animate .animate({left:ao+diff+'px'},150).animate({left:ao-diff/2+'px'},150).animate({le