~~~~我的生活,我的点点滴滴!!
基于cocos2dx 3.2版
cocos2d-x引擎中几个主要类做了简单的介绍:Director, Application, Node, Renderer, EventDispatcher, Scheduler等对于这些类简短的介绍,在心里有个大概。
virtual const char * getCurrentLanguage();
virtual Platform getTargetPlatform();
virtual void setAnimationInterval(double interval);
int run();//启动主循环
int Application::run()
{
...
while(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart;
director->mainLoop(); //Director进行这一帧的渲染
glview->pollEvents(); // This function processes only those events that have already been received and then returns immediately.
}
else
{
Sleep(0);
}
}
...
return true;
}
//openGL Matrix Operate在3.0里面没有,尼吗我用的是3.0蛋疼无比
void pushMatrix(MATRIX_STACK_TYPE type);
void popMatrix(MATRIX_STACK_TYPE type);
void loadIdentityMatrix(MATRIX_STACK_TYPE type);
void loadMatrix(MATRIX_STACK_TYPE type, const Mat4& mat);
void multiplyMatrix(MATRIX_STACK_TYPE type, const Mat4& mat);
Mat4 getMatrix(MATRIX_STACK_TYPE type);
void resetMatrixStack();
//View Data
inline double getAnimationInterval();
inline bool isDisplayStats();
inline GLView* getOpenGLView();
inline Projection getProjection();
Size getVisibleSize() const;
Vec2 getVisibleOrigin() const;
Vec2 convertToGL(const Vec2& point);
Vec2 convertToUI(const Vec2& point);
float getZEye() const;
// Scene 场景管理
inline Scene* getRunningScene();
void runWithScene(Scene *scene);
void pushScene(Scene *scene);
// 控制绘制的暂停和恢复
void end();
void pause();
void resume();
//绘制图形(界面展示最重要的函数)
void drawScene();
//Getter and Setter
Scheduler* getScheduler() const { return _scheduler; }
void setScheduler(Scheduler* scheduler);
ActionManager* getActionManager() const { return _actionManager; }
void setActionManager(ActionManager* actionManager);
EventDispatcher* getEventDispatcher() const { return _eventDispatcher; }
void setEventDispatcher(EventDispatcher* dispatcher);
Renderer* getRenderer() const { return _renderer; }
// Draw the Scene
void Director::drawScene()
{
...
if (! _paused)
{
_scheduler->update(_deltaTime); //Scheduler 定时器 更新
_eventDispatcher->dispatchEvent(_eventAfterUpdate); //Dispatcher 抛发事件.
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glClear
if (_nextScene) //取得下一个将要显示的Scene.
{
setNextScene();
}
pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //将上一次绘制的Context放到堆栈
// draw the scene
if (_runningScene)
{
_runningScene->visit(_renderer, Mat4::IDENTITY, false);
_eventDispatcher->dispatchEvent(_eventAfterVisit);
}
_renderer->render(); //渲染
_eventDispatcher->dispatchEvent(_eventAfterDraw);
popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //返回到上一次绘制时的状态.
// swap buffers
if (_openGLView)
{
_openGLView->swapBuffers(); //把上面渲染的结果显示到屏幕
}
...
}
visit()的主要功能就是:
1、调用所有孩子的visit函数
2、调用self->draw()函数
void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if (!_visible)
{
return;
}
uint32_t flags = processParentFlags(parentTransform, parentFlags);
// IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
int i = 0;
if(!_children.empty())
{
sortAllChildren();
// draw children zOrder < 0
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i);
if ( node && node->_localZOrder < 0 )
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
// self draw
this->draw(renderer, _modelViewTransform, flags);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else
{
this->draw(renderer, _modelViewTransform, flags);
}
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
因为Node是所有可显示对象的父类, 没有任何显示内容, 所以draw函数为空。
这里我们以Sprite::draw函数为例简单介绍下draw的作用:
void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
if(_insideBounds)
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform);
renderer->addCommand(&_quadCommand);
}
}
再看看Label的绘制函数:
void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
if(_insideBounds) {
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, flags);
renderer->addCommand(&_customCommand);
}
}
其实, 跟Sprite::draw也差不多. 关键在于这个RenderCommand怎么构造和执行的。
void initGLView();
/** Adds a `RenderComamnd` into the renderer */
void addCommand(RenderCommand* command);
/** Adds a `RenderComamnd` into the renderer specifying a particular render queue ID */
void addCommand(RenderCommand* command, int renderQueue);
/** Pushes a group into the render queue */
void pushGroup(int renderQueueID);
/** Pops a group from the render queue */
void popGroup();
/** Creates a render queue and returns its Id */
int createRenderQueue();
/** Renders into the GLView all the queued `RenderCommand` objects */
void render();
1、对ReanderCommand进行排序和分类管理。
2、进行渲染:render()
渲染函数Renderer::render()
void Renderer::render()
{
...
if (_glViewAssigned)
{
...
//排列渲染队列
for (auto &renderqueue : _renderGroups)
{
renderqueue.sort();
}
//进行渲染
visitRenderQueue(_renderGroups[0]);
...
}
...
}
Schelduler是cocos2d-x中实现延迟调用,定时调用时最重要的功能. 类似于其他语言中的Timer 他最核心的函数就是:
void schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key);
比如在析构的时候调用void unschedule(void *target)即可移除当前对象的所有定时操作。Schelduler的其它大部分方法, 要么
是它的衍生, 为了减少调用参数; 要么是对定时操作的控制, 比如暂停, 恢复, 移除等。
1、EventDispatcher: 事件分发器, 相当于所有事件的中控中心. 管理着EventListener,当一个Event到来的时候决定CallBack的调用顺序。
2、Event ( EventTouch, EventKeyboard 等), 具体的事件数据等。
3、EventListener ( EventListenerTouch, EventListenerKeyboard 等 ): 建立了Event到CallBack的映射关系, EventDispatcher 根据这种映射关系调用对应的 CallBack。
enum class Type
{
TOUCH,
KEYBOARD,
ACCELERATION,
MOUSE,
FOCUS,
CUSTOM
};
enum class Type
{
UNKNOWN,
TOUCH_ONE_BY_ONE,
TOUCH_ALL_AT_ONCE,
KEYBOARD,
MOUSE,
ACCELERATION,
FOCUS,
CUSTOM
};
处理单点触摸事件和多点触摸事件。多说几句: 假如一个TouchEvent事件中有多个触摸点, 那么类型为EventListener::Type::TOUCH_ONE_BY_ONE的EventListener会把
这个事件分解成若干个单点触摸事件来处理。而类型为EventListener::Type::TOUCH_ALL_AT_ONCE 的 EventListener 就是来处理多点触摸的, 会一次处理它,其它几
种类型都是一一对应的, 即一种Event::Type的Event会被对应类型的EventListener接受。
std::unordered_map _listenerMap;
1、EventListener::ListenerID : 每一种EventListener::Type有唯一的 EventListener::ListenerID. 其实通过这段代码typedef std::string ListenerID; 可
知: EventListener::ListenerID 就是简单 string, 就是一个名称而已。
2、EventListenerVector: 顾名思义, 就是一个 EventListener 的向量容器. 相对于普通的向量容器, 它增加了priority管理功能。
EventListener 处理之后, 会停止遍历其它的 EventListener。反映到实战中就是: 你监听了某种事件, 这种事件也出发了, 但是对应的回调函数并没有被调用, 也就是
被优先级更高的 EventListener 截获了。
如果 fixedPriority 一样呢? 按照什么顺序?
1、fixedPriority 为0, 这个值是专门为 Scene Object 预留的。即默认情况下, 绝大多数继承自 Node 的对象添加的普通事件监听器,其 fixedPriority 都为0。此
时, Node 的 globalZOrder 决定了优先级, 值越大, 越先被遍历到, 即在显示层中层级越高, 越先接受事件,这在ui响应逻辑中也是合理的。
2、fixedPriority 不为0, 那就按添加顺序。
可以用 EventListenerTouchOneByOne::setSwallowTouches(bool needSwallow) 来改变它。
2、对于其它类型的 EventLIstener, 只有在显示调用了 Event::stopPropagation() 的时候, 才会中断遍历。
void EventDispatcher::dispatchEvent(Event* event);
当有响应的事件到来的时候, 都会调用这个函数来通知监听了此事件的对象。
其实上面的介绍, 已经把这个函数里绝大部分逻辑都描述了,这里做一个最后的总结。
事件抛发的简要流程如下:
1、检查 _listenerMap 中所有的 EventListnerVector, 如果哪个容器的 EventListener 优先级顺序需要更新, 则重新排序。
2、对于类型为 Event::Type::TOUCH 的事件, 则按照 EventListener 的遍历顺序遍历所有的 EventListener。只有接受了 EventTouch::EventCode::BEGAN 事件的 EventListener,
才会收到其他类型的 EventTouch 事件。
3、对于其他类型的事件, 也按照EventListener的遍历顺序的顺序遍历对应的EventListener。
总的来说, Eventdispatcher 是一个中转器:
1、事件的产生模块儿, 只关心自己构造正确的 Event, 调用 EventDispatcher::dispatchEvent(Event* event) 交给 EventDispatcher。
2、需要监听事件的模块儿, 只需调用 EventDispatcher::addEventListener(EventListener* listener) (或者它的其它变种)来注册自己作为监听者。
3、EventDispatcher 的作用是:
3.1、把特定类型的 Event 送给对应类型的 EventListener。
3.2、对于同一种 Event, 规定了事件送达的优先级。