Cocos2d-x 3.2中重要类的总结

来源:互联网 发布:淘宝个人闲置 编辑:程序博客网 时间:2024/05/12 22:48

本文转自:http://blog.csdn.net/ac_huang/article/details/39204317

本文基于Cocos2d-x3.2版本引擎。Cocos2d-x引擎中几个主要类做了简单的介绍:Director,Application,Node,Renderer,EventDispatcher,Scheduler等对于这些类简短的介绍,在心里有个大概。


1、Application

主要方法:

1
2
3
4
virtual const char * getCurrentLanguage();
virtual Platform getTargetPlatform();
virtual void setAnimationInterval(double interval);
int run();//启动主循环

run()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
}


2、Director

主要函数预览:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//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; }

drawScene():主要绘制函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 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();                             //把上面渲染的结果显示到屏幕
    }
 
 
    ...
}


3、Node

visit()的主要功能就是:

1)调用所有孩子的visit函数

2)调用self->draw()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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);
}


draw()函数:

因为Node是所有可显示对象的父类,没有任何显示内容,所以draw函数为空。这里我们以Sprite::draw函数为例简单介绍下draw的作用:

1
2
3
4
5
6
7
8
9
10
11
12
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);
    }
}


我们看到,Sprite::draw函数主要实现了[添加一个QuadCommand到Render中去]的功能。

再看看Label的绘制函数:

1
2
3
4
5
6
7
8
9
10
11
12
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怎么构造和执行的。


4、Renderer渲染器

主要函数预览:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Renderer::render()
{
   ...
    if (_glViewAssigned)
    {
       ...
        //排列渲染队列
        for (auto &renderqueue : _renderGroups)
        {
            renderqueue.sort();
        
        //进行渲染
        visitRenderQueue(_renderGroups[0]);
        ...
    }
    ...
}


5、Schelduler

Schelduler是Cocos2d-x中实现延迟调用,定时调用时最重要的功能。类似于其他语言中的Timer他最核心的函数就是:

1
void schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key);

用来启动一个定时操作:在延迟delay时间后,每隔repeat时间,调用一次callback.target用来标记这个操作属于谁,方便管理,比如在析构的时候调用voidunschedule(void*target)即可移除当前对象的所有定时操作。Schelduler的其它大部分方法,要么是它的衍生,为了减少调用参数;要么是对定时操作的控制,比如暂停、恢复、移除等。


6、EventDispatcher

EventDispatcher,EventListener,Event之间的关系如下:

1)EventDispatcher:事件分发器,相当于所有事件的中控中心。管理着EventListener,当一个Event到来的时候决定CallBack的调用顺序。

2)Event(EventTouch,EventKeyboard等),具体的事件数据等。

3)EventListener(EventListenerTouch,EventListenerKeyboard等):建立了Event到CallBack的映射关系,EventDispatcher根据这种映射关系调用对应的CallBack。


6.1 Event

Event有以下几种类型:

1
2
3
4
5
6
7
8
9
    enum class Type
    {
        TOUCH,
        KEYBOARD,
        ACCELERATION,
        MOUSE,
        FOCUS,
        CUSTOM
    };

Event最重要的属性就是type,标识了它是那种类型的事件,也决定了由哪个EventListner来处理它。


6.2 EventListener

EventListner有以下几种类型:

1
2
3
4
5
6
7
8
9
10
11
enum class Type
{
    UNKNOWN,
    TOUCH_ONE_BY_ONE,
    TOUCH_ALL_AT_ONCE,
    KEYBOARD,
    MOUSE,
    ACCELERATION,
    FOCUS,
    CUSTOM
};

除了UNKNOWN,跟Event::Type相比,Event::Type::TOUCH会同时被两种类型的EventListener处理:TOUCH_ONE_BY_ONE和TOUCH_ALL_AT_ONCE。这两种EventListener分别处理单点触摸事件和多点触摸事件。多说几句:假如一个TouchEvent事件中有多个触摸点,那么类型为EventListener::Type::TOUCH_ONE_BY_ONE的EventListener会把这个事件分解成若干个单点触摸事件来处理。而类型为EventListener::Type::TOUCH_ALL_AT_ONCE的EventListener就是来处理多点触摸的,会一次处理它,其它几种类型都是一一对应的,即一种Event::Type的Event会被对应类型的EventListener接受。


6.3 存放EventListener的地方

在EventDispatcher中,它把以上7种EventListener::Type类型的EventListner放到7个队列中.也就是在这样一个字段中:

1
std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;

1)EventListener::ListenerID:每一种EventListener::Type有唯一的EventListener::ListenerID.其实通过这段代码typedefstd::stringListenerID;可知:EventListener::ListenerID就是简单string,就是一个名称而已。

2)EventListenerVector:顾名思义,就是一个EventListener的向量容器.相对于普通的向量容器,它增加了priority管理功能。


6.4 EventListener的fixedPriority

简单来说,每个EventListener有自己的fixedPriority属性,它是一个整数。


6.5 EventListener的遍历顺序

EventDispatcher在抛发事件的时候,会先处理Event的时候,会优先遍历fixedPriority低的EventListener,调用它的CallBack在某些条件下一个Event被一个EventListener处理之后,会停止遍历其它的EventListener。反映到实战中就是:你监听了某种事件,这种事件也出发了,但是对应的回调函数并没有被调用,也就是被优先级更高的EventListener截获了。


如果fixedPriority一样呢?按照什么顺序?

1、fixedPriority为0,这个值是专门为SceneObject预留的。即默认情况下,绝大多数继承自Node的对象添加的普通事件监听器,其fixedPriority都为0。此时,Node的globalZOrder决定了优先级,值越大,越先被遍历到,即在显示层中层级越高,越先接受事件,这在ui响应逻辑中也是合理的。

2、fixedPriority不为0,那就按添加顺序。


6.6 Event在什么条件下会被优先级更高的EventListener截获?

1)对于EventListenerTouchOneByOne,它有一个字段:_needSwallow,当它为true的时候,如果它接受了某个Event,优先级更低的EventListener就接受不到了。可以用EventListenerTouchOneByOne::setSwallowTouches(boolneedSwallow)来改变它。

2)对于其它类型的EventLIstener,只有在显示调用了Event::stopPropagation()的时候,才会中断遍历。


6.7 EventDispatcher::dispatchEvent()

下面我们看看EventDispatcher最核心的函数:

1
voidEventDispatcher::dispatchEvent(Event*event);

当有响应的事件到来的时候,都会调用这个函数来通知监听了此事件的对象。其实上面的介绍,已经把这个函数里绝大部分逻辑都描述了,这里做一个最后的总结。


事件抛发的简要流程如下:

1)检查_listenerMap中所有的EventListnerVector,如果哪个容器的EventListener优先级顺序需要更新,则重新排序。

2)对于类型为Event::Type::TOUCH的事件,则按照EventListener的遍历顺序遍历所有的EventListener。只有接受了EventTouch::EventCode::BEGAN事件的EventListener,才会收到其他类型的EventTouch事件。

3)对于其他类型的事件,也按照EventListener的遍历顺序的顺序遍历对应的EventListener。


6.8 总结

Eventdispatcher中的其它函数,主要功能都是添加EventListener,删除EventListener等,不做详细介绍。


总的来说,Eventdispatcher是一个中转器:

1)事件的产生模块儿,只关心自己构造正确的Event,调用EventDispatcher::dispatchEvent(Event*event)交给EventDispatcher。

2)需要监听事件的模块儿,只需调用EventDispatcher::addEventListener(EventListener*listener)(或者它的其它变种)来注册自己作为监听者。

3)EventDispatcher的作用是:

  • 把特定类型的Event送给对应类型的EventListener。

  • 对于同一种Event,规定了事件送达的优先级。


0 0