unity前端架构之定时器完整代码实现

目录

前言:

一、定义定时器

1、定义帧定时器类

2、定义普通定时器

 二、定时器管理类


前言:

Unity游戏开发中需要定时器的原因主要有以下几点:

  1. 延迟操作:游戏中有很多需要在一定的时间间隔之后才能执行的操作。例如在某个角色死亡后需要重新生成、在物品被拾取后需要消失、在陷阱触发后需要一段时间再释放等等。此时就可以使用定时器来实现延迟操作,达到需要的效果。

  2. 倒计时:游戏中有很多需要倒计时的情况,例如任务倒计时、炸弹倒计时等。在这种情况下,我们可以使用定时器来记录时间并显示倒计时。当时间到达指定时间后,就可以执行相应的操作。

  3. 动画控制:在游戏中,一些动画需要精确的时间控制,例如闪烁、振动等。在这种情况下,定时器可以很好的帮助我们控制动画的播放时间和速度,使得动画可以按照我们的预期进行。

总之,定时器在Unity游戏开发中非常重要,可以帮助我们实现延迟操作、倒计时、精确的动画控制等功能。通过使用定时器,我们能够更加方便地控制游戏对象的行为和状态,从而提高游戏的玩家体验。

定时器是unity前端架构中必须有的一个模块功能。定时器一定要满足几个需求

第一、需要能够添加和删除定时器

第二、实现延时触发一次

第三、实现循环调用

第四、实现隔一定帧数调用一次


一、定义定时器

1、定义帧定时器类

帧定时器在希望某个操作在下一帧或一定帧数后执行,定时器接口中包含两个参数,定时器ID和object类型参数

Action<int, object> _action;

 隔多少帧调用

_maxFrameCount 

完整的帧定时器代码如下: 

 public class FrameTimer
    {
        private Action<int, object> _action;
        private int _maxFrameCount;
        private int _currentFrame;
        private object _param;

        public FrameTimer(Action<int, object> 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;
        }

    }

2、定义普通定时器

如果是延时调用的一次定时器_intervalSeconds是延时时间

如果是循环(_isLoop)调用的定时器 _intervalSeconds,就是调用间隔时间

private float _intervalSeconds;
private bool _isLoop;

普通定时器类定义

 public class OneTimer
    {
        public Action<int,object> _action;
        private object _param;
        private float _intervalSeconds;
        private bool _isLoop;

        private float _beginTime;
        private int _id;


        public OneTimer(Action<int, object> 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<OneTimer> _timers = new List<OneTimer>();
        private List<OneTimer> _timersTemp = new List<OneTimer>();
        private float _NextCheckTime = 0.0f;

        private List<FrameTimer> _frames = new List<FrameTimer>();


        public int  AddLoop(Action<int,object> action, float intervalSeconds,object param=null)
        {
            return Register(intervalSeconds, action, null, false);
        }

        public int AddOnce(Action<int, object> action, float beginSecond, object param)
        {
            return Register(beginSecond, action, param);
        }

        public void  AddOnceDelayFrame(Action<int, object> action, object param=null,int delayFrameCount=1)
        {
            _frames.Add(new FrameTimer(action,param, delayFrameCount));
        }

        private int Register(float intervalSeconds, Action<int, object> 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<int, object> 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接口删除相应的定时器


猜你喜欢

转载自blog.csdn.net/lejian/article/details/131076978