Cocos2d-x源碼解析(1)——地圖模塊(3)

接上一章《Cocos2d-x源碼解析(1)——地圖模塊(2)》


通過前面兩章的分析,我們可以知道cocos將tmx的信息結構化到 CCTMXMapInfo,CCTMXTilesetInfo,CCTMXLayerInfo之中。

其中CCTMXMapInfo存儲地圖的信息包擴以下幾塊信息:

- Map orientation (hexagonal, isometric or orthogonal)
- Tile size
- Map size

- Layers (an array of TMXLayerInfo objects)
- Tilesets (an array of TMXTilesetInfo objects)
- ObjectGroups (an array of TMXObjectGroupInfo objects)

CCTMXTilesetInfo存儲瓦片信息包括:

- Tileset name
- Tileset spacing
- Tileset margin
- size of the tiles
- Image used for the tiles
- Image size

CCTMXLayerInfo存儲層的信息包括:

- Layer name
- Layer size
- Layer opacity at creation time (it can be modified at runtime)
- Whether the layer is visible (if it's not visible, then the CocosNode won't be created)


接下來,我們分析cocos如何通過這些信息,生成地圖的圖像:

首先我們看一個重要的函數buildWithMapInfo

void CCTMXTiledMap::buildWithMapInfo(CCTMXMapInfo* mapInfo)
{
    m_tMapSize = mapInfo->getMapSize();
    m_tTileSize = mapInfo->getTileSize();
    m_nMapOrientation = mapInfo->getOrientation();

    CC_SAFE_RELEASE(m_pObjectGroups);
    m_pObjectGroups = mapInfo->getObjectGroups();
    CC_SAFE_RETAIN(m_pObjectGroups);

    CC_SAFE_RELEASE(m_pProperties);
    m_pProperties = mapInfo->getProperties();
    CC_SAFE_RETAIN(m_pProperties);

    CC_SAFE_RELEASE(m_pTileProperties);
    m_pTileProperties = mapInfo->getTileProperties();
    CC_SAFE_RETAIN(m_pTileProperties);

    int idx=0;

    CCArray* layers = mapInfo->getLayers();
    if (layers && layers->count()>0)
    {
        CCTMXLayerInfo* layerInfo = NULL;
        CCObject* pObj = NULL;
        CCARRAY_FOREACH(layers, pObj)
        {
            layerInfo = (CCTMXLayerInfo*)pObj;
            if (layerInfo && layerInfo->m_bVisible)
            {
                CCTMXLayer *child = parseLayer(layerInfo, mapInfo);
                addChild((CCNode*)child, idx, idx);

                // update content size with the max size
                const CCSize& childSize = child->getContentSize();
                CCSize currentSize = this->getContentSize();
                currentSize.width = MAX( currentSize.width, childSize.width );
                currentSize.height = MAX( currentSize.height, childSize.height );
                this->setContentSize(currentSize);

                idx++;
            }
        }
    }
}

這個函數首相將地圖信息賦給map類,接下來對於每個layer進行處理,重要的函數是parseLayer,這個函數是將layer的信息處理好並且加上sprite,並生成CTMXlayer對象。


因此我們需要分析parseLayer函數和CTMXlayer類。

首先我們看CTMXlayer的聲明:


class CC_DLL CCTMXLayer : public CCSpriteBatchNode
{
    /** size of the layer in tiles */
    CC_SYNTHESIZE_PASS_BY_REF(CCSize, m_tLayerSize, LayerSize);
    /** size of the map's tile (could be different from the tile's size) */
    CC_SYNTHESIZE_PASS_BY_REF(CCSize, m_tMapTileSize, MapTileSize);
    /** pointer to the map of tiles */
    CC_SYNTHESIZE(unsigned int*, m_pTiles, Tiles);
    /** Tileset information for the layer */
    CC_PROPERTY(CCTMXTilesetInfo*, m_pTileSet, TileSet);
    /** Layer orientation, which is the same as the map orientation */
    CC_SYNTHESIZE(unsigned int, m_uLayerOrientation, LayerOrientation);
    /** properties from the layer. They can be added using Tiled */
    CC_PROPERTY(CCDictionary*, m_pProperties, Properties);
public:
    /**
     * @js ctor
     * @lua NA
     */
    CCTMXLayer();
    /**
     * @js NA
     * @lua NA
     */
    virtual ~CCTMXLayer();
  
    /** creates a CCTMXLayer with an tileset info, a layer info and a map info */
    static CCTMXLayer * create(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo);

    /** initializes a CCTMXLayer with a tileset info, a layer info and a map info 
     * @lua NA
     */
    bool initWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo);

    /** dealloc the map that contains the tile position from memory.
    Unless you want to know at runtime the tiles positions, you can safely call this method.
    If you are going to call layer->tileGIDAt() then, don't release the map
    */
    void releaseMap();

    /** returns the tile (CCSprite) at a given a tile coordinate.
    The returned CCSprite will be already added to the CCTMXLayer. Don't add it again.
    The CCSprite can be treated like any other CCSprite: rotated, scaled, translated, opacity, color, etc.
    You can remove either by calling:
    - layer->removeChild(sprite, cleanup);
    - or layer->removeTileAt(ccp(x,y));
    @js getTileGIDAt
    */
    CCSprite* tileAt(const CCPoint& tileCoordinate);

    /** returns the tile gid at a given tile coordinate.
    if it returns 0, it means that the tile is empty.
    This method requires the the tile map has not been previously released (eg. don't call layer->releaseMap())
    @js tileGIDAt
    */
    unsigned int  tileGIDAt(const CCPoint& tileCoordinate);

    /** returns the tile gid at a given tile coordinate. It also returns the tile flags.
     This method requires the the tile map has not been previously released (eg. don't call [layer releaseMap])
     @js tileGIDAt
     @lua NA
     */
    unsigned int tileGIDAt(const CCPoint& tileCoordinate, ccTMXTileFlags* flags);

    /** sets the tile gid (gid = tile global id) at a given tile coordinate.
    The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor -> Tileset Mgr +1.
    If a tile is already placed at that position, then it will be removed.
    */
    void setTileGID(unsigned int gid, const CCPoint& tileCoordinate);

    /** sets the tile gid (gid = tile global id) at a given tile coordinate.
     The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor -> Tileset Mgr +1.
     If a tile is already placed at that position, then it will be removed.
     
     Use withFlags if the tile flags need to be changed as well
     */

    void setTileGID(unsigned int gid, const CCPoint& tileCoordinate, ccTMXTileFlags flags);

    /** removes a tile at given tile coordinate */
    void removeTileAt(const CCPoint& tileCoordinate);

    /** returns the position in points of a given tile coordinate 
     * @js getPositionAt
     */
    CCPoint positionAt(const CCPoint& tileCoordinate);

    /** return the value for the specific property name 
     *  @js getProperty
     */
    CCString *propertyNamed(const char *propertyName);

    /** Creates the tiles */
    void setupTiles();

    /** CCTMXLayer doesn't support adding a CCSprite manually.
     *  @warning addchild(z, tag); is not supported on CCTMXLayer. Instead of setTileGID.
     *  @lua NA
     */
    virtual void addChild(CCNode * child, int zOrder, int tag);
    /** super method
     *  @lua NA
     */
    void removeChild(CCNode* child, bool cleanup);

    inline const char* getLayerName(){ return m_sLayerName.c_str(); }
    inline void setLayerName(const char *layerName){ m_sLayerName = layerName; }
private:
    CCPoint positionForIsoAt(const CCPoint& pos);
    CCPoint positionForOrthoAt(const CCPoint& pos);
    CCPoint positionForHexAt(const CCPoint& pos);

    CCPoint calculateLayerOffset(const CCPoint& offset);

    /* optimization methods */
    CCSprite* appendTileForGID(unsigned int gid, const CCPoint& pos);
    CCSprite* insertTileForGID(unsigned int gid, const CCPoint& pos);
    CCSprite* updateTileForGID(unsigned int gid, const CCPoint& pos);

    /* The layer recognizes some special properties, like cc_vertez */
    void parseInternalProperties();
    void setupTileSprite(CCSprite* sprite, CCPoint pos, unsigned int gid);
    CCSprite* reusedTileWithRect(CCRect rect);
    int vertexZForPos(const CCPoint& pos);

    // index
    unsigned int atlasIndexForExistantZ(unsigned int z);
    unsigned int atlasIndexForNewZ(int z);
protected:
    //! name of the layer
    std::string m_sLayerName;
    //! TMX Layer supports opacity
    unsigned char        m_cOpacity;

    unsigned int        m_uMinGID;
    unsigned int        m_uMaxGID;

    //! Only used when vertexZ is used
    int                    m_nVertexZvalue;
    bool                m_bUseAutomaticVertexZ;

    //! used for optimization
    CCSprite            *m_pReusedTile;
    ccCArray            *m_pAtlasIndexArray;
    
    // used for retina display
    float               m_fContentScaleFactor;            
};

雖然有一大堆的屬性和函數,但是歸根結底他是一個CCSpriteBatchNode對象,由於地圖中很多圖片是相同的。CCSpriteBatchNode就是cocos2d-x爲了降低渲染批次而建立的一個專門管理精靈的類。

然後是函數parseLayer

CCTMXLayer * CCTMXTiledMap::parseLayer(CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
{
    CCTMXTilesetInfo *tileset = tilesetForLayer(layerInfo, mapInfo);
    CCTMXLayer *layer = CCTMXLayer::create(tileset, layerInfo, mapInfo);

    // tell the layerinfo to release the ownership of the tiles map.
    layerInfo->m_bOwnTiles = false;
    layer->setupTiles();

    return layer;
}

這個函數又分爲3步

第一步tilesetForLayer是拿到任意一塊屬於這個layer的tile。

第二步是根據layerInfo創建一個真正的層信息。

第三步是將tiled加入到這個層中去。

發佈了31 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章