Unity代码实现序列帧动画播放器
序列帧动画经常用到,最直接的方式就是用Animation录制。但某些情况下这种方式并不是太友好,需要靠代码的方式进行序列帧动画的实现。
代码实现序列帧动画,基本的思路是定义一个序列帧的数组/列表,根据时间的流逝来确定使用哪一帧并更新显示。
NGUI的UI2DSpriteAnimation已经实现了此功能,但是它支持的目标只有Native2D的SpriteRenderer组件或者NGUI自身的UI2DSprite组件,并不支持UGUI的Image组件。
当然可以通过改写源码的方式来添加对Image组件的支持,不过秉着学习的目的,我这里重新写了一个同时支持Image组件和SpriteRenderer组件的序列帧动画播放器。
代码如下,注释写的很详细了,不再赘述。
usingUnityEngine; usingUnityEngine.UI; usingSystem; //////序列帧动画播放器 ///支持UGUI的Image和Unity2D的SpriteRenderer /// publicclassFrameAnimator:MonoBehaviour { //////序列帧 /// publicSprite[]Frames{get{returnframes;}set{frames=value;}} [SerializeField]privateSprite[]frames=null; //////帧率,为正时正向播放,为负时反向播放 /// publicfloatFramerate{get{returnframerate;}set{framerate=value;}} [SerializeField]privatefloatframerate=20.0f; //////是否忽略timeScale /// publicboolIgnoreTimeScale{get{returnignoreTimeScale;}set{ignoreTimeScale=value;}} [SerializeField]privateboolignoreTimeScale=true; //////是否循环 /// publicboolLoop{get{returnloop;}set{loop=value;}} [SerializeField]privateboolloop=true; //动画曲线 [SerializeField]privateAnimationCurvecurve=newAnimationCurve(newKeyframe(0,1,0,0),newKeyframe(1,1,0,0)); //////结束事件 ///在每次播放完一个周期时触发 ///在循环模式下触发此事件时,当前帧不一定为结束帧 /// publiceventActionFinishEvent; //目标Image组件 privateImageimage; //目标SpriteRenderer组件 privateSpriteRendererspriteRenderer; //当前帧索引 privateintcurrentFrameIndex=0; //下一次更新时间 privatefloattimer=0.0f; //当前帧率,通过曲线计算而来 privatefloatcurrentFramerate=20.0f; //////重设动画 /// publicvoidReset() { currentFrameIndex=framerate<0?frames.Length-1:0; } //////从停止的位置播放动画 /// publicvoidPlay() { this.enabled=true; } //////暂停动画 /// publicvoidPause() { this.enabled=false; } //////停止动画,将位置设为初始位置 /// publicvoidStop() { Pause(); Reset(); } //自动开启动画 voidStart() { image=this.GetComponent(); spriteRenderer=this.GetComponent (); #ifUNITY_EDITOR if(image==null&&spriteRenderer==null){ Debug.LogWarning("Noavailablecomponentfound.'Image'or'SpriteRenderer'required.",this.gameObject); } #endif } voidUpdate() { //帧数据无效,禁用脚本 if(frames==null||frames.Length==0){ this.enabled=false; }else{ //从曲线值计算当前帧率 floatcurveValue=curve.Evaluate((float)currentFrameIndex/frames.Length); floatcurvedFramerate=curveValue*framerate; //帧率有效 if(curvedFramerate!=0){ //获取当前时间 floattime=ignoreTimeScale?Time.unscaledTime:Time.time; //计算帧间隔时间 floatinterval=Mathf.Abs(1.0f/curvedFramerate); //满足更新条件,执行更新操作 if(time-timer>interval){ //执行更新操作 DoUpdate(); } } #ifUNITY_EDITOR else{ Debug.LogWarning("Framerategot'0'value,animationstopped."); } #endif } } //具体更新操作 privatevoidDoUpdate() { //计算新的索引 intnextIndex=currentFrameIndex+(int)Mathf.Sign(currentFramerate); //索引越界,表示已经到结束帧 if(nextIndex<0||nextIndex>=frames.Length){ //广播事件 if(FinishEvent!=null){ FinishEvent(); } //非循环模式,禁用脚本 if(loop==false){ currentFrameIndex=Mathf.Clamp(currentFrameIndex,0,frames.Length-1); this.enabled=false; return; } } //钳制索引 currentFrameIndex=nextIndex%frames.Length; //更新图片 if(image!=null){ image.sprite=frames[currentFrameIndex]; }elseif(spriteRenderer!=null){ spriteRenderer.sprite=frames[currentFrameIndex]; } //设置计时器为当前时间 timer=ignoreTimeScale?Time.unscaledTime:Time.time; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。