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

Posted 萧寒大大

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析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;

以上是关于解析ET6框架定时器的原理和使用的主要内容,如果未能解决你的问题,请参考以下文章

基于ET6框架的声音组件

解析ET6接入ILRuntime实现热更

Andfix热修复框架原理及源代码解析-上篇

KVM虚拟化技术-实战与原理解析

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段

Spring AOP源码解析:Spring事务实现原理