使用场景、层和精灵这些元素,可以构建游戏框架,要让游戏动起来需要借助定时器。cocos2d-x提供的方式有两种:update和schedule。
- update定时器
- schedule定时器
与定时器相关的方法有:
- 启动定时器方法
/**
* Schedules the "update" method.
*
* It will use the order number 0. This method will be called every frame.
* Scheduled methods with a lower order value will be called before the ones that have a higher order value.
* Only one "update" method could be scheduled per node.
* @js NA
* @lua NA
*/
void scheduleUpdate(void);
/**
* Schedules a custom selector.
*
* If the selector is already scheduled, then the interval parameter will be updated without scheduling it again.
@code
// firstly, implement a schedule function
void MyNode::TickMe(float dt);
// wrap this function into a selector via schedule_selector marco.
this->schedule(schedule_selector(MyNode::TickMe), 0, 0, 0);
@endcode
*
* @param selector The SEL_SCHEDULE selector to be scheduled.
* @param interval Tick interval in seconds. 0 means tick every frame. If interval = 0, it's recommended to use scheduleUpdate() instead.
* @param repeat The selector will be excuted (repeat + 1) times, you can use kRepeatForever for tick infinitely.
* @param delay The amount of time that the first tick will wait before execution.
* @lua NA
*/
void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
/**
* Schedules a custom selector with an interval time in seconds.
* @see `schedule(SEL_SCHEDULE, float, unsigned int, float)`
*
* @param selector The SEL_SCHEDULE selector to be scheduled.
* @param interval Callback interval time in seconds. 0 means tick every frame,
* @lua NA
*/
void schedule(SEL_SCHEDULE selector, float interval);
/**
* Schedules a custom selector, the scheduled selector will be ticked every frame
* @see schedule(SEL_SCHEDULE, float, unsigned int, float)
*
* @param selector A function wrapped as a selector
* @lua NA
*/
void schedule(SEL_SCHEDULE selector);
- 有变化的启动定时器
/**
* Schedules the "update" method with a custom priority.
*
* This selector will be called every frame.
* Scheduled methods with a lower priority will be called before the ones that have a higher value.
* Only one "update" selector could be scheduled per node (You can't have 2 'update' selectors).
* @js NA
* @lua NA
*/
void scheduleUpdateWithPriority(int priority);
/**
* Schedules a selector that runs only once, with a delay of 0 or larger
* @see `schedule(SEL_SCHEDULE, float, unsigned int, float)`
*
* @param selector The SEL_SCHEDULE selector to be scheduled.
* @param delay The amount of time that the first tick will wait before execution.
* @lua NA
*/
void scheduleOnce(SEL_SCHEDULE selector, float delay);
- 取消定时器
/*
* Unschedules the "update" method.
* @see scheduleUpdate();
*/
void unscheduleUpdate(void);
/**
* Unschedules a custom selector.
* @see `schedule(SEL_SCHEDULE, float, unsigned int, float)`
*
* @param selector A function wrapped as a selector
* @lua NA
*/
void unschedule(SEL_SCHEDULE selector);
/**
* Unschedule all scheduled selectors: custom selectors, and the 'update' selector.
* Actions are not affected by this method.
* @lua NA
*/
void unscheduleAllSelectors(void);
- 和暂停重启相关的
/**
* Resumes all scheduled selectors, actions and event listeners.
* This method is called internally by onEnter
*/
void resume(void);
/**
* Pauses all scheduled selectors, actions and event listeners..
* This method is called internally by onExit
*/
void pause(void);
/**
* Resumes all scheduled selectors, actions and event listeners.
* This method is called internally by onEnter
*/
CC_DEPRECATED_ATTRIBUTE void resumeSchedulerAndActions(void);
/**
* Pauses all scheduled selectors, actions and event listeners..
* This method is called internally by onExit
*/
CC_DEPRECATED_ATTRIBUTE void pauseSchedulerAndActions(void);
- update方法
/*
* Update method will be called automatically every frame if "scheduleUpdate" is called, and the node is "live"
*/
virtual void update(float delta);
游戏主循环会反复执行三个动作:输入响应、定时事件、绘图。此循环方法则是Director::mainLoop()。此方法每帧调用一次,帧间间隔由帧率决定。mainLoop()方法的实现在DisplayLinkDirector::mainLoop()。
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)//清除Director
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::sharedPoolManager()->pop();
}
}
mainLoop把所有要处理的操作都交给drawScene()方法。
// Draw the Scene
void Director::drawScene()
{
// calculate "global" dt
calculateDeltaTime();
if (_openGLView)
{
_openGLView->pollInputEvents();//轮询输入事件
}
//tick before glClear: issue #533
if (! _paused)
{
_scheduler->update(_deltaTime);
_eventDispatcher->dispatchEvent(_eventAfterUpdate);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* to avoid flickr, nextScene MUST be here: after tick and before draw.
XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
if (_nextScene)
{
setNextScene();
}
kmGLPushMatrix();
//construct the frustum
{
kmMat4 view;
kmMat4 projection;
kmGLGetMatrix(KM_GL_PROJECTION, &projection);
kmGLGetMatrix(KM_GL_MODELVIEW, &view);
_cullingFrustum->setupFromMatrix(view, projection);
}
// draw the scene
if (_runningScene)
{
_runningScene->visit();
_eventDispatcher->dispatchEvent(_eventAfterVisit);
}
// draw the notifications node
if (_notificationNode)
{
_notificationNode->visit();//处理通知节点
}
if (_displayStats)
{
showStats();
}
_renderer->render();
_eventDispatcher->dispatchEvent(_eventAfterDraw);
kmGLPopMatrix();
_totalFrames++;
// swap buffers
if (_openGLView)
{
_openGLView->swapBuffers();
}
if (_displayStats)
{
calculateMPF();
}
}
在drawScene中主要进行了3个操作:1、调用定时调度器的update方法,引发定时器事件;2、如果需要则切换场景;3、事件分发;4、绘制当前场景。
定时调度器的update方法会先按照优先级由低到高的顺序处理节点的update定时器。然后处理所有普通定时器。再处理脚本引擎相关的事件。最后按优先级由低到高清理被标记了删除记号的节点update方法。
所以,实际上它们都是串行操作,并不是多线程并发。