目录
前言:
一、定义定时器
1、定义帧定时器类
2、定义普通定时器
二、定时器管理类
Unity游戏开发中需要定时器的原因主要有以下几点:
延迟操作:游戏中有很多需要在一定的时间间隔之后才能执行的操作。例如在某个角色死亡后需要重新生成、在物品被拾取后需要消失、在陷阱触发后需要一段时间再释放等等。此时就可以使用定时器来实现延迟操作,达到需要的效果。
倒计时:游戏中有很多需要倒计时的情况,例如任务倒计时、炸弹倒计时等。在这种情况下,我们可以使用定时器来记录时间并显示倒计时。当时间到达指定时间后,就可以执行相应的操作。
动画控制:在游戏中,一些动画需要精确的时间控制,例如闪烁、振动等。在这种情况下,定时器可以很好的帮助我们控制动画的播放时间和速度,使得动画可以按照我们的预期进行。
总之,定时器在Unity游戏开发中非常重要,可以帮助我们实现延迟操作、倒计时、精确的动画控制等功能。通过使用定时器,我们能够更加方便地控制游戏对象的行为和状态,从而提高游戏的玩家体验。
定时器是unity前端架构中必须有的一个模块功能。定时器一定要满足几个需求
第一、需要能够添加和删除定时器
第二、实现延时触发一次
第三、实现循环调用
第四、实现隔一定帧数调用一次
帧定时器在希望某个操作在下一帧或一定帧数后执行,定时器接口中包含两个参数,定时器ID和object类型参数
Action _action;
隔多少帧调用
_maxFrameCount
完整的帧定时器代码如下:
public class FrameTimer
{
private Action _action;
private int _maxFrameCount;
private int _currentFrame;
private object _param;
public FrameTimer(Action action, object param = null, int maxFrame = 1)
{
_action = action;
_maxFrameCount = maxFrame;
_param = param;
}
public bool Execute()
{
try
{
if (_action != null)
_action(0, _param);
}
catch (Exception e)
{
ULog.Error(e);
}
return false;
}
public bool TryAction()
{
_currentFrame++;
if (_currentFrame == _maxFrameCount)
return true;
return false;
}
}
如果是延时调用的一次定时器_intervalSeconds是延时时间
如果是循环(_isLoop)调用的定时器 _intervalSeconds,就是调用间隔时间
private float _intervalSeconds;
private bool _isLoop;
普通定时器类定义
public class OneTimer
{
public Action _action;
private object _param;
private float _intervalSeconds;
private bool _isLoop;
private float _beginTime;
private int _id;
public OneTimer(Action action,float intervalSeconds,object param=null,bool isLoop=false)
{
_id = UId.I.NextId();
_action = action;
_param = param;
_isLoop = isLoop;
_beginTime = TimeUtils.RealtimeSinceStartup;
_intervalSeconds = intervalSeconds;
}
public void Execute()
{
try
{
if (_action != null)
_action(_id, _param);
}
catch (Exception e)
{
ULog.Error(e);
}
}
public int Id
{
get { return _id; }
}
public float GetEndTime()
{
return _beginTime + _intervalSeconds;
}
public bool IsLoop
{
get { return _isLoop; }
}
public void UpdateNextTime()
{
_beginTime = GetEndTime();
}
public override string ToString()
{
StringBuilder sb = UString.GetBuilder();
sb.Append(" id:" + _id);
sb.Append(" ");
if (_action != null)
{
if (_action.Target != null)
{
sb.Append(_action.Target.ToString());
sb.Append(":");
}
if (_action.Method != null)
{
sb.Append(_action.Method.ToString());
}
}
sb.Append(" param:");
sb.Append(_param);
sb.Append(" intervalSeconds:");
sb.Append(_intervalSeconds);
sb.Append(" _isLoop:");
sb.Append(_isLoop);
sb.Append(" beginTime:");
sb.Append(_beginTime);
sb.Append(" waitSeconds:");
sb.Append(GetEndTime() - TimeUtils.RealtimeSinceStartup);
return sb.ToString();
}
}
定时器定义每帧调用函数Update,_timers管理的是普通定时器,_frames管理的是帧定时器
UpdateFrameTimer循环遍历帧定时器是否符合触发条件,并进行触发
普通定时器隔一定时间判定一次,CHECK_INTERVAL_SECONDS来确定
const float CHECK_INTERVAL_SECONDS = 0.1f;
public class TimersComponent
{
const float CHECK_INTERVAL_SECONDS = 0.1f;
private List _timers = new List();
private List _timersTemp = new List();
private float _NextCheckTime = 0.0f;
private List _frames = new List();
public int AddLoop(Action action, float intervalSeconds,object param=null)
{
return Register(intervalSeconds, action, null, false);
}
public int AddOnce(Action action, float beginSecond, object param)
{
return Register(beginSecond, action, param);
}
public void AddOnceDelayFrame(Action action, object param=null,int delayFrameCount=1)
{
_frames.Add(new FrameTimer(action,param, delayFrameCount));
}
private int Register(float intervalSeconds, Action action, object param = null, bool isLoop = false)
{
if (action == null)
{
LogError("Register: callback is null");
return 0;
}
if (intervalSeconds <= 0.0f)
{
LogError("Register: intervalSeconds = " + intervalSeconds + " <= 0.0f");
return 0;
}
OneTimer data = new OneTimer(action, intervalSeconds, param, isLoop);
_timers.Add(data);
if (intervalSeconds < CHECK_INTERVAL_SECONDS)
{
LogError("Register: Interval seconds: " + intervalSeconds + " < " + CHECK_INTERVAL_SECONDS);
}
if (_timers.Count >= 128)
{
LogError("Register: Too many timers: " + _timers.Count + " >= 128. Please redesign TimerSimple");
}
return data.Id;
}
public bool Remove(int id)
{
for (int i = 0; i < _timers.Count; ++i)
{
if (_timers[i].Id == id)
{
_timers.RemoveAt(i);
return true;
}
}
return false;
}
public bool Remove(Action action)
{
if (action == null)
{
return false;
}
bool find = false;
for (int i = 0; i < _timers.Count; ++i)
{
if (_timers[i]._action == action)
{
find = true;
_timers.RemoveAt(i);
--i;
}
}
return find;
}
public void Update()
{
UpdateFrameTimer();
float curTime = TimeUtils.RealtimeSinceStartup;
if (curTime < _NextCheckTime)
{
return;
}
if (_NextCheckTime <= 0.0f)
{
_NextCheckTime = TimeUtils.RealtimeSinceStartup + CHECK_INTERVAL_SECONDS;
return;
}
_NextCheckTime = curTime + CHECK_INTERVAL_SECONDS;
_timersTemp.Clear();
for (int i = 0; i < _timers.Count; ++i)
{
OneTimer oneTimer = _timers[i];
float endTime = oneTimer.GetEndTime();
if (curTime >= endTime)
{
_timersTemp.Add(oneTimer);
if (!oneTimer.IsLoop)
{
_timers.RemoveAt(i);
--i;
}
}
}
for (int i = 0; i < _timersTemp.Count; ++i)
{
OneTimer oneTimer = _timersTemp[i];
oneTimer.Execute();
oneTimer.UpdateNextTime();
}
_timersTemp.Clear();
}
private void UpdateFrameTimer()
{
for (int i = 0; i < _frames.Count; i++)
{
FrameTimer timer = _frames[i];
if (timer.TryAction())
{
timer.Execute();
--i;
_frames.RemoveAt(i);
continue;
}
}
}
static void LogError(string str)
{
Debug.LogError(TimeUtils.RealtimeSinceStartup + " TimerSimple." + str);
}
public void Destroy()
{
base.Destroy();
_timersTemp.Clear();
_timers.Clear();
_frames.Clear();
}
}
当我们想要创建定时器时根据:循环定时器AddLoop、一次调用定时器AddOnce、一次调用帧定时器AddOnceDelayFrame接口创建我们想要的定时器。通过定时器id来Remove接口删除相应的定时器