1. 程式人生 > >4.幀迴圈(遊戲主迴圈),schedule

4.幀迴圈(遊戲主迴圈),schedule



1 概述

遊戲乃至圖形介面的本質是不斷地繪圖,然而繪圖並不是隨意的,任何遊戲都需要遵循一定的規則來呈現出來,這些規則就體現為遊戲邏輯。遊戲邏輯會控制遊戲內容,使其根據使用者輸入和時間流逝而改變。因此,遊戲可以抽象為不斷地重複。

2 以下動作:

A 處理使用者輸入

B 處理定時事件

C 繪圖

遊戲主迴圈就是這樣的一個迴圈,它會反覆執行以上動作,保持遊戲進行下去,直到玩家退出遊戲。

CCDirector::mainLoop()方法,這個方法負責調動定時器,繪圖,傳送全域性通知,並處理記憶體回收池。該方法按幀呼叫,每幀呼叫一次,而幀間間隔取決於兩個因素,一個是預設的幀率,預設為60幀每秒:另一個是每幀的計算大小。當邏輯處理與繪圖計算過大時,裝置無法完成每秒

60次繪製,此時幀率就會降低。

3 實現

mainLoop()方法是定義在CCDirector中的抽象方法,它的實現位於同一個檔案中的CCDisplayLinkDirector類。程式碼如下:

上述程式碼主要包含如下3個步驟。

判斷是否需要釋放CCDirector,如果需要,則刪除CCDirector佔用的資源,通常,遊戲結束時才會執行這個步驟。

呼叫drawScene()發方法,繪製當前場景並進行其他必要的處理。

彈出自動回收池,使得這一幀被放入自動回收池的物件全部釋放。

在主迴圈中drawScene(),主要進行3個操作:

呼叫了定時排程器的update方法,引發定時器事件。

如果場景需要被切換,則呼叫setNextStage方法,在顯示場景前切換場景。

呼叫當前場景的visit方法,繪製當前場景。

4 定時器

Schedule.h

#ifndef__Schedule_H__

#define__Schedule_H__

#include"cocos2d.h"

USING_NS_CC;

classSchedule :publicCCLayer {

public:

staticCCScene * scene();

CREATE_FUNC(Schedule);

boolinit();

voidupdate(float

) override;

voidmySchedule(floatdt);

};

#endif

Schedule.cpp

#include"Schedule.h"

#include"AppMacros.h"

CCScene *Schedule::scene()

{

CCScene * scene = CCScene::create();

Schedule * layer = Schedule::create();

scene->addChild(layer);

returnscene;

}

boolSchedule::init()

{

CCLayer::init();

//scheduleUpdate();

//unscheduleUpdate();

//scheduleOnce(schedule_selector(Schedule::mySchedule), 2);

schedule(schedule_selector(Schedule::mySchedule));

//功能等同scheduleUpdate();回撥函式可以自定義

//schedule(schedule_selector(Schedule::mySchedule), 3);

//CCNode::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);

//schedule(schedule_selector(Schedule::mySchedule),1,10,4);

//4s以後,每隔1s執行一次回撥,共執行10

CCSprite * spr = CCSprite::create("p_2_01.png");

spr->setPosition(ccp(100,winSize.height / 2));

addChild(spr);

spr->setTag(100);

//CCMoveBy * by = CCMoveBy::create(2, ccp(300, 0));

//CCMoveBy * by1 = (CCMoveBy *)by->reverse();

//CCSequence *seq = CCSequence::create(by, by1, NULL);

//spr->runAction(CCRepeatForever::create(seq));

returntrue;

}

voidSchedule::update(floatdt)

{

CCLOG("dt = %g",dt);

staticinti = 0;

i++;

if (i == 120)

{

//結束定時器

unscheduleUpdate();

CCLog("schedule is over");

}

}

voidSchedule::mySchedule(floatdt) {

CCSprite * spr = (CCSprite *)getChildByTag(100);

floatv = 300 / 2;

staticintcount = 0;

count++;

staticboolflag = true;

if (flag)

{

if ((spr->getPositionX() + v*dt) < 400)

{

spr->setPositionX(spr->getPositionX() + v*dt);

}

else

{

flag = !flag;

}

}

if (!flag)

{

if ((spr->getPositionX() - v*dt) > 100)

{

spr->setPositionX(spr->getPositionX() - v*dt);

}

else

{

flag = !flag;

}

}

if (count == 1000)

{

unschedule(schedule_selector(Schedule::mySchedule));

}

}

執行結果:

5 定時器Schedule

A 幀迴圈定時器

scheduleUpdate();//幀迴圈定時器,每一幀都會被調動,對實時性要求非常高的,比如碰撞檢測

void update(float delta);

unscheduleUpdate();//關閉定時器

B 一次性定時器

引數解析:

scheduleOnce(SEL_SCHEDULE selector, float delay)

//第一個引數表示要回調的函式,第二個引數表示延時

typedef void (CCObject::*SEL_SCHEDULE)(float);

#define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR);

scheduleOnce (schedule_selector(Schedule::updateOnce),2);

void updateOnce(float delta);

C 自定義定時器

自定義定時器有3個過載函式,底層都預設呼叫了scheduleSelector,它的幾個引數分別表示,scheduleSelector回撥函式,interval時間間隔,repeat重複次數,delay延時執行。

void CCNode::schedule(SEL_SCHEDULE selector) {

this->schedule(selector, 0.0f, kCCRepeatForever, 0.0f);

}

/本質同scheduleUpdate 但是可以自己寫回調函式

void CCNode::schedule(SEL_SCHEDULE selector, float interval) {

this->schedule(selector, interval, kCCRepeatForever, 0.0f);

}

void CCNode::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay){

m_pScheduler->scheduleSelector(selector, this, interval , repeat,delay, !m_bRunning);

}

D 定時器停止

void CCNode::unschedule(SEL_SCHEDULE selector);

void CCNode::unscheduleAllSelectors();

注意:多個定時器,可並存,可彼此開始與停止。