OneV's Den

上善若水,人淡如菊

嗨,我是王巍 (@onevcat),一名来自中国的 iOS / Unity 开发者。现居日本,就职于 LINE。正在修行,探求创意之源。


ObjC 中国与 objc.io 合作最新作品《函数式 Swift》,《Core Data》及《Swift 进阶》已经发布泊学网正在开展订阅赠书活动,也欢迎前往了解

Unity3D中暂停时的动画及粒子效果实现

暂停是游戏中经常出现的功能,而Unity3D中对于暂停的处理并不是很理想。一般的做法是将Time.timeScale设置为0。Unity的文档中对于这种情况有以下描述;

The scale at which the time is passing. This can be used for slow motion effects….When timeScale is set to zero the game is basically paused …

timeScale表示游戏中时间流逝快慢的尺度。文档中明确表示,这个参数是用来做慢动作效果的。对于将timeScale设置为0的情况,仅只有一个补充说明。在实际使用中,通过设置timeScale来实现慢动作特效,是一种相当简洁且不带任何毒副作用的方法,但是当将timeScale设置为0来实现暂停时,由于时间不再流逝,所有和时间有关的功能痘将停止,有些时候这正是我们想要的,因为毕竟是暂停。但是副作用也随之而来,在暂停时各种动画和粒子效果都将无法播放(因为是时间相关的),FixedUpdate也将不再被调用。

换句话说,最大的影响是,在timeScale=0的暂停情况下,你将无法实现暂停菜单的动画以及各种漂亮的点击效果。

但是并非真的没办法,关于timeScale的文档下就有提示:

Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.

因为 realtimeSinceStartuptimeScale 无关,因此也就成了解决在暂停下的动画和粒子效果的救命稻草。对于Unity动画,在每一帧,根据实际时间寻找相应帧并采样显示的方法来模拟动画:

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();
    //…repeat or over by wrap mode 
}

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

_deltaTime = Time.realtimeSinceStartup - _timeAtLastFrame;
_timeAtLastFrame = Time.realtimeSinceStartup;
if (Time.timeScale == 0 ){
    _emitter.Simulate(_deltaTime);
    _emitter.emit = true;
}

核心的代码基本都在上面了,可以根据这个思路完成实现。完整的代码和示例工程我放到了github上,有需要的朋友可以去查看,也欢迎大家指正。

最近的文章

Xcode 4 插件制作入门

本文欢迎转载,但烦请保留此行出处信息:http://www.onevcat.com/2013/02/xcode-plugin/2014.5.4更新对于 Xcode 5,本文有些地方显得过时了。Xcode 5 现在已经全面转向了 ARC,因此在插件初始化设置方面其实有所改变。另外由于一大批优秀插件的带动(可以参看文章底部链接),很多大神们逐渐加入了插件开发的行列,因此,一个简单的 Template 就显得很必要了。在 Github 上的这个 repo 里,包含了一个 Xcode 5 的插件的...…

能工巧匠集继续阅读
更早的文章

Unity编译至Xcode工程后自动添加文件和库的方法

废话之前XUPorter项目Github链接为什么想要自动添加由于Unity是全平台的游戏开发环境,在开发中针对特定平台的特定功能时,很难避免根据对象平台的不同而引入不同的依赖。包括源码,需要的库和框架等。在使用各种插件后这种情况愈发严重:比如想加入内购功能,StroreKit.framework必不可少,而且也需要相应的处理代码。按照一般的Unity插件开发流程,在完成.cs的接口声明和Unity侧的调用实现后,最重要的当然是在iOS native侧完成实现。而在以前,包括依赖库和所有源...…

能工巧匠集继续阅读