Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器

     保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈。

 
一、游戏主循环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");
}
GameSchedule.cpp
 
使用静态单例创建主循环对象,并使用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;
}
GameDelayTime.cpp
 
三、结合
     游戏主循环与定时器基本就这样了,我的实现比较简单。
 
简单出兵应用:
 
 
  简单的控制主循环实现游戏的暂停逻辑处理。目前是比较简单的实现,希望后续能想到更好的idea。
原文地址:https://www.cnblogs.com/Richard-Core/p/4234152.html