先上代碼,本身沒有任何高科技的東西,不過很好用和方便。 [cpp] #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); } [cpp] #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秒開始戰斗流程。那麼就可以這麼寫。 [cpp] 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的無窮魅力,還在用函數指針的同學要補充一下新工具了。