pre
- 原来写过一篇相关内容,后头一看实在太简要了,有些东西自己都不记得为啥这么写了
- 现在重新写一篇,详细一点 step by step
定时器
- 游戏里定时器简直是不可或缺的东西,比如技能冷却、怪物刷新、玩家心跳等等
- 定时器一般分为两类:单次定时器和周期定时器
- 单次定时器:定时器到时间后,执行一次回调函数,然后销毁
- 周期定时器:定时器到时间后,执行一次回调函数,然后重新计时
- 游戏里定时器的精度一般要求在毫秒(1-500ms)级别
- 常见游戏类型已经精度控制:
- FPS、赛车实时游戏:精度要求高,一般要求在1-5ms级别
- MMO游戏:精度要求一般,一般要求在200ms级别,怪物傻一点在400-500ms
- ARPG游戏:精度要求比MMO高,一般要求在50ms级别?
- 定时器的通用需求:
- 排序的
- 没有空间限制的
- 最大可能保持精度
- 对CPU、内存没有太大压力
- 上述要求看好像排序的容器就可以满足需求(set, priority_queue),也有不少介绍定时器的是用最小堆这样的容器实现的,但是这种排序容器在插入的时候有时间复杂度
- 想做到O(1)的插入时间复杂度,首先需要用到数组,假设定义一个3600长度的数组,每个下标代表1s的刻度,那这个数组最多容纳3600秒范围内的定时器,超过这个时间的就塞不进去了
时间轮-定时器
- 在我理解,时间轮核心内容是轮子的复用
标准时间
- 日常表述:(秒级)
- 钟表表示:
- 程序表述:
- 程序用时间戳(timestamp)表示时间,这里我们依然只用秒级
- 有了上面钟表表示的方式,这里的程序表示需要被分片到钟表上:把时间戳切成一个个数字(这里为了更直观用的是 % 10 的方式)(如下图)
- 上面相差的时间:2秒,49秒在程序里差异的数字分别是:(红框、橙框)
- 差值用程序的写法:
1
2
3
4
5
6
7-- 49秒
....
(04031 + 49) / 10 / 10 / 10 / 10 % 10 = 0 没有变更
(4031 + 49) / 10 / 10 / 10 % 10 = 4 没有变更
(031 + 49) / 10 / 10 % 10 = 0 没有变更
(31 + 49) / 10 % 10 = 8
(1 + 49) % 10 = 0
- 好像时间轮已经快出来了,这就是根据差值,把一个新的定时任务插入到时间轮的写法了:
1 | // cpp: xx 插入到时间轮 |
- 其实写到这里看起来时间轮这个定时器已经写好了