前言
Unity游戏开发中,我们常用Unity的协程来实现延时,使用频率还是蛮高的,例如:分帧加载,延时加载等,感觉有必要做成一个通用的库,但正好看到网上有人写好了这块,就不重复造轮子了,就收入囊中了,感谢作者!
简要说明
- 简单上手:在脚本中使用this作为入口,e.g. this.Delayer(1, DoSomething);
- 自定义:e.g. this.Sequence().Loop(2).Interval(1).Action(DoSomething1).Interval(0.5f).Action(DoSomething2);
- 无GC:使用了内存池存放序列和节点,在数组容量足够的情况下,运行时无GC(数组自动扩容会产生GC)
- 自动回收:使用Component或其子类作为ID受控,一旦ID被销毁,计时器会随之自动回收
- 精准受控:准确停止指定的计时器(请看使用方法的最后)
- 支持时间缩放:支持deltaTime和unscaledDeltaTime
设计架构
ActionSequenceSystem序列系统
- 使用了内存池
- 管理ActionSequence
ActionSequence序列
- 对Component做了扩展,在脚本中使用this作为入口
- 对Component实例做了依赖,使其可以随Component实例的销毁自动回收
- 可自定义,加入不同的ActionNode实现不同的行为链
ActionNode节点
- Action:执行函数
- Interval: 延时一段时间
- SetActive:激活物体/反激活物体
- WaitFor:知道条件判断为true才跳下一个节点
使用方法
说明:下面使用方法中的this的类型为Component或其子类(其实this is MonoBehaviour)
延迟开关GameObject功能
既然用了Component来做ID,控制gameObject显示隐藏就是举手之劳,何乐而不为1
2
3
4
5
6//Start a toggle gameObject active/deactive sequence
tfShowHideExample.Shower(0.5f);
tfShowHideExample.Hider(1.5f);
//Start a infinite loop toggle active gameObject
tfShowHideExample.Sequence().Interval(0.5f).ToggleActive().Loop();
开启单次计时器(延迟)
1 | //Start a once timer |
开启计次计时器(次数)
1 | //Start a loop timer |
开启无限计时器
相当于计次计时器的缩写,循环次数设置为-11
2//Start a infinite loop timer
this.Looper(1, i => Debug.Log("Infiniter" + i));
开启自定义序列
1 | //Start a custom sequence |
停止序列
1 | //Stop the sequence with the specified ID |
可以不用ID直接开序列
1 | //Start a sequence without id. |
停止序列特殊技巧:ActionSequenceHandle用法
简单来说就是引用一个计时器,让我们可以随时手动停止它
但ActionSequence自身有停止的方法,为什么还要使用ActionSequenceHandle?
ActionSequenceHandle是为了处理“开启全局计时器时不传入ID,又要控制这个计时器”的情况1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public class ActionSequenceHandleExample : MonoBehaviour
{
private readonly ActionSequenceHandle infiniteSequenceHandle = new ActionSequenceHandle();
private ActionSequence sequence;
private void Start()
{
//Notes:An instance must be preserved to manually stop an infinite loop sequence.
ActionSequenceSystem.Looper(infiniteSequenceHandle, 0.2f, -1, false, () => Debug.Log("No id infinite looper"));
sequence = this.Looper(0.5f, 3, false, () => Debug.Log("this looper"));
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.B))
{
//使用ActionSequenceHandle停止
infiniteSequenceHandle.StopSequence();
//使用ActionSequence停止
sequence.Stop(this);
this.StopSequence(sequence);//Same as sequence.Stop(this);
}
if (Input.GetKeyDown(KeyCode.X))
{
transform.Looper(infiniteSequenceHandle, 1, 5, false, i =>
{
if (i == 2)
{
infiniteSequenceHandle.StopSequence();
}
});
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59using GF.MonoBehavior.ActionSequenceSystem;
using UnityEngine;
public class ActionSequence : MonoBehaviour
{
private readonly ActionSequenceHandle infiniteSequenceHandle = new ActionSequenceHandle();
public Transform ShowHideExample;
void Start()
{
//延时执行
this.Delayer(1, () => Debug.Log("延时1s执行"));
transform.Delayer(1, () => Debug.Log("延时1s执行"));
ActionSequenceSystem.Delayer(5, () => Debug.Log("不依赖物体的延时执行"));
ActionSequenceSystem.Looper(0.2f, 10, false, () => Debug.Log("不依赖物体的延时执行"));
//循环执行,设置执行次数
this.Looper(0.5f, 3, false, () => Debug.Log("循环执行三次,并且延时0.5s执行"));
//支持延时序列,增加一个运行节点
this.Sequence().Interval(1).Action(() => Debug.Log("延时序列 ,增加一个运行节点"));
//循环1s执行一次
this.Looper(1, i => Debug.Log("循环执行" + i));
//定时检测按键次数
this.Sequence()
.Loop()
.Interval(1f) //间隔1秒
.WaitFor(() => Input.GetKeyDown(KeyCode.Q))
.Action(n => Debug.Log("Q键 按下次数" + n));
//延时0.5s隐藏物体
ShowHideExample.Hider(0.5f);
//0.5s显示/隐藏物体
ShowHideExample.Sequence().Interval(0.5f).ToggleActive().Loop();
//停止所有序列
ActionSequenceSystem.StopSequenceAll();
//事件循环
this.LooperUnscaled(infiniteSequenceHandle, 1f, () => Debug.Log("No id infinite looper"));
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.B))
{
infiniteSequenceHandle.StopSequence();
}
if (Input.GetKeyDown(KeyCode.X))
{
transform.LooperUnscaled(infiniteSequenceHandle, 1, 5, false, i =>
{
Debug.Log("transform looper " + i);
if (i == 2)
{
infiniteSequenceHandle.StopSequence();
}
});
}
}
}
GFFramework地址
https://github.com/dingxiaowei/GFFrameWork