5.【cocos2d-x 源码分析】:Node 类体系的详细分析

对应源码位置:(1)cocos2d-x-3.3\cocos\2d\CCNode (2)cocos2d-x-3.3\cocos\2d\CCLayer(3)cocos2d-x-3.3\cocos\2d\CCScene

Node是整个游戏对象的根节点

基本后面熟知的 spritelayer 以及 scene都是他的子类。
5.【cocos2d-x 源码分析】:Node 类体系的详细分析

Node类的部分代码

由于Cocos2d-x采用继承的方针组织整个游戏对象,所以Node类的负担很重,很庞大。简单抽取一部分出来。

class CC_DLL Node : public Ref
{
public:
    /// Default tag used for all the nodes
    static const int INVALID_TAG = -1;
	//老规矩  就是看 变了没  没变就不计算  这样优化
    enum {
        FLAGS_TRANSFORM_DIRTY = (1 << 0),
        FLAGS_CONTENT_SIZE_DIRTY = (1 << 1),

        FLAGS_DIRTY_MASK = (FLAGS_TRANSFORM_DIRTY | FLAGS_CONTENT_SIZE_DIRTY),
    };
    
    static Node * create();
	//加入 孩子节点  用一个vector来存储
    virtual void addChild(Node* child, int localZOrder, const std::string &name);
	//设置 父级节点
    virtual void setParent(Node* parent);
   	//这里主要是  设置 opengl的 shader程序  下一篇具体分析
    GLProgram* getGLProgram() const;
    GLProgramState *getGLProgramState() const;
    virtual void setGLProgramState(GLProgramState *glProgramState);
	//这里就是 具体渲染时  跟opengl有关的部分 
	//统一的接口  代表节点对象的绘制 方式
    virtual void draw(Renderer *renderer, const Mat4& transform, uint32_t flags);
    virtual void draw() final;

    /**
     * Visits this node's children and draw them recursively.
     */
     //这里是  访问孩子节点  并绘制  后面具体分析
    virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags);
    virtual void visit() final;
	//获取 Node所属于的scene
    virtual Scene* getScene() const;
    //这个就是  前面schedule里面注册的  每帧调用的函数  注册的位置
    //这也是  最常用的 update逻辑
    void scheduleUpdate(void);
    virtual void update(float delta);

	//下面是 node的属性  也是action动作改变的数据

    float _rotationX;               ///< rotation on the X-axis
    float _rotationY;               ///< rotation on the Y-axis

    // rotation Z is decomposed in 2 to simulate Skew for Flash animations
    float _rotationZ_X;             ///< rotation angle on Z-axis, component X
    float _rotationZ_Y;             ///< rotation angle on Z-axis, component Y

    float _scaleX;                  ///< scaling factor on x-axis
    float _scaleY;                  ///< scaling factor on y-axis
    float _scaleZ;                  ///< scaling factor on z-axis

    Vec2 _position;                ///< position of the node
    float _positionZ;               ///< OpenGL real Z position
    Vec2 _normalizedPosition;
    bool _usingNormalizedPosition;
    bool _normalizedPositionDirty;

    float _skewX;                   ///< skew angle on x-axis
    float _skewY;                   ///< skew angle on y-axis

    Vec2 _anchorPointInPoints;     ///< anchor point in points
    Vec2 _anchorPoint;             ///< anchor point normalized (NOT in points)

    Size _contentSize;              ///< untransformed size of the node
    bool _contentSizeDirty;         ///< whether or not the contentSize is dirty

    Mat4 _modelViewTransform;    ///< ModelView transform of the Node.

    // "cache" variables are allowed to be mutable
    mutable Mat4 _transform;      ///< transform
    mutable bool _transformDirty;   ///< transform dirty flag
    mutable Mat4 _inverse;        ///< inverse transform
    mutable bool _inverseDirty;     ///< inverse transform dirty flag
    mutable Mat4 _additionalTransform; ///< transform
    bool _useAdditionalTransform;   ///< The flag to check whether the additional transform is dirty
    bool _transformUpdated;         ///< Whether or not the Transform object was updated since the last frame
	//一个是local一个是全局的
    int _localZOrder;               ///< Local order (relative to its siblings) used to sort the node
    float _globalZOrder;            ///< Global order used to sort the node

    Vector<Node*> _children;        ///< array of children nodes
    Node *_parent;                  ///< weak reference to parent node

    int _tag;                         ///< a tag. Can be any number you assigned just to identify this node
    
    std::string _name;               ///<a string label, an user defined string to identify this node
    size_t _hashOfName;            ///<hash value of _name, used for speed in getChildByName

    void *_userData;                ///< A user assingned void pointer, Can be point to any cpp object
    Ref *_userObject;               ///< A user assigned Object

    GLProgramState *_glProgramState; ///< OpenGL Program State

    int _orderOfArrival;            ///< used to preserve sequence while sorting children with the same localZOrder

    Scheduler *_scheduler;          ///< scheduler used to schedule timers and updates

    ActionManager *_actionManager;  ///< a pointer to ActionManager singleton, which is used to handle all the actions

    EventDispatcher* _eventDispatcher;  ///< event dispatcher used to dispatch all kinds of events

    bool _running;                  ///< is running

    bool _visible;                  ///< is this node visible

    bool _ignoreAnchorPointForPosition; ///< true if the Anchor Vec2 will be (0,0) when you position the Node, false otherwise.
                                          ///< Used by Layer and Scene.

    bool _reorderChildDirty;          ///< children order dirty flag
    bool _isTransitionFinished;       ///< flag to indicate whether the transition was finished
    
    ComponentContainer *_componentContainer;        ///< Dictionary of components
	//刚体部分  用于参与 物理世界
    PhysicsBody* _physicsBody;        ///< the physicsBody the node have
    float _physicsScaleStartX;         ///< the scale x value when setPhysicsBody
    float _physicsScaleStartY;         ///< the scale y value when setPhysicsBody

    
    // opacity controls
    GLubyte		_displayedOpacity;
    GLubyte     _realOpacity;
    Color3B	    _displayedColor;
    Color3B     _realColor;
    bool		_cascadeColorEnabled;
    bool        _cascadeOpacityEnabled;

    static int s_globalOrderOfArrival;
    //和unity类似的  标签
    // camera mask, it is visible only when _cameraMask & current camera' camera flag is true
    unsigned short _cameraMask;
    //几个阶段的  回调函数
    //If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately.
    std::function<void()> _onEnterCallback;
    std::function<void()> _onExitCallback;
    std::function<void()> _onEnterTransitionDidFinishCallback;
    std::function<void()> _onExitTransitionDidStartCallback;
};

下面看具体实现的几个函数:

//添加孩子节点的逻辑
void Node::addChild(Node* child, int localZOrder, const std::string &name)
{
    CCASSERT(child != nullptr, "Argument must be non-nil");
    CCASSERT(child->_parent == nullptr, "child already added. It can't be added again");
    
    addChildHelper(child, localZOrder, INVALID_TAG, name, false);
}

void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
{
    if (_children.empty())
    {
        this->childrenAlloc();
    }
    //插入到 vector中 同时 更新一下 孩子标志 脏了
    //为了 重新排序
    this->insertChild(child, localZOrder);
    
    if (setTag)
        child->setTag(tag);
    else
        child->setName(name);
    //设置父级节点
    child->setParent(this);
    //设置到达顺序
    child->setOrderOfArrival(s_globalOrderOfArrival++);
    
#if CC_USE_PHYSICS
    // Recursive add children with which have physics body.
    //如果 是物理的scene 则加 入到 物理世界中
    auto scene = this->getScene();
    if (scene && scene->getPhysicsWorld())
    {
    	//同时  更新  一些物理属性
        child->updatePhysicsBodyTransform(scene);
        scene->addChildToPhysicsWorld(child);
    }
#endif
    
    if( _running )
    {
    	//汇报  孩子节点  进入的消息  
        child->onEnter();
        // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
        if (_isTransitionFinished) {
            child->onEnterTransitionDidFinish();
        }
    }
    //更新相关属性
    if (_cascadeColorEnabled)
    {
        updateCascadeColor();
    }
    
    if (_cascadeOpacityEnabled)
    {
        updateCascadeOpacity();
    }
}
//绘制相关  具体opengl内容 下一篇
void Node::draw()
{
    auto renderer = Director::getInstance()->getRenderer();
    draw(renderer, _modelViewTransform, true);
}
//留给子类实现
void Node::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags)
{
}
//访问子类  并访问
void Node::visit()
{
    auto renderer = Director::getInstance()->getRenderer();
    Mat4 parentTransform = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    visit(renderer, parentTransform, true);
}
//parentTransform 是用来传递  父节点的 位置朝向 矩阵  
//与子类的相乘才得到最终的 世界坐标系的位置
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);
    
    bool visibleByCamera = isVisitableByVisitingCamera();

    int i = 0;

    if(!_children.empty())
    {
    	//先排序  似曾相识
        sortAllChildren();
        //关于zorder盗来 一段话
 /*总结:节点的渲染顺序跟节点的三个成员变量有关(_localZOrder、_globalZOrder、_orderOfArrival)分别对应三个设置函数setLocalZOrder、		   setGlobalZOrder、setOrderOfArrival。无论是_localZOrder、_globalZOrder、_orderOfArrival都是越大的越后渲染,越小的越先渲染,而且有_globalZOrder的优先级大于_localZOrder的优先级大于_orderOfArrival的优先级。所以我们判断节点间的渲染(绘制)顺序时应先对比他们的_globalZOrder值,如若相等,再对比他们的_localZOrder值,如若相等,再对比他们的_orderOfArrival值。其中,_orderOfArrival值在调用addChild函数是自动给出,一般我们不调用setOrderOfArrival函数去更改节点间的渲染(绘制)顺序。

补充:当采用LocalZOrder作为节点渲染(绘制)顺序的判断值时,父节点的LocalZOrder不与子节点的LocalZOrder值作比较。子节点中LocalZOrder值小于0的节点作为以父节点为根节点的树的左子树的根节点,大于0的作为右子树的根节点。所以在中序遍历下,先(渲染)绘制子节点中LocalZOrder值小于0的子节点,再渲染(绘制)父节点,再渲染LocalZOrder值大于0的子节点。*/

        // 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
        if (visibleByCamera)
            this->draw(renderer, _modelViewTransform, flags);
		//注意 加了个i 所以是zorder>0 cbegin是指返回的const类型 迭代器
        for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
            (*it)->visit(renderer, _modelViewTransform, flags);
    }
    //没有孩子  如果能被摄像机看到  就绘制自身
    else if (visibleByCamera)
    {	
        this->draw(renderer, _modelViewTransform, flags);
    }

    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    // FIX ME: Why need to set _orderOfArrival to 0??
    // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
    // reset for next frame
    // _orderOfArrival = 0;
}

简要介绍 Layer

//可以看到 layer 没有添加什么
//只是 把常用的 几个事件监听器  更方便的集成
class CC_DLL Layer : public Node
{
public:    
    /** creates a fullscreen black layer */
    static Layer *create();
    // Overrides
    virtual std::string getDescription() const override;

CC_CONSTRUCTOR_ACCESS:
    Layer();
    virtual ~Layer();
    virtual bool init() override;
    
    bool _touchEnabled;
    bool _accelerometerEnabled;
    bool _keyboardEnabled;
    EventListener* _touchListener;
    EventListenerKeyboard* _keyboardListener;
    EventListenerAcceleration* _accelerationListener;

    Touch::DispatchMode _touchMode;
    bool _swallowsTouches;
};

简要介绍 Scene

//这里面最重要的是 Scene对Camera和BaseLight的支持  以及物理世界的支持
class CC_DLL Scene : public Node
{
public:
    /** creates a new Scene object */
    static Scene *create();

    /** creates a new Scene object with a predefined Size */
    static Scene *createWithSize(const Size& size);

    using Node::addChild;
    virtual std::string getDescription() const override;
    
    /** get all cameras */
    const std::vector<Camera*>& getCameras() const { return _cameras; }

    const std::vector<BaseLight*>& getLights() const { return _lights; }
    
    /** render the scene */
    void render(Renderer* renderer);
    
CC_CONSTRUCTOR_ACCESS:
    Scene();
    virtual ~Scene();
    
    bool init();
    bool initWithSize(const Size& size);
    
    void onProjectionChanged(EventCustom* event);

protected:
    std::vector<Camera*> _cameras; //weak ref to Camera
    Camera*              _defaultCamera; //weak ref, default camera created by scene, _cameras[0], Caution that the default camera can not be added to _cameras before onEnter is called
    EventListenerCustom*       _event;

    std::vector<BaseLight *> _lights;
    
private:
    CC_DISALLOW_COPY_AND_ASSIGN(Scene);
    
#if CC_USE_PHYSICS
public:
    virtual void addChild(Node* child, int zOrder, int tag) override;
    virtual void addChild(Node* child, int zOrder, const std::string &name) override;
    virtual void update(float delta) override;
    inline PhysicsWorld* getPhysicsWorld() { return _physicsWorld; }
    static Scene *createWithPhysics();
    
CC_CONSTRUCTOR_ACCESS:
    bool initWithPhysics();
    
protected:
    void addChildToPhysicsWorld(Node* child);

    PhysicsWorld* _physicsWorld;
#endif // CC_USE_PHYSICS
};

最后

Node 类体系 与 渲染部分 密不可分 ,本篇只能简单分析,下一篇 分析渲染部分