常见游戏中高性能定时器,有两种实现:
时间轮定时器
最小堆定时器
时间轮定时器
将定时器的走时假定为一个轮盘,通过合适的算法将每一个定时器都放入到轮盘中,轮盘又分N(最好是2的多少次方)个槽,一个槽对应一个tick,
所以一个轮盘一圈总时间为N*tick。考虑到有些时间长的定时器,可能要转好几圈(rotation)。
#include <functional>
#include "CodeException.h"
#include "ObjectPool.h"
template<typename Player>
struct Timer {
Timer(int nRotation, int timeSlot):rotation(nRotation), time_slot(timeSlot){}
int rotation;
int time_slot;
std::function<void(const Player)> pf_task_call;
Player pPlayer;
Timer<Player>* pNext = nullptr;
};
template<typename Player>
class Timer_Wheel {
static const int _n_slot_size = 64;//2的6次方
static const int _n_min_duration = 1;
Timer<Player>* _p_array_slot[_n_slot_size]{ nullptr };
int _n_cur_slot = 0;
public:
Timer_Wheel() {
ObjectAllocator::getInstance().Init<Timer<Player>>();
}
inline Timer<Player>* addTimer(int nDuration) {
if (nDuration < _n_min_duration) throw CodeExceptionLog("illegal args");
int time_slot = nDuration % _n_slot_size;
Timer<Player>* pTimer = ObjectAllocator::getInstance().allocate<Timer<Player>>(nDuration / _n_slot_size, time_slot);
if (nullptr == _p_array_slot[time_slot])
{
_p_array_slot[time_slot] = pTimer;
}
else
{
pTimer->pNext = _p_array_slot[time_slot];
_p_array_slot[time_slot] = pTimer;
}
return pTimer;
}
void tick() {
Timer<Player>* pTimer = _p_array_slot[_n_cur_slot];
Timer<Player>* pPreTimer = nullptr;
while (pTimer)
{
if (0 != pTimer->rotation)
{
--(pTimer->rotation);
pPreTimer = pTimer;//设置前置节点
pTimer = pTimer->pNext;
}
else
{
pTimer->pf_task_call(pTimer->pPlayer);
//从_p_array_slot[_n_cur_slot]中删除pTimer
if (pPreTimer == nullptr)//前置节点为空,第一个节点
{
//只有删除第一个才需要修改_p_array_slot[_n_cur_slot]
_p_array_slot[_n_cur_slot] = pTimer->pNext;
}
else
{
pPreTimer->pNext = pTimer->pNext;
}
Timer<Player>* pTemp = pTimer->pNext;
ObjectAllocator::getInstance().deletor<Timer<Player>>(pTimer);
pTimer = pTemp;
}
}
_n_cur_slot = (_n_cur_slot + 1) % _n_slot_size;
}
};