unity协程在写动画相关的代码时相当有用。但如果组织不当常常会导致思维混乱。这是一个使用协程的帮助类,利用装饰模式的思想最大化解耦。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class IEM : MonoBehaviour {
private IEnumerator iem = null;
public IEnumerator getIenumerator()
{
return iem;
}
//使用装饰模式来嵌套功能链条
//给一个协程增加执行前逻辑以及执行后逻辑
private IEnumerator _ACT(IEnumerator i, Action after = null, Action before = null)
{
if (before != null)
before();
if (i != null)
yield return StartCoroutine(i);
if (after != null)
after();
}
//延迟一定时间后执行
private IEnumerator _DELAY(IEnumerator i, float time)
{
if (time > 0)
yield return new WaitForSeconds(time);
if (i != null)
yield return StartCoroutine(i);
}
//执行后等待一定时间
private IEnumerator _WAIT(IEnumerator i, float time)
{
if (i != null)
yield return StartCoroutine(i);
if (time > 0)
yield return new WaitForSeconds(time);
}
//将两个协程链接在一起
private IEnumerator _JOIN(IEnumerator start, IEnumerator end)
{
if (start != null)
yield return StartCoroutine(start);
if (end != null)
yield return StartCoroutine(end);
}
public IEnumerator _WHILE(IEnumerator m, IEnumerator n)
{
Coroutine c = null;
Coroutine d = null;
if (m != null)
c = StartCoroutine(m);
if (n != null)
d = StartCoroutine(n);
yield return m;
yield return n;
}
//使用装饰模式思想 制造一个协程链条
//为了保证数据正确 原则上应从start 开始 end结束
//开始
public static IEM START()
{
GameObject s = new GameObject();
s.AddComponent<IEM>();
IEM d = s.GetComponent<IEM>() as IEM;
return d;
}
public static IEM START(IEnumerator enm)
{
GameObject s = new GameObject();
s.AddComponent<IEM>();
IEM d = s.GetComponent<IEM>() as IEM;
d.iem = enm;
return d;
}
//结束时开始执行协程 以及加入群组
public IEM END()
{
if (iem == null)
return this;
StartCoroutine(iem);
iem = null;
return this;
}
public IEM END(int group)
{
if (iem == null)
return this;
Coroutine c = StartCoroutine(iem);
CRTS.Instance.Add(group, c);
iem = null;
return this;
}
//增加行为
public IEM ACT(Action after = null, Action before = null)
{
iem = _ACT(iem, after, before);
return this;
}
//增加下一个协程
public IEM AFTER(IEnumerator after)
{
iem = _JOIN(iem, after);
return this;
}
public IEM AFTER(IEM after)
{
return AFTER(after.getIenumerator());
}
//增加上一个协程
public IEM BEFORE(IEnumerator before)
{
iem = _JOIN(before, iem);
return this;
}
public IEM BEFORE(IEM before)
{
return BEFORE(before.getIenumerator());
}
//增加延迟时间 延迟运行当前协程
public IEM TIME_BEFORE(float time)
{
iem = _DELAY(iem, time);
return this;
}
//完成协程后等待一定时间
public IEM TIME_AFTER(float time)
{
iem = _WAIT(iem, time);
return this;
}
//与其他协程共同运行
public IEM WHILE(IEnumerator enm)
{
iem = _WHILE(iem, enm);
return this;
}
public IEM WHILE(IEM enm)
{
return WHILE(enm.getIenumerator());
}
//注意 多个参数的while与单参数的while结果有巨大区别
//使用参数的while 表明 是前述协程运行完毕后再共同运行,函数生成一个新的iem返回
//而单参数的while表明与前述协程共同运行 在原IEM 基础上生效
public static IEM WHILE(params IEnumerator[] senm)
{
IEM temp = null;
foreach(IEnumerator i in senm)
{
if (i != null && temp == null)
temp = IEM.START(i);
else
temp = temp.WHILE(i);
}
return temp;
}
public static IEM WHILE(params IEM[] senm)
{
IEM temp = null;
foreach (IEM i in senm)
{
if (i != null && temp != null)
temp = i;
else
temp = temp.WHILE(i);
}
return temp;
}
//判断分支
public IEM IF(Func<bool> act,IEnumerator t = null,IEnumerator f = null)
{
bool bb = act();
if (bb)
return AFTER(t);
else
return AFTER(f);
}
public IEM IF(Func<bool> act, IEM t, IEnumerator f = null)
{
return IF(act,t.getIenumerator(),f);
}
public IEM IF(Func<bool> act, IEnumerator t, IEM f)
{
return IF(act, t, f.getIenumerator());
}
public IEM IF(Func<bool> act, IEM t , IEM f )
{
return IF(act, t.getIenumerator(), f.getIenumerator());
}
}
使用:比如一个三消游戏,棋子定义了
迭代器moveTo,棋盘定义了判断是否消除函数check则可以这样写代码:
IEM.START(g.MoveTo(l))
.WHILE(l.MoveTo(g))
.ACT(null, g.SetState_Switching).ACT(null, l.SetState_Switching)
.TIME_AFTER(1.0f)
.IF(check,IEM.START().ACT(g.SetState_death).ACT(l.SetState_death,IEM.WHILE(g.MoveTo(l),l.MoveTo(g)))
.END();
从上到下,棋子g与棋子l交换,同时l与g交换,交换之前将棋子状态设置为交换状态,交换完毕后等待1秒,然后开始check函数判断是否可以消除,判断为真将g和l状态设置为death,判断为false则交换回去。