cocos2d-x庖丁解牛(1):CCParallaxNode源碼分析

/**
 CCPointObject用於記錄CCParallaxNode孩子節點的ratio和offset屬性
 **/
class CCPointObject : CCObject
{
    //視差速率
    CC_SYNTHESIZE(CCPoint, m_tRatio, Ratio)
    //在CCParallaxNode中的偏移量
    CC_SYNTHESIZE(CCPoint, m_tOffset, Offset)
    CC_SYNTHESIZE(CCNode *,m_pChild, Child)    // weak ref

    static CCPointObject * pointWithCCPoint(CCPoint ratio, CCPoint offset)
    {
        CCPointObject *pRet = new CCPointObject();
        pRet->initWithCCPoint(ratio, offset);
        pRet->autorelease();
        return pRet;
    }
    bool initWithCCPoint(CCPoint ratio, CCPoint offset)
    {
        m_tRatio = ratio;
        m_tOffset = offset;
        m_pChild = NULL;
        return true;
    }
};

//CCParallaxNode構造函數
CCParallaxNode::CCParallaxNode()
{
    m_pParallaxArray = ccArrayNew(5);        
    m_tLastPosition = CCPointMake(-100,-100);
}
CCParallaxNode::~CCParallaxNode()
{
    if( m_pParallaxArray )
    {
        ccArrayFree(m_pParallaxArray);
        m_pParallaxArray = NULL;
    }
}

CCParallaxNode * CCParallaxNode::node()
{
    return CCParallaxNode::create();
}

CCParallaxNode * CCParallaxNode::create()
{
    CCParallaxNode *pRet = new CCParallaxNode();
    pRet->autorelease();
    return pRet;
}

void CCParallaxNode::addChild(CCNode * child, unsigned int zOrder, int tag)
{
    CC_UNUSED_PARAM(zOrder);
    CC_UNUSED_PARAM(child);
    CC_UNUSED_PARAM(tag);
    CCAssert(0,"ParallaxNode: use addChild:z:parallaxRatio:positionOffset instead");
}
void CCParallaxNode::addChild(CCNode *child, unsigned int z, const CCPoint& ratio, const CCPoint& offset)
{
    CCAssert( child != NULL, "Argument must be non-nil");
    //記錄屬性
    CCPointObject *obj = CCPointObject::pointWithCCPoint(ratio, offset);
    obj->setChild(child);
    //擴容處理
    ccArrayAppendObjectWithResize(m_pParallaxArray, (CCObject*)obj);
    
    //當CCParallaxNode的位置不是(0,0)時添加孩子,會發生比較詭異的事情
    CCPoint pos = m_tPosition;
    pos.x = pos.x * ratio.x + offset.x;
    pos.y = pos.y * ratio.y + offset.y;
    child->setPosition(pos);

    CCNode::addChild(child, z, child->getTag());
}
void CCParallaxNode::removeChild(CCNode* child, bool cleanup)
{
    //刪除屬性
    for( unsigned int i=0;i < m_pParallaxArray->num;i++)
    {
        CCPointObject *point = (CCPointObject*)m_pParallaxArray->arr[i];
        if( point->getChild()->isEqual(child)) 
        {
            ccArrayRemoveObjectAtIndex(m_pParallaxArray, i, true);
            break;
        }
    }
    //刪除node
    CCNode::removeChild(child, cleanup);
}
void CCParallaxNode::removeAllChildrenWithCleanup(bool cleanup)
{
    ccArrayRemoveAllObjects(m_pParallaxArray);
    CCNode::removeAllChildrenWithCleanup(cleanup);
}
CCPoint CCParallaxNode::absolutePosition()
{
    CCPoint ret = m_tPosition;
    CCNode *cn = this;
    //層層向上計算,獲得絕對座標,至於爲什麼需要這樣,下面有段註釋
    while (cn->getParent() != NULL)
    {
        cn = cn->getParent();
        ret = ccpAdd( ret,  cn->getPosition());
    }
    return ret;
}

/*
The positions are updated at visit because:
- using a timer is not guaranteed that it will called after all the positions were updated
- overriding "draw" will only precise if the children have a z > 0
*/
void CCParallaxNode::visit()
{
    //    CCPoint pos = position_;
    //    CCPoint    pos = [self convertToWorldSpace:CCPointZero];
    CCPoint pos = this->absolutePosition(); //獲得絕對座標
    if( ! CCPoint::CCPointEqualToPoint(pos, m_tLastPosition) ) //dirty處理
    {
        //計算所有孩子相對於CCParallaxNode的位置,注意當我們移動CCParallaxNode位置時,表現出來的其實是孩子位置的改變,這種變化是本類的核心設計。
        for(unsigned int i=0; i < m_pParallaxArray->num; i++ ) 
        {
            //
            CCPointObject *point = (CCPointObject*)m_pParallaxArray->arr[i];
            //例如CCParallaxNode絕對位置爲100,表現出來的是孩子位置爲-100,CCParallaxNode的移動我們不能感知,但孩子的位置卻發生了變化。
            //簡單點就是類似於一個攝像頭場景的移動,攝像頭未動,風景變了
            //如果ratio爲1,則postion == offset
            //如果ratio爲(0,1),則position < offset,移動速度慢
            //如果ratio爲(1,xx),則postion > offset,移動速度快
            float x = -pos.x + pos.x * point->getRatio().x + point->getOffset().x;
            //同x
            float y = -pos.y + pos.y * point->getRatio().y + point->getOffset().y;
            //孩子的位置是通過上面兩行計算出來的,因此手動設置其postion不會有任何作用
            point->getChild()->setPosition(ccp(x,y));
        }
        //更新上一個位置
        m_tLastPosition = pos;
    }
    CCNode::visit();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章