先上代码,本身没有任何高科技的东西,不过很好用和方便。
#pragma once
#include "CommandQueue.h"
#include "GlobalFunction.h"
//
// 计时器回调函数.
//
typedef function<void(int)> TimerCallback;
class Timer
{
public:
Timer(int timerId, int ms, bool isLoop, const TimerCallback& func);
virtual ~Timer() {};
int getId() const
{
return m_timerId;
}
// return true if need remove
bool process();
private:
int m_timerId;
bool m_isLoop;
unsigned int m_startTime;
unsigned int m_delayTime;
TimerCallback m_function;
};
#ifdef USE_FOR_COCOS2D
class TimerObject : public Timer
{
public:
TimerObject(int timerId, int ms, bool isLoop, const TimerCallback& func, CCObject* target);
virtual ~TimerObject();
private:
CCObject* m_target;
};
#endif
class TimerMgr : public MySingleton<TimerMgr>
{
public:
TimerMgr()
{
m_currentTimerId = 0;
};
~TimerMgr() {};
int addTimer(int ms, bool loop, TimerCallback func)
{
Timer* timer = new Timer(++m_currentTimerId, ms, loop, func);
m_allTimers.push_back(std::move(timer));
return m_currentTimerId;
}
#ifdef USE_FOR_COCOS2D
int addTimerObject(int ms, bool loop, TimerCallback func, CCObject* target)
{
TimerObject* timer = new TimerObject(++m_currentTimerId, ms, loop, func, target);
m_allTimers.push_back(timer);
return m_currentTimerId;
}
#endif
void deleteTimer(int timerId)
{
auto itr = std::find_if(m_allTimers.begin(), m_allTimers.end(), [timerId](Timer* timer){
return (timer && timer->getId() == timerId);
});
delete *itr;
m_allTimers.erase(itr);
}
void processTimer();
private:
unsigned int m_currentTimerId;
unsigned int m_timerMgrStart;
std::vector<Timer*> m_allTimers;
};
inline int delay_call(int ms, const TimerCallback& func, bool isLoop = false)
{
return TimerMgr::getSingleton().addTimer(ms, isLoop, func);
}
inline int delay_call(CCObject* target, int ms, const TimerCallback& func, bool isLoop = false)
{
return TimerMgr::getSingleton().addTimerObject(ms, isLoop, func, target);
}
#ifdef USE_FOR_COCOS2D
// 用法PERFORM_SELECTOR(延迟时间毫秒, 回调函数, 参数),有几个参数调用PERFORM_SELECTORn
#define PERFORM_SELECTOR(ms, func, ...) delay_call(this, static_cast<int>(ms), bind(&func, this, ##__VA_ARGS__))
#endif
inline void remove_timer(int timerId)
{
TimerMgr::getSingleton().deleteTimer(timerId);
}
#include "stdafx.h"
#include "TimerUtil.h"
TimerObject::TimerObject(int timerId, int ms, bool isLoop, const TimerCallback& func, CCObject* target):Timer(timerId, ms, isLoop, func)
{
m_target = target;
m_target->retain();
}
TimerObject::~TimerObject()
{
if (m_target) {
m_target->release();
m_target = NULL;
}
}
Timer::Timer(int timerId, int ms, bool isLoop, const TimerCallback& func)
{
m_timerId = timerId;
m_isLoop = isLoop;
// 可以循环,第一次直接调用
if (isLoop) {
m_startTime = 0;
} else {
m_startTime = TimeGet();
}
m_delayTime = ms;
m_function = std::move(func);
}
bool Timer::process()
{
if (TimeGet() < m_startTime + m_delayTime) {
return false;
}
m_function(m_timerId);
if (m_isLoop) {
m_startTime = TimeGet();
return false;
} else {
return true;
}
}
void TimerMgr::processTimer()
{
for (int i = 0; i < (int)m_allTimers.size(); ++i) {
Timer* timer = m_allTimers[i];
if (timer && timer->process()) {
delete timer;
m_allTimers[i] = NULL;
}
}
for (auto itr = m_allTimers.begin(); itr != m_allTimers.end();) {
if (*itr == NULL) {
itr = m_allTimers.erase(itr);
} else {
++itr;
}
}
}
计时器说简单也很简单,就是纪录开始时间,每桢监测,如果到延迟时间了则执行对应的回调函数。 算是游戏中非常基础的工具类。这里借助function和bind实现了更加灵活的回调绑定。 回调函数没有任何限制,也不需要回调者继承任何东西。比如我们有一个战斗管理者,开始战斗的时候播放一个特效,延时1秒开始战斗流程。那么就可以这么写。
class FightMgr
{
public:
void play()
{
// play effect here
delay_call(1000, bind(&FightMgr::startFight, this, param1, param2), false);
}
void startFight(int playerId, int data)
{
}
}
计时器delay_call第二个参数是一个function,通过bind可以绑定任意函数,甚至可以传lambda。
这个计时器并不是多线程异步操作的,需要游戏每桢运行的时候调用TimerMgr::getSingleton().process(); 这样的好处是我们写代码的时候不需要考虑线程同步,虽然我延时执行某些函数,但是都是在主线程完成的调用,也不用担心opengl的content失效等问题。
没有其他需要特意说明的了,最后再次感叹一下function的无穷魅力,还在用函数指针的同学要补充一下新工具了。