~~~~我的生活,我的点点滴滴!!
基于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<EventListener::ListenerID, EventListenerVector*> _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, 规定了事件送达的优先级。