最近在做一个小Demo,发现有很多地方需要延时调用一个方法,或者是一段逻辑才能实现功能。总结起来我感觉最常用的有以下几个。
1.定义 timeCounter 最简单的一种
float timeCounter = 0; //定义一个时间计时器
private void Update()
{
timeCounter += Time.deltaTime; //在update中调用 加上帧间隔时间
if(timeCounter > 10)
{
//TODO; //在这里写上需要在 10 秒之后执行的逻辑
}
}
这种写法虽然最为方便,但却要一直在update中实时调用,当然你也可以加一个bool,控制流程,但仍需要时时刻刻去做判断。不是一种好的写法。如果只是为了实现一些简单的功能,这种写法还是挺好用的,简单粗暴。
2.Invoke 延时调用
private void Start()
{
Invoke("ToDo",10);
}
private void ToDo()
{
//Do Something
}
这种写法也挺简单的,直接定义好逻辑然后在你想要调用的地方,直接 Invoke 就行了,但是有个问题,逻辑必须要额外的封装到一个方法中,且调用的时候需要通过方法的 字符串名称调用的。
3. Coroutines 协程
//假如在游戏开始时,我需要延时10s做一件事情
private void Start()
{
StartCoroutine("ToDo");
}
IEnumerator ToDo()
{
yield return new waitForSecond(10);
//Do Something;
}
StartCoroutine用来开启协程,StopCoroutine用来终止协程,注意参数必须是1⃣️ IEnumerator 类型的 方法字符串名称 ,如上代码所示。2⃣️还可以这样写 StartCoroutine(ToDo()); 但是这种方式 终止协程StopCoroutine(ToDo());有点不太好使,停不下来 ,原因还在寻找中。
这种写法很实用,而且随时开启并随时终止它,易于控制使用灵活。但是逻辑仍然需要额外封装,方法多了略微会降低代码的可读性。而且不停的 new waitForScond ,在优化时也是一个需要处理的很大的消耗项。
4.TimeManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//创建时间 Timer 类
public class Timer
{
Action action; //需要执行的事件
public bool isEnd = false; //时间计时结束标志
float timeCounter = 0; //时间计时器
float endTime; //终止时间
private Timer() { }
public Timer(float time, Action action) //构造方法赋值
{
timeCounter = 0;
endTime = time;
this.action = action;
}
public void Update(float dt) //提供一个公开的 Update 方法 用来计时
{
timeCounter += dt;
if (timeCounter >= endTime) //当时间计时器 加到 终止时间 的大小时,执行事件
{
action();
isEnd = true; //标记isEnd = true;
}
}
}
//时间管理器。用来管理 Timer 类实例化出来的对象
public class TimeManager
{
//单例
private static TimeManager instance;
public static TimeManager Instance
{
get
{
if (instance == null)
{
instance = new TimeManager();
}
return instance;
}
}
List<Timer> timeList = new List<Timer>(); // 创建一个链表 用来存储 Timer 对象
//Invoke 公开方法 当外界调用时 传入 timer:需要延时的时间。 action:需要执行的事件
public void Invoke(float timer, Action action)
{
Timer time = new Timer(timer, action); //调用构造时,传入参数
timeList.Add(time); //将这个 Timer 对象添加进链表中
}
//提供给外界一个 Update 方法需要实时调用
public void Update(float dt)
{
//for 循环遍历 字典,执行 链表成员 的update 方法
for (int i = 0; i < timeList.Count; i++)
{
timeList[i].Update(dt);
//当成员的某一个对象延时调用结束,则将此对象从链表中移除
if (timeList[i].isEnd)。
{
timeList.Remove(timeList[i]);
}
}
}
//提供给外界一个清空 链表的 方法
public void Clear()
{
timeList.Clear();
}
}
自己实现一个TimeManager类来管理Timer对象,当事件执行结束后,该事件所对应的Timer对象也被移除很方便。在使用时需要在一个游戏管理器中的update方法中调用一下 TimeManager.Instance.Update(Time.deltaTime);然后当需要延时调用时,可以像方法2那样将方法封装起来然后 Invoke(10,ToDo); 也可以使用Lambda表达式 Invoke(10,()=>{ //Do Someting }); 的方式来实现。
还可以进一步实现 延时重复调用方法 InvokeRepeat() ,持续时间调用方法 ContinueExecute() ,等;还可以进一步扩展Timer 对象的类型,使之在不同的游戏状态下,执行不同的延时事件。可扩展性很高,配合游戏管理器来使用很方便。
个人见解,如有错误,敬请指正。