Node

Sprite

Layer

类对比图

流程图


*背景代表未搞懂的部分

代码栏中的红色函数则是未弄懂的函数

  • 继承:ref


    成员函数:


    void Node::setLocalZOrder(int z)
    {
        //如果 z!=_localZOrder 则_parent->reorderChild(this, z)
        ...
        _eventDispatcher->setDirtyForNode(this);
    }

    _localZOrder_globalZOrder_orderOfArrival

    cocos渲染顺序是依据这三个成员变量的值的大小来进行渲染:

    _globalZOrder:  优先级最高,值越低越先渲染。

    _localZOrder  :  是用来和同级节点(siblings兄弟姐妹)进行渲染顺序区分,同样是越小越先渲染

    _orderOfArrial:  是用来在同级节点且_localZOrder相同的情况下,越小的越先渲染。
                               这个值来自Node中的静态变量s_globalOrderOfArrival,每用一次自加1。

    若三个值都相同的情况下(基本不太可能吧),绘制的顺序是不能预测的(在一个博客上看到的)。



    //addChild会调用
    void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
    {
        if (_children.empty())
        {
            //把_children(Vector)容量设为4
            this->childrenAlloc();
        }
        
        //pushback到_children中(自动retain)
        this->insertChild(child, localZOrder);
        
        if (setTag)
            child->setTag(tag);
        else
            child->setName(name);
        
        child->setParent(this);
        child->setOrderOfArrival(s_globalOrderOfArrival++);
        
        //如果此时的_parent在运行状态则加入的child也会onEnter
        //如果该_parent过度完成,则在onEnter完成之后也会调用finish
        if( _running )
        {
            child->onEnter();
            // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
            if (_isTransitionFinished)
            {
                //应是:调用了cocos的transition
                child->onEnterTransitionDidFinish();
            }
        }
        
        //如果允许颜色或者透明度传递,则按照父节点的透明度百分比进行调整
        //此刻 数值 * 父数值 / 225
        if (_cascadeColorEnabled)
        {
            updateCascadeColor();
        }
        
        if (_cascadeOpacityEnabled)
        {
            updateCascadeOpacity();
        }
    }


    //删除了script-binding和component(作用未知).  
    //onExit和onEnter与此同理
    void Node::onEnter()
    {
        //如果用户设置了回调,则在onEnter的时候会进行回调
        if (_onEnterCallback)
            _onEnterCallback();
        //这时候还没有进行Entertransition
        _isTransitionFinished = false;
        for( const auto &child: _children)
            child->onEnter();
        //计时器开启、动作开启、时间监听开启
        //默认的的_scheduler、_actionManager、_eventDispatcher都是来自Director
        this->resume();
        _running = true;
    }

    onEnteronExit

    onEnter和onExit应是标志着改节点是否在此刻运行的舞台上,即_parent中_running参数是true或false。
    onEnter:    _running参数被设置为true,_scheduler, _actionManager, _eventDispatcher都继续工作。
    onExit  :     反之。是暂停工作。


    virtual ActionManager* getActionManager() { return _actionManager; }
    virtual const ActionManager* getActionManager() const { return _actionManager; }

    c++多态
    牵扯到的是c++多态问题 virtual 中的const(尾部修饰的const)可以看作为一个参数。
    即,若子类若想重写(override),也需要添加const,否则视为覆盖(hide)
    尾部修饰符的const的意思:类成员变量不可改变


    有关节点的变换(visible, position, skewX...)的一类函数
    会与 _transformUpdated、_transformDirty、_inverseDirty这几个变量相关


    //基本的正则匹配  并不会使用“/..”
    virtual void enumerateChildren(const std::string &name, std::function<bool(Node* node)> callback) const;
    bool doEnumerate(std::string name, std::function<bool (Node *)> callback) const;
    bool doEnumerateRecursive(const Node* node, const std::string &name, std::function<bool (Node *)> callback) const;


    //感觉这个函数应该属于内部函数,函数内部只是_parent指针指向了该node
    //即父类容器并没有添加该子类,前父类也并没有移除掉该node,通过改节点进行的一系列与父类相关的操作 //都是无用的
    virtual void setParent(Node* parent);


    Rect Node::getBoundingBox() const
    {
        Rect rect(0, 0, _contentSize.width, _contentSize.height);
        //进行仿射变换  即对rect进行 缩放和平移
        return RectApplyAffineTransform(rect, getNodeToParentAffineTransform());
    }




    //判断其父类是否存在该子类,存在则调用detachChild virtual void removeFromParentAndCleanup(bool cleanup);

    void Node::detachChild(Node *child, ssize_t childIndex, bool doCleanup)
    {
        // IMPORTANT:
        //  -1st do onExit
        //  -2nd cleanup
        if (_running)
        {
            child->onExitTransitionDidStart();
            child->onExit();
        }
        // If you don't do cleanup, the child's actions will not get removed and the
        // its scheduledSelectors_ dict will not get released!
        if (doCleanup)
        {
            //暂停所有子类动作管理器和计时器
            child->cleanup();
        }
        // set parent nil at the end
        child->setParent(nullptr);
        //如果存在则release
        _children.erase(childIndex);
    }


    void Node::reorderChild(Node *child, int zOrder)
    {
        CCASSERT( child != nullptr, "Child must be non-nil");
        _reorderChildDirty = true;
        //避免相同_orderOfArrival
        child->setOrderOfArrival(s_globalOrderOfArrival++);
        child->_localZOrder = zOrder;
    }


    void Node::sortAllChildren()
    {
        //addChild(insertChild)和reorderChild 都会使得_reorderChildDirty
        if (_reorderChildDirty)
        {
            //localZOder越小越在前面
            std::sort(std::begin(_children), std::end(_children), nodeComparisonLess);
            _reorderChildDirty = false;
        }
    }


    //这个方法挺好用的

    //getChildByTag<Sprite*>(1);将child直接转成需要的类型

    template <typename T>

    inline T getChildByName(const std::string& name) const { return static_cast<T>(getChildByName(name)); }


    _actionManager去看ActionManager类.

    _scheduler去看Scheduler类.


    //有关openGL的东西

    //先visit再draw

    virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags);

    virtual void visit() final;


    virtual void draw(Renderer *renderer, const Mat4& transform, uint32_t flags);

    void Node::draw()

    {

        //获得渲染器

        auto renderer = _director->getRenderer();


        draw(renderer, _modelViewTransform, true);

    }


    virtual void setNormalizedPosition(const Vec2 &position);

    virtual void setGLProgram(GLProgram *glprogram);

    virtual void setGLProgramState(GLProgramState *glProgramState);


    virtual void updateTransform();

    virtual const Mat4& getNodeToParentTransform() const;

    virtual AffineTransform getNodeToParentAffineTransform() const;

    virtual void setNodeToParentTransform(const Mat4& transform);

    virtual const Mat4& getParentToNodeTransform() const;

    virtual AffineTransform getParentToNodeAffineTransform() const;

    virtual Mat4 getNodeToWorldTransform() const;

    virtual AffineTransform getNodeToWorldAffineTransform() const;

    virtual Mat4 getWorldToNodeTransform() const;

    virtual AffineTransform getWorldToNodeAffineTransform() const;


    返回值为Mat4的应是用于node和world坐标系的转化.


    void setAdditionalTransform(Mat4* additionalTransform);

    void setAdditionalTransform(const AffineTransform& additionalTransform);


    关于component


    物理引擎类先略过


    _displayedOpacity  最终显示的不透明度(自身的透明度 * parent的最终不透明度)

    _realOpacity          自身的透明度

    void Node::updateDisplayedOpacity(GLubyte parentOpacity)

    {

        //根据父类的透明度比例得出

        _displayedOpacity = _realOpacity * parentOpacity/255.0;

        updateColor();

        

        if (_cascadeOpacityEnabled)

        {

            for(const auto& child : _children)

            {

                //并传递到child

                child->updateDisplayedOpacity(_displayedOpacity);

            }

        }

    }


    virtual void setOpacityModifyRGB(bool value) {CC_UNUSED_PARAM(value);}

    virtual bool isOpacityModifyRGB() const { return false; };


    unsigned short getCameraMask() const { return _cameraMask; }

    virtual void setCameraMask(unsigned short mask, bool applyChildren = true);


    /// Convert cocos2d coordinates to UI windows coordinate.

    Vec2 convertToWindowSpace(const Vec2& nodePoint) const;


    Mat4 transform(const Mat4 &parentTransform);

    uint32_t processParentFlags(const Mat4& parentTransform, uint32_t parentFlags);


    //check whether this camera mask is visible by the current visiting camera

    bool isVisitableByVisitingCamera() const;


    // update quaternion from Rotation3D

    void updateRotationQuat();

    // update Rotation3D from quaternion

    void updateRotation3D();



    漏了一个类在node下方









  • Sprite

    继承:Node TextureProtocol


    构造函数:

    CC_SPRITE_DEBUG_DRAW    //宏


    sprite的create()函数和init()函数

    最终会调用到

    bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated)

    {

        bool result;

        if (Node::init())

        {

            _batchNode = nullptr;

            //是否所有精灵的孩子需要更新

            _recursiveDirty = false;

            //_dirty = false, 是否这个精灵需要更新

            setDirty(false);


            // opacity and RGB protocol

            _opacityModifyRGB = true;


            //BlendFunc::ALPHA_PREMULTIPLIED = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA};

            //源文件所有都取,目标文件只取源文件中1-alpha值的

            _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;

            

            _flippedX = _flippedY = false;

            

            // default transform anchor: center

            setAnchorPoint(Vec2(0.5f, 0.5f));

            

            //偏移位置设置为0,偏移位置还未搞懂

            _offsetPosition.setZero();


            // clean the Quad,如前所说是清理quad

            memset(&_quad, 0, sizeof(_quad));

            

            // Atlas: Color  颜色集

            _quad.bl.colors = Color4B::WHITE;

            _quad.br.colors = Color4B::WHITE;

            _quad.tl.colors = Color4B::WHITE;

            _quad.tr.colors = Color4B::WHITE;

            

            // shader state

            setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));


            // update texture (calls updateBlendFunc)  转下方函数

            setTexture(texture);

            setTextureRect(rect, rotated, rect.size);

            

            // by default use "Self Render".

            // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"

            //???

            //和setTextureRect有重复代码部分

            setBatchNode(nullptr);

            result = true;

        }

        else

        {

            result = false;

        }

        _recursiveDirty = true;

        setDirty(true);

        return result;

    }


    //有重载,最终调用的是这个

    void Sprite::setTexture(Texture2D *texture)

    {

        // If batchnode, then texture id should be the same

        //batchNode需要的texture需要是一样的

        CCASSERT(! _batchNode || (texture &&  texture->getName() == _batchNode->getTexture()->getName()), "CCSprite: Batched sprites should use the same texture as the batchnode");

        // accept texture==nil as argument

        CCASSERT( !texture || dynamic_cast<Texture2D*>(texture), "setTexture expects a Texture2D. Invalid argument");


        if (texture == nullptr)

        {

            // Gets the texture by key firstly.

            //这个是一个默认的材质名字,用于在创建空的精灵时候创建的,为了保证opacity和color正确运行

            //可以见该文档cc_2x2_white_image的注释

            texture = Director::getInstance()->getTextureCache()->getTextureForKey(CC_2x2_WHITE_IMAGE_KEY);


            // If texture wasn't in cache, create it from RAW data.

            //有关image的可以在看之后的文档在回头看!!!!

            if (texture == nullptr)

            {

                Image* image = new (std::nothrow) Image();

                bool isOK = image->initWithRawData(cc_2x2_white_image, sizeof(cc_2x2_white_image), 2, 2, 8);

                CC_UNUSED_PARAM(isOK);

                CCASSERT(isOK, "The 2x2 empty texture was created unsuccessfully.");


                texture = Director::getInstance()->getTextureCache()->addImage(image, CC_2x2_WHITE_IMAGE_KEY);

                CC_SAFE_RELEASE(image);

            }

        }


        //切换素材

        if (!_batchNode && _texture != texture)

        {

            CC_SAFE_RETAIN(texture);

            CC_SAFE_RELEASE(_texture);

            _texture = texture;

            //更新blendFunc,见下

            updateBlendFunc();

        }

    }


    void Sprite::updateBlendFunc(void)

    {

        CCASSERT(! _batchNode, "CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a SpriteBatchNode");


        // it is possible to have an untextured spritec

        //??

        //是否通过不透明度来改变RGB值并不是很懂

        if (! _texture || ! _texture->hasPremultipliedAlpha())

        {

            _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED;

            setOpacityModifyRGB(false);

        }

        else

        {

            _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;

            setOpacityModifyRGB(true);

        }

    }


    //是否和当前设置冲突,如果冲突则更新颜色

    void Sprite::setOpacityModifyRGB(bool modify);


    //前半部本即是否根据透明度改变值,后半部分不懂

    void Sprite::updateColor(void);



    void Sprite::setTextureRect(const Rect& rect, bool rotated, const Size& untrimmedSize)

    {

        //这个参数是判断texture是否rotated的,但是具体不是很懂??

        //将此参数改为true后,图像逆时针反转了90度

        _rectRotated = rotated;


        setContentSize(untrimmedSize);

        setVertexRect(rect);

        //见下

        setTextureCoords(rect);


        //??

        //需要特别了解_quad

        //变量_unflippedOffsetPositionFromCenter如字面意思没有翻转前离中心点(?)的Vec2

        //目前看到该变量的入口是setSpriteFrame(SpriteFrame*)

        float relativeOffsetX = _unflippedOffsetPositionFromCenter.x;

        float relativeOffsetY = _unflippedOffsetPositionFromCenter.y;


        // issue #732

        if (_flippedX)

        {

            relativeOffsetX = -relativeOffsetX;

        }

        if (_flippedY)

        {

            relativeOffsetY = -relativeOffsetY;

        }


        _offsetPosition.x = relativeOffsetX + (_contentSize.width - _rect.size.width) / 2;

        _offsetPosition.y = relativeOffsetY + (_contentSize.height - _rect.size.height) / 2;


        // rendering using batch node

        if (_batchNode)

        {

            // update dirty_, don't update recursiveDirty_

            setDirty(true);

        }

        else

        {

            // self rendering

            

            // Atlas: Vertex

            float x1 = 0.0f + _offsetPosition.x;

            float y1 = 0.0f + _offsetPosition.y;

            float x2 = x1 + _rect.size.width;

            float y2 = y1 + _rect.size.height;


            // Don't update Z.

            _quad.bl.vertices.set(x1, y1, 0.0f);

            _quad.br.vertices.set(x2, y1, 0.0f);

            _quad.tl.vertices.set(x1, y2, 0.0f);

            _quad.tr.vertices.set(x2, y2, 0.0f);

        }

        

        _polyInfo.setQuad(&_quad);

    }


    void Sprite::setTextureCoords(Rect rect)

    {

        //经过scale_factor缩放过后的rect

        rect = CC_RECT_POINTS_TO_PIXELS(rect);


        Texture2D *tex = _batchNode ? _textureAtlas->getTexture() : _texture;

        if (! tex)

        {

            return;

        }


        float atlasWidth = (float)tex->getPixelsWide();

        float atlasHeight = (float)tex->getPixelsHigh();


        float left, right, top, bottom;


        //if的预编译在tilemap地图中出现黑色缝隙的时候进行使用,具体原理还未懂??

        //四个float变量是求在(1, 1)的材质中该材质的位置

        if (_rectRotated)

        {

    #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL

            left    = (2*rect.origin.x+1)/(2*atlasWidth);

            right   = left+(rect.size.height*2-2)/(2*atlasWidth);

            top     = (2*rect.origin.y+1)/(2*atlasHeight);

            bottom  = top+(rect.size.width*2-2)/(2*atlasHeight);

    #else

            left    = rect.origin.x/atlasWidth;

            right   = (rect.origin.x+rect.size.height) / atlasWidth;

            top     = rect.origin.y/atlasHeight;

            bottom  = (rect.origin.y+rect.size.width) / atlasHeight;

    #endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL


            if (_flippedX)

            {

                std::swap(top, bottom);

            }


            if (_flippedY)

            {

                std::swap(left, right);

            }


            //材质四个点

            _quad.bl.texCoords.u = left;

            _quad.bl.texCoords.v = top;

            _quad.br.texCoords.u = left;

            _quad.br.texCoords.v = bottom;

            _quad.tl.texCoords.u = right;

            _quad.tl.texCoords.v = top;

            _quad.tr.texCoords.u = right;

            _quad.tr.texCoords.v = bottom;

        }

        else

        {

    #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL

            left    = (2*rect.origin.x+1)/(2*atlasWidth);

            right    = left + (rect.size.width*2-2)/(2*atlasWidth);

            top        = (2*rect.origin.y+1)/(2*atlasHeight);

            bottom    = top + (rect.size.height*2-2)/(2*atlasHeight);

    #else

            left    = rect.origin.x/atlasWidth;

            right    = (rect.origin.x + rect.size.width) / atlasWidth;

            top        = rect.origin.y/atlasHeight;

            bottom    = (rect.origin.y + rect.size.height) / atlasHeight;

    #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL


            if(_flippedX)

            {

                std::swap(left, right);

            }


            if(_flippedY)

            {

                std::swap(top, bottom);

            }

            //u、v是材质坐标对应的横纵

            _quad.bl.texCoords.u = left;

            _quad.bl.texCoords.v = bottom;

            _quad.br.texCoords.u = right;

            _quad.br.texCoords.v = bottom;

            _quad.tl.texCoords.u = left;

            _quad.tl.texCoords.v = top;

            _quad.tr.texCoords.u = right;

            _quad.tr.texCoords.v = top;

        }

    }


    //对应上面的setTextureRect()

    void Sprite::setSpriteFrame(SpriteFrame *spriteFrame)

    {

        // retain the sprite frame

        // do not removed by SpriteFrameCache::removeUnusedSpriteFrames

        if (_spriteFrame != spriteFrame)

        {

            CC_SAFE_RELEASE(_spriteFrame);

            _spriteFrame = spriteFrame;

            spriteFrame->retain();

        }


        //这个getOffset()目前所知道的入口在于SpriteFrame::create(filename, rect, rotated, offset, originSize)

        //offset即是对应此offset,不过scale_factor参数影响。具体在SpriteFrame.cpp分析

        _unflippedOffsetPositionFromCenter = spriteFrame->getOffset();


        Texture2D *texture = spriteFrame->getTexture();

        // update texture before updating texture rect

        if (texture != _texture)

        {

            setTexture(texture);

        }


        // update rect

        _rectRotated = spriteFrame->isRotated();

        setTextureRect(spriteFrame->getRect(), _rectRotated, spriteFrame->getOriginalSize());

    }




    initWithPolygon特殊一些

    bool Sprite::initWithPolygon(const cocos2d::PolygonInfo &info)

    {

        Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(info.filename);

        bool res = false;

        if(initWithTexture(texture))

        {

            //多了一个这个参数,??

            _polyInfo = info;

            setContentSize(_polyInfo.rect.size/Director::getInstance()->getContentScaleFactor());

            res = true;

        }

        return res;

    }


    void Sprite::updateTransform(void);


    void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)

    {

        //自动裁剪

    #if CC_USE_CULLING

        // Don't do calculate the culling if the transform was not updated

        auto visitingCamera = Camera::getVisitingCamera();

        auto defaultCamera = Camera::getDefaultCamera();

        if (visitingCamera == defaultCamera) {

            _insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY)|| visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;

        }

        else

        {

            _insideBounds = renderer->checkVisibility(transform, _contentSize);

        }


        if(_insideBounds)

    #endif

        {

            //初始化QuadCommand对象,这就是渲染命令,会丢到渲染队列里

            _trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags);

            renderer->addCommand(&_trianglesCommand);

        }

    }


    有关batchNode先忽略


    //进行debugdraw,数据基于_polyInfo。如果是autoPolygon创建的会更精确,但是作用在那里?是否可以进行碰撞检测?

    void Sprite::debugDraw(bool on);









  • Layer:

    继承node


    构造函数,多了几个特定的参数,并进行初始化

    layer的锚点为Vec2(0.5, 0.5),但是因为开启了_ignoreAnchorPointForPosition,

    .所以可以理解为锚点为Vec2::Zero


    bool Layer::init()

    {

        Director * director = Director::getInstance();

        //contentSize为WinSize大小,也即是说放在layer上的需要做适配

        setContentSize(director->getWinSize());

        return true;

    }


    Layer貌似没有太多可以东西,很多东西都是不提倡使用的

    如setTouchEnabled,setKeyPad..等弃用函数,但是用依然还是可以用的。


    __LayerRGBA之后和__NodeRGBA一起学习


    LayerColor:

    继承Layer、BlendProtocol


    可以改变宽高的参数


    virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;

    virtual void setContentSize(const Size & var) override;

    bool initWithColor(const Color4B& color, GLfloat width, GLfloat height);

    void onDraw(const Mat4& transform, uint32_t flags);

    virtual void updateColor() override;


    LayerGradient(大概是颜色梯度) 和 LayerMultiplex  优先级放后面