欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity 动画(UITweener)、协程(Coroutine)和委托(Delegate)队列管理

程序员文章站 2022-05-17 15:49:41
...

Unity 动画(UITweener)、协程(Coroutine)和委托(Delegate)队列管理

 

By D.S.Qiu

尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com

 

问题

        前段时间,项目中要做奖励界面UI缓动动画要一个接着一个播放,如:先播放达成星星动画,在播放经验数字增加动画,最后播放奖励物品动画。

        当然最笨最直接的方法可以类似成语接龙那样,把下个动画的开始播放都写在上一个动画播放完毕委托中。一般直接的方法是实现起来非常之简单,但这里却不是,会看见代码中有一系列播放完毕回调函数(除了最后一个),显然维护起来是否费劲。

        把上面的方法进行简化,把回调函数变为一个:维护一个动画的 List 和当前播放动画的索引 index ,然后再回调函数中只需要让 index 递增 播放动画就可以了。这个方法比上面成语接龙方法改进的地方在于只需要维护List中动画的顺序,不用还要做首尾结合的工作了。

 

        上面的问题之所以会觉得有点棘手是因为动画是在一个时间片段上“连续”执行的,这里的“时间片段”不是计算机概念上的 time slot 。在使用协程和延时委托也会遇到同样的问题,本来就是介绍使用队列对动画,协程和委托的管理,只需要关心彼此在队列的次序。

         

 IPlay定义  

         先定义了一个借口 IPlay 有两个方法:

                Begin() ,动画,协程 开始执行方法

                OnEnd ,动画,协程 执行完毕的回调函数(委托队列)

这里的 EventDelegate 类型是 NGUI 定义的, 可以查看参考①。 IPay 只是定义了 开始 和 结束 两个状态,其实是在 上一个 OnEnd 中执行了下一个 的 Begin 方法。

using System;
using System.Collections.Generic;
public interface IPlay
{
	List<EventDelegate> OnEnd
	{
		get;
	}
	void Begin();
}

实现IPlay

       在项目中,主要是使 UITweener 实现了 IPlay ,UITweener 本来就支持IPlay的这两个方法,只是封装下就可以了:

public abstract class UITweener : MonoBehaviour,IPlay
{
        [HideInInspector]
	public List<EventDelegate> onFinished = new List<EventDelegate>();
	//implement for IPlay infterface
	public List<EventDelegate> OnEnd
	{
		get{
			return onFinished;
		}
	}
	public void Begin()
	{
		ResetToBeginning();
		if(amountPerDelta>0)
			PlayForward();
		else if(amountPerDelta<0)
			PlayReverse();
	}
        //省略其他代码
}

 

协程实现IPlay

       协程是通过前面介绍的 TaskManager (点击查看)来实现 IPlay的方法的:

public class Task :IPlay
{
		public List<EventDelegate> onFinish = new List<EventDelegate>();

		public List<EventDelegate> OnEnd
		{
			get{
				return onFinish;
			}
		}
		public void Begin()
		{
			task.Start();
		}
                //省略其他代码
}

 

PlayList——实现队列管理

          PlayList就是维护了 IPlay 的 List ,先往 playList 中添加 IPlay ,然后通过调用 ContactPlay 把 IPlay 安装先后次序连接起来,直接贴出源码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PlaytList {
	public List<IPlay> playList = new List<IPlay>();

	private int index = 0;
	public void AddPlay(IPlay play,int index = -1)
	{
		if(play == null)
			return;
		if(index == -1)
			playList.Add(play);
		else if(index < 0 || index > playList.Count)
			return;
		else
			playList.Insert(index,play);
	}
        //添加 时间间隔
	public void AddTimeInterval(float seconds,int index = -1)
	{
		AddPlay(WaitForSeconds(seconds),index);
	}
        //添加 协程
	public void AddCoroutine(IEnumerator coroutine,int index = -1)
	{
		AddPlay(new Task(coroutine,false),index);
	}
	private void ContatPlay()
	{
		for(int i =0,length = playList.Count-1;i<length;i++)
		{
			EventDelegate.Add (playList[i].OnEnd,PlayNext);
		}
	}
	public void ClearPlay()
	{
		playList.Clear();
	}
	public void Start()
	{
		ContatPlay();
		index = 0;
		if(playList.Count>0)
			playList[0].Begin();
	}
	private void PlayNext()
	{
		index ++;
		if(index >= playList.Count)
			return;
		else
			playList[index].Begin();

	}
	public Task WaitForSeconds(float seconds)
	{
		return new Task(WaitForSecondsHandle(seconds),false);
	}
	IEnumerator WaitForSecondsHandle(float seconds)
	{
		yield return new WaitForSeconds(seconds);
	}
}

 

 

小结:

       这是 D.S.Qiu 自己写的一个小管理类,功能也很少,小团队在实际开发中最不能的就是研发,研发太占时间了,所以很多功能都是跟着需求走点到为止。为了写这篇文章今天下午还特意跑回公司,没有备份上面的代码,本来可以写点别的,等明天去公司再做进一步补充,但是D.S.Qiu只要心里有疙瘩,就不能安心去做其他事情,犹豫再三还是跑了趟公司。

       如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。

       转载请在文首注明出处:http://dsqiu.iteye.com/blog/2031778

更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风)

 

 

参考:

①NGUI EventDelegate: http://www.tasharen.com/ngui/docs/class_event_delegate.html