保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈。
一、游戏主循环GameSchedule
主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的。写一个简单的游戏主循环是很有必要的~
游戏主循环有开始、有结束、有暂停、有恢复把握好进度,控制好游戏,处理好逻辑。我在Cocos2dx进入主场景时开启游戏主循环,在永远不再使用时删除主循环,在游戏暂停时pause主循环,在游戏恢复时resume主循环。
#ifndef __GameSchedule__ #define __GameSchedule__ #include "cocos2d.h" USING_NS_CC; class GameSchedule : public Ref { public: static GameSchedule* getInstance(); void start(); void end(); static void pause(); static void resume(); private: virtual void onExit(); ~GameSchedule(); void globalUpdate(float time); void init(); }; #endif
#include "GameSchedule.h" #include "GameDelayTime.h" #include "SceneMgr.h" static GameSchedule* _instance = nullptr; static bool _pause = true; GameSchedule* GameSchedule::getInstance() { if( !_instance ) { _instance = new GameSchedule(); _instance->init(); } return _instance; } void GameSchedule::init() { _pause = true; } void GameSchedule::start() { log("GameSchedule -----> start "); _pause = false; Director::getInstance()->getScheduler()->schedule(schedule_selector(GameSchedule::globalUpdate),this,0,false); } void GameSchedule::end() { log("GameSchedule -----> end "); Director::getInstance()->getScheduler()->unschedule(schedule_selector(GameSchedule::globalUpdate),this); CC_SAFE_DELETE(_instance); } void GameSchedule::pause() { log("GameSchedule -----> pause "); _pause = true; } void GameSchedule::resume() { log("GameSchedule -----> resume "); _pause = false; } void GameSchedule::globalUpdate(float time) { if( _pause ) return; GameDelayTime::getInstance()->UpdateTime(time); SceneMgr::getInstance()->UpdateScene(time); } void GameSchedule::onExit() { log("GameSchedule dispose!!!!1111"); } GameSchedule::~GameSchedule() { log("GameSchedule dispose!!!!222"); }
使用静态单例创建主循环对象,并使用Schedule 注册函数接口,作为引擎的主循环回调。
Director::getInstance()->getScheduler()->schedule(schedule_selector(GameSchedule::globalUpdate),this,0,false);
这里的GameSchedule::globalUpdate函数将是逻辑处理的开始,定时器刷新,场景处理等。
在进入主场景时开启入主循环,实现游戏的逻辑处理。
二、定时器GameDelayTime
定时器也就是定时回调,在有限时间内调用指定目标函数。这在一些游戏逻辑处理中很有用,包括一些动作处理(Cocos2dx中有延时动作和回调动作)。当然,有一个自己写的处理函数,我想是非常棒的~自己动手才能理解。
定时器的处理类GameDelayTime将会集中处理所有的定时器、更新定时器、删除定时器。当然GameDelayTime类将会出现在游戏主循环GameSchedule::globalUpdate函数中,使用游戏主循环控制整个游戏的所有动作表现,当游戏暂停时停止所有逻辑处理,等待再次恢复。定时器数据类DelayTimeDate是定时器的数据中心,记录定时器的延迟时间、延迟目标等。如果达到延迟时间将会调用目标函数,并退出自更新,等待处理类GameDelayTime删除。
游戏中的定时器是危险的,如果在场景中使用了定时器或在结点对象中使用定时器时,必须在退出场景或移除结点时删除所使用的定时器!
如:Node::onExit()时 删除定时器对象。这是至关重要的!如果结点已移除而没有删除定时器对象,那么定时器指针会一直存在于内存,指针成为野指针,到达延迟时间时被调用将会产生不可预料的麻烦。(我很想知道该怎样去判断一个函数指针指向的目标是否被释放……这样就可以避免野指针调用后崩溃,自己c++太菜……希望有人能告诉我)。
#ifndef __GameDelayTime__ #define __GameDelayTime__ #include "cocos2d.h" using namespace std; USING_NS_CC; class DelayTimeDate { public: static DelayTimeDate* create( float delayTime,std::function<void()> callback ); CC_SYNTHESIZE( float, delayTime, DelayTime ); CC_SYNTHESIZE( std::function<void()>, callback, Callback ); CC_SYNTHESIZE_READONLY( float, time, TotalTime ); bool update(float time); private: float _time; void init( float delayTime,std::function<void()> callback ){ _time = 0; setDelayTime(delayTime); setCallback(callback); } }; class GameDelayTime { public: static GameDelayTime* getInstance(); DelayTimeDate* addDelayTimeCallBack( float delayTime,std::function<void()> callback ); void removeDelayTimeCallBack( DelayTimeDate* delayTimeDate ); void UpdateTime(float time); private: vector<DelayTimeDate*> _keyMap; void init(); }; #endif
#include "GameDelayTime.h" static GameDelayTime* _instance = nullptr; GameDelayTime* GameDelayTime::getInstance() { if(!_instance) { _instance = new GameDelayTime(); _instance->init(); } return _instance; } void GameDelayTime::init() { } DelayTimeDate* GameDelayTime::addDelayTimeCallBack( float delayTime,std::function<void()> callback ) { auto delayTimeDate = DelayTimeDate::create(delayTime,callback); _keyMap.push_back(delayTimeDate); return delayTimeDate; } void GameDelayTime::removeDelayTimeCallBack( DelayTimeDate* delayTimeDate ) { int size = _keyMap.size(); while (size-->0) { if(delayTimeDate == _keyMap.at(size) ) { _keyMap.erase(_keyMap.begin()+size); CC_SAFE_DELETE(delayTimeDate); break; } } } void GameDelayTime::UpdateTime(float time) { int size = _keyMap.size(); while (size-->0) { auto delayTimeDate = _keyMap.at(size); if( delayTimeDate != nullptr ) { bool isCallBack = delayTimeDate->update(time); if( isCallBack ) { removeDelayTimeCallBack(delayTimeDate); } } } } DelayTimeDate* DelayTimeDate::create( float delayTime,std::function<void()> callback ) { DelayTimeDate* delayTimeDate = new DelayTimeDate(); delayTimeDate->init(delayTime,callback); return delayTimeDate; } bool DelayTimeDate::update(float time) { _time+=time; if( _time >= getDelayTime() ) { if( callback ) { callback(); return true; } } return false; }
三、结合
游戏主循环与定时器基本就这样了,我的实现比较简单。
简单出兵应用:
简单的控制主循环实现游戏的暂停逻辑处理。目前是比较简单的实现,希望后续能想到更好的idea。