解析ET6框架定时器的原理和使用

1.介绍

 在游戏逻辑编写中定时器是必不可少的,接下来我就来解析ET6框架的定时器的原理和使用。

2.原理(TimerComponent.cs)

1.awake

将所有TimerAttribute的类型的类存入timerActions数组

        public void Awake()
        {
            this.timerActions = new ITimer[TimeTypeMax];

            //获取所有TimerAttribute的类型
            HashSet<Type> types = Game.EventSystem.GetTypes(typeof (TimerAttribute));

            foreach (Type type in types)
            {
                ITimer iTimer = Activator.CreateInstance(type) as ITimer;
                if (iTimer == null)
                {
                    Log.Error($"Timer Action {type.Name} 需要继承 ITimer");
                    continue;
                }
                
                object[] attrs = type.GetCustomAttributes(typeof(TimerAttribute), false);
                if (attrs.Length == 0)
                {
                    continue;
                }
                //将TimerAttribute的类保存在timerActions数组
                foreach (object attr in attrs)
                {
                    TimerAttribute timerAttribute = attr as TimerAttribute;
                    this.timerActions[timerAttribute.Type] = iTimer;
                }
            }
        }

 2.WaitTillAsync/WaitFrameAsync/WaitAsync/NewOnceTimer/NewFrameTimer/NewRepeatedTimer(以WaitAsync为例子)

创建TimerAction到子节点,并添加timer到TimeId上

        public async ETTask<bool> WaitAsync(long time, ETCancellationToken cancellationToken = null)
        {
            if (time == 0)
            {
                return true;
            }
            long tillTime = TimeHelper.ServerNow() + time;

            ETTask<bool> tcs = ETTask<bool>.Create(true);
            //在子节点创建TimerAction
            TimerAction timer = this.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceWaitTimer, time, 0, tcs, true);
            //添加到TimeId上
            this.AddTimer(tillTime, timer);
            long timerId = timer.Id;

            //移除timer并且返回false
            void CancelAction()
            {
                if (this.Remove(timerId))
                {
                    tcs.SetResult(false);
                }
            }

            bool ret;
            //cancellationToken不为null就添加CancelAction方法
            try
            {
                cancellationToken?.Add(CancelAction);
                ret = await tcs;
            }
            finally
            {
                cancellationToken?.Remove(CancelAction); 
            }
            return ret;
        }

3.Update

 每帧刷新,将超时的timer执行run方法并从TimeId中移除

        public void Update()
        {
            if (this.TimeId.Count == 0)
            {
                return;
            }

            long timeNow = TimeHelper.ServerNow();

            if (timeNow < this.minTime)
            {
                return;
            }
            //到时间的timer压入timeOutTime队列
            foreach (KeyValuePair<long, List<long>> kv in this.TimeId)
            {
                long k = kv.Key;
                if (k > timeNow)
                {
                    minTime = k;
                    break;
                }

                this.timeOutTime.Enqueue(k);
            }
            //将到时的的timerId压入timeOutTimerIds队列并从TimeId移除该timer
            while (this.timeOutTime.Count > 0)
            {
                long time = this.timeOutTime.Dequeue();
                foreach (long timerId in this.TimeId[time])
                {
                    this.timeOutTimerIds.Enqueue(timerId);
                }

                this.TimeId.Remove(time);
            }
            //执行所有到时的计时器的timerAction
            while (this.timeOutTimerIds.Count > 0)
            {
                long timerId = this.timeOutTimerIds.Dequeue();

                TimerAction timerAction = this.GetChild<TimerAction>(timerId);
                if (timerAction == null)
                {
                    continue;
                }
                //执行timer标签类的run方法
                Run(timerAction);
            }
        }

 4.Run

执行timer的run方法

        private void Run(TimerAction timerAction)
        {
            switch (timerAction.TimerClass)
            {
                case TimerClass.OnceTimer://回调等待,需要自己移除timer(单次)
                {
                    int type = timerAction.Type;
                    ITimer timer = this.timerActions[type];
                    if (timer == null)
                    {
                        Log.Error($"not found timer action: {type}");
                        return;
                    }
                    timer.Handle(timerAction.Object);
                    break;
                }
                case TimerClass.OnceWaitTimer://携程等待,自动移除timer并返回true(单次)
                {
                    ETTask<bool> tcs = timerAction.Object as ETTask<bool>;
                    this.Remove(timerAction.Id);
                    tcs.SetResult(true);
                    break;
                }
                case TimerClass.RepeatedTimer://回调等待,需要自己移除timer(多次)
                    {
                    int type = timerAction.Type;
                    long tillTime = TimeHelper.ServerNow() + timerAction.Time;
                    this.AddTimer(tillTime, timerAction);

                    ITimer timer = this.timerActions[type];
                    if (timer == null)
                    {
                        Log.Error($"not found timer action: {type}");
                        return;
                    }
                    timer.Handle(timerAction.Object);
                    break;
                }
            }
        }

5.Remove

移除定时器

        public bool Remove(ref long id)
        {
            long i = id;
            id = 0;
            return this.Remove(i);
        }
        
        private bool Remove(long id)
        {
            if (id == 0)
            {
                return false;
            }
            //从子节点移除TimerAction
            TimerAction timerAction = this.GetChild<TimerAction>(id);
            if (timerAction == null)
            {
                return false;
            }
            timerAction.Dispose();
            return true;
        }

3.使用

1.打上timer标签,继承ATimer,并重写Run方法

    [Timer(TimerType.AITimer)]
    public class AITimer: ATimer<AIComponent>
    {
        public override void Run(AIComponent self)
        {
            //方法
        }
    }

2.注册定时器

self.Timer = TimerComponent.Instance.NewRepeatedTimer(1000, TimerType.AITimer, self);
//中途可取消
bool timeRet = await TimerComponent.Instance.WaitAsync(1000, cancellationToken);

3.销毁定时器

TimerComponent.Instance.Remove(ref self.Timer);
self.CancellationToken?.Cancel();
self.CancellationToken = null;

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>