using System;
using XGame.Framework.Interfaces;
namespace XGame.Framework.Time
{
public class Timer : ITimer, IReset
{
public enum TimerRunState : sbyte
{
None,
Running,
Paused,
Stoped,
Finished,
Exception,
}
private int _delay;
///
/// 间隔
///
private int _interval;
///
/// 时间轴
///
private int _timeAxis;
///
/// 循环次数上限
///
private int _loopTimes;
private Action _action;
private Action _actionLoop;
public ITimeListener Listener { get; set; }
public float TimeScale { get; set; } = 1;
private int _passTimes;
private TimerRunState _runState;
public TimerRunState State
{
get => _runState;
private set
{
_runState = value;
if (value is TimerRunState.Stoped or TimerRunState.Finished or TimerRunState.Exception)
{
try
{
Listener?.OnCompleted(this);
}
catch (Exception ex)
{
Log.Exception($"定时器事件监听执行异常.", ex);
}
Listener = null;
}
}
}
internal Timer(int delay, int interval, int looptimes, Action action)
{
#if UNITY_EDITOR
UnityEngine.Assertions.Assert.IsTrue(delay >= 0, "延迟不能<0");
UnityEngine.Assertions.Assert.IsTrue(!(delay == 0 && looptimes == 1), "立即执行的延迟定时器次数不能小于2");
UnityEngine.Assertions.Assert.IsTrue(interval > 0, "定时器间隔不能<=0");
UnityEngine.Assertions.Assert.IsTrue(looptimes != 0, "定时器执行次数不能为0,如果要无限循环请设置为-1");
UnityEngine.Assertions.Assert.IsNotNull(action, "定时器回调不能为null");
#endif
_action = action;
InnerInit(delay, interval, looptimes);
}
internal Timer(int delay, int interval, int looptimes, Action action)
{
#if UNITY_EDITOR
UnityEngine.Assertions.Assert.IsTrue(delay >= 0, "延迟不能<0");
UnityEngine.Assertions.Assert.IsTrue(!(delay == 0 && looptimes == 1), "立即执行的延迟定时器次数不能小于2");
UnityEngine.Assertions.Assert.IsTrue(interval > 0, "定时器间隔不能<=0");
UnityEngine.Assertions.Assert.IsTrue(looptimes != 0, "定时器执行次数不能为0,如果要无限循环请设置为-1");
UnityEngine.Assertions.Assert.IsNotNull(action, "定时器回调不能为null");
#endif
_actionLoop = action;
InnerInit(delay, interval, looptimes);
}
private void InnerInit(int delay, int interval, int looptimes)
{
_delay = delay;
_interval = interval;
_loopTimes = looptimes;
_passTimes = 0;
State = TimerRunState.Running;
}
//校准时间
private float addingValue = 0;
private int CorrectTime(int deltaTime)
{
float updateTime = (float)deltaTime * TimeScale;
int elapse = (int)updateTime;
float timeDecimals = updateTime - elapse;
addingValue += timeDecimals;
if (addingValue >= 1.0f)
{
elapse += 1;
addingValue -= 1.0f;
}
return elapse;
}
internal bool Update(int deltaTime)
{
switch (State)
{
case TimerRunState.Stoped:
case TimerRunState.Finished:
case TimerRunState.Exception:
return true;
case TimerRunState.Paused:
return false;
}
int correctedTime = CorrectTime(deltaTime);
_timeAxis += correctedTime;
var interval = _passTimes == 0 ? _delay : _interval;
if (_timeAxis > interval)
{
_timeAxis -= interval;
_passTimes += 1;
try
{
_action?.Invoke();
_actionLoop?.Invoke(_passTimes);
}
catch (Exception e)
{
State = TimerRunState.Exception;
Log.Exception($"定时器回调执行发生异常({_passTimes}/{_loopTimes})", e);
//throw new Exception($"定时器回调执行发生异常({_passTimes}/{_loopTimes}):{e}");
}
if (_passTimes == _loopTimes)
{
State = TimerRunState.Finished;
return true;
}
}
return false;
}
public void Cancel()
{
State = TimerRunState.Stoped;
_action = null;
_actionLoop = null;
}
public void Pause()
{
if (State == TimerRunState.Running)
State = TimerRunState.Paused;
}
public void Resume()
{
if (State == TimerRunState.Paused)
State = TimerRunState.Running;
}
public void Dispose()
{
_action = null;
_actionLoop = null;
Listener = null;
}
///
/// 只对Running状态的定时器有效
///
void IReset.Reset()
{
if (State != TimerRunState.Running)
{
return;
}
_timeAxis = 0;
_passTimes = 0;
}
public int TimeAxis => _timeAxis;
///
/// 只对Running状态的定时器有效
///
///
public void ResetForAxis(int timeAsis)
{
if (State != TimerRunState.Running)
{
return;
}
_timeAxis = timeAsis;
_passTimes = 0;
}
}
}