TMXMap解析

来源:互联网 发布:windows如何设置锁屏 编辑:程序博客网 时间:2024/06/07 02:51

TMXMap.h

#ifndef __CCTMX_TILE_MAP_H__#define __CCTMX_TILE_MAP_H__#include "CCNode.h"#include "CCTMXObjectGroup.h"#include "CCValue.h"NS_CC_BEGIN// TMXMap 需要包含的类class TMXObjectGroup;class TMXLayer;class TMXLayerInfo;class TMXTilesetInfo;class TMXMapInfo;/** 地图方向 */enum{    /** 直角地图 */    TMXOrientationOrtho,    /** 六边形地图 */    TMXOrientationHex,    /** 45度斜角地图 */    TMXOrientationIso,};/**特点:-每个图块都会被当做sprite处理-精灵只有在需要的时候才被创建,他们只有当你使用"layer->tileAt(position)"创建-每个图块可以使用旋转,放大,缩小等等操作-图块在程序运行的时候可以移除-TMX地图的锚点时(0 ,0)-地图图块的z轴值可以动态变更-图块的锚点时(0 ,0)-TMX图层被当做Layer添加-TNX图层有自己的名称-图块会使用TextureCache添加-每个图块都有自己特有的标签-每个图块都有z轴值,左上方z为0,右下方z轴值最大-每个对象组都会被当做Array处理-对象类使用字典包含所有的属性-各个属性会被分配到地图,层,对象组和对象中限制:-每个地图层最多支持一套瓦片素材组-被嵌套的瓦片地图不被支持(如 使用瓦片素材组与其他图片)-只支持XMl数据格式技术性描述TMX地图使用TMXLayer加载图层,如果图层设置为不可见,程序不会加载图层可以通过- map->getChildByTag(tag_number);  // 0=1st layer, 1=2nd layer, 2=3rd layer, etc...- map->getLayer(name_of_the_layer);获取图层每个对象组都会使用TMXObjectGroup加载对象,可以通过getObjectGroup()函数获取对象组每个对象都是TMXObject。每个属性都会存储在字典数组中map->getProperty(name_of_the_property);layer->getProperty(name_of_the_property);objectGroup->getProperty(name_of_the_property);object->getProperty(name_of_the_property);*/class CC_DLL TMXTiledMap : public Node{public:    /** 静态函数 根据路径创建TMXMap*/    static TMXTiledMap* create(const std::string& tmxFile);    /** 使用XML数据导入地图 */    static TMXTiledMap* createWithXML(const std::string& tmxString, const std::string& resourcePath);    /** 获取图层 */    TMXLayer* getLayer(const std::string& layerName) const;    /**     * @js NA     * @lua NA     */    CC_DEPRECATED_ATTRIBUTE TMXLayer* layerNamed(const std::string& layerName) const { return getLayer(layerName); };    /** 返回对象组 */    TMXObjectGroup* getObjectGroup(const std::string& groupName) const;    /**     * @js NA     * @lua NA     */    CC_DEPRECATED_ATTRIBUTE TMXObjectGroup* objectGroupNamed(const std::string& groupName) const { return getObjectGroup(groupName); };    /** 通过属性名获取属性 */    Value getProperty(const std::string& propertyName) const;    /**     * @js NA     * @lua NA     */    CC_DEPRECATED_ATTRIBUTE Value propertyNamed(const char *propertyName) const { return getProperty(propertyName); };    /**返回属性字典,每个图块都有一个id */    Value getPropertiesForGID(int GID) const;    CC_DEPRECATED_ATTRIBUTE Value propertiesForGID(int GID) const { return getPropertiesForGID(GID); };    /** 根据GID,获得属性字典     */    bool getPropertiesForGID(int GID, Value** value);    /** 地图的大小获取与设置 */    inline const Size& getMapSize() const { return _mapSize; };    inline void setMapSize(const Size& mapSize) { _mapSize = mapSize; };    /** 返回图块大小,以像素点为单位 */    inline const Size& getTileSize() const { return _tileSize; };    inline void setTileSize(const Size& tileSize) { _tileSize = tileSize; };    /** 地图的朝向 */    inline int getMapOrientation() const { return _mapOrientation; };    inline void setMapOrientation(int mapOrientation) { _mapOrientation = mapOrientation; };    /** 获取对象数组 */    inline const Vector<TMXObjectGroup*>& getObjectGroups() const { return _objectGroups; };    inline Vector<TMXObjectGroup*>& getObjectGroups() { return _objectGroups; };    inline void setObjectGroups(const Vector<TMXObjectGroup*>& groups) {        _objectGroups = groups;    };        /** 获取与设置属性 */    inline ValueMap& getProperties() { return _properties; };    inline void setProperties(const ValueMap& properties) {        _properties = properties;    };    virtual std::string getDescription() const override;    CC_CONSTRUCTOR_ACCESS:    /**     * @js ctor     */    TMXTiledMap();    /**     * @js NA     * @lua NA     */    virtual ~TMXTiledMap();        /** 根据路径获取地图数据 */    bool initWithTMXFile(const std::string& tmxFile);        /** XML字符串与资源路径创建Map */    bool initWithXML(const std::string& tmxString, const std::string& resourcePath);protected:    TMXLayer * parseLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo);    TMXTilesetInfo * tilesetForLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo);    void buildWithMapInfo(TMXMapInfo* mapInfo);    /** 地图大小 */    Size _mapSize;    /** 图块大小 */    Size _tileSize;    /** 地图朝向 */    int _mapOrientation;    /** 对象数组 */    Vector<TMXObjectGroup*> _objectGroups;    /** 属性 */    ValueMap _properties;        //! 图块属性    ValueMapIntKey _tileProperties;private:    CC_DISALLOW_COPY_AND_ASSIGN(TMXTiledMap);};// end of tilemap_parallax_nodes group/// @}NS_CC_END#endif //__CCTMX_TILE_MAP_H__

TMXMap.cpp

#include "CCTMXTiledMap.h"#include "CCTMXXMLParser.h"#include "CCTMXLayer.h"#include "CCSprite.h"#include "deprecated/CCString.h" // For StringUtils::format#include <algorithm>NS_CC_BEGIN// 静态函数TMXTiledMap * TMXTiledMap::create(const std::string& tmxFile){    TMXTiledMap *ret = new TMXTiledMap();    if (ret->initWithTMXFile(tmxFile))    {        ret->autorelease();        return ret;    }    CC_SAFE_DELETE(ret);    return nullptr;}// 静态函数TMXTiledMap* TMXTiledMap::createWithXML(const std::string& tmxString, const std::string& resourcePath){    TMXTiledMap *ret = new TMXTiledMap();    if (ret->initWithXML(tmxString, resourcePath))    {        ret->autorelease();        return ret;    }    CC_SAFE_DELETE(ret);    return nullptr;}// 根据路径生成TMXMapInfo 由TMXMapInfo产生地图bool TMXTiledMap::initWithTMXFile(const std::string& tmxFile){    CCASSERT(tmxFile.size()>0, "TMXTiledMap: tmx file should not be empty");        setContentSize(Size::ZERO);    TMXMapInfo *mapInfo = TMXMapInfo::create(tmxFile);    if (! mapInfo)    {        return false;    }    CCASSERT( !mapInfo->getTilesets().empty(), "TMXTiledMap: Map not found. Please check the filename.");    buildWithMapInfo(mapInfo);    return true;}// 同上bool TMXTiledMap::initWithXML(const std::string& tmxString, const std::string& resourcePath){    setContentSize(Size::ZERO);    TMXMapInfo *mapInfo = TMXMapInfo::createWithXML(tmxString, resourcePath);    CCASSERT( !mapInfo->getTilesets().empty(), "TMXTiledMap: Map not found. Please check the filename.");    buildWithMapInfo(mapInfo);    return true;}TMXTiledMap::TMXTiledMap()    :_mapSize(Size::ZERO)    ,_tileSize(Size::ZERO)        {}TMXTiledMap::~TMXTiledMap(){}// 解析层TMXLayer * TMXTiledMap::parseLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo){    TMXTilesetInfo *tileset = tilesetForLayer(layerInfo, mapInfo);    TMXLayer *layer = TMXLayer::create(tileset, layerInfo, mapInfo);    //用于使Info释放the tiles map.    layerInfo->_ownTiles = false;    layer->setupTiles();    return layer;}TMXTilesetInfo * TMXTiledMap::tilesetForLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo){    Size size = layerInfo->_layerSize;    auto& tilesets = mapInfo->getTilesets();    if (tilesets.size()>0)    {        TMXTilesetInfo* tileset = nullptr;        for (auto iter = tilesets.crbegin(); iter != tilesets.crend(); ++iter)        {            tileset = *iter;            if (tileset)            {                for( int y=0; y < size.height; y++ )                {                    for( int x=0; x < size.width; x++ )                    {                        int pos = static_cast<int>(x + size.width * y);                        int gid = layerInfo->_tiles[ pos ];                       // 关于数据存储的形式                        // XXX: gid == 0 --> empty tile                        if( gid != 0 )                         {                            // Optimization: quick return                            // 如果层是无效的(如:包含了多于一套素材组)后面会抛出错误                            if( (gid & kTMXFlippedMask) >= tileset->_firstGid )                                return tileset;                        }                    }                }                    }        }    }    // 如果图集为空 打印空层名称    CCLOG("cocos2d: Warning: TMX Layer '%s' has no tiles", layerInfo->_name.c_str());    return nullptr;}// 根据MapInfo数据结构创建TMXMap地图void TMXTiledMap::buildWithMapInfo(TMXMapInfo* mapInfo){    _mapSize = mapInfo->getMapSize();    _tileSize = mapInfo->getTileSize();    _mapOrientation = mapInfo->getOrientation();    _objectGroups = mapInfo->getObjectGroups();    _properties = mapInfo->getProperties();    _tileProperties = mapInfo->getTileProperties();    int idx=0;    auto& layers = mapInfo->getLayers();    for(const auto &layerInfo : layers) {        if (layerInfo->_visible)        {        // TMXLayer 使用addchild添加进children数组        // paraseLaye函数中tilesetForLayer解析LayerInfo生成TMXLayer,注意zorder            TMXLayer *child = parseLayer(layerInfo, mapInfo);            addChild(child, idx, idx);                        // update content size with the max size            const Size& childSize = child->getContentSize();            Size currentSize = this->getContentSize();            currentSize.width = std::max( currentSize.width, childSize.width );            currentSize.height = std::max( currentSize.height, childSize.height );            this->setContentSize(currentSize);                        idx++;        }    }}// publicTMXLayer * TMXTiledMap::getLayer(const std::string& layerName) const{    CCASSERT(layerName.size() > 0, "Invalid layer name!");        for (auto& child : _children)    {        TMXLayer* layer = dynamic_cast<TMXLayer*>(child);        if(layer)        {            if(layerName.compare( layer->getLayerName()) == 0)            {                return layer;            }        }    }    // layer not found    return nullptr;}TMXObjectGroup * TMXTiledMap::getObjectGroup(const std::string& groupName) const{    CCASSERT(groupName.size() > 0, "Invalid group name!");    if (_objectGroups.size()>0)    {        TMXObjectGroup* objectGroup = nullptr;        for (auto iter = _objectGroups.cbegin(); iter != _objectGroups.cend(); ++iter)        {            objectGroup = *iter;            if (objectGroup && objectGroup->getGroupName() == groupName)            {                return objectGroup;            }        }    }    // objectGroup not found    return nullptr;}Value TMXTiledMap::getProperty(const std::string& propertyName) const{    if (_properties.find(propertyName) != _properties.end())        return _properties.at(propertyName);        return Value();}Value TMXTiledMap::getPropertiesForGID(int GID) const{    if (_tileProperties.find(GID) != _tileProperties.end())        return _tileProperties.at(GID);        return Value();}bool TMXTiledMap::getPropertiesForGID(int GID, Value** value){    if (_tileProperties.find(GID) != _tileProperties.end()) {        *value = &_tileProperties.at(GID);        return true;    } else {        return false;    }}std::string TMXTiledMap::getDescription() const{    return StringUtils::format("<TMXTiledMap | Tag = %d, Layers = %d", _tag, static_cast<int>(_children.size()));}NS_CC_END

通过上面代码解析,可以看到TMXMap依据路径创建Info数据结构,然后TMXLayer通过Info数据结构生成Layer。很多人会忽略掉一个层只能使用一个地图集的限制,具体意思是指比如说一个层,引用了一个图块集后,我再引用不同的一个地图集,两个地图集的图块放置在同一层上,程序会报错,tiled规范不允许这样做。


TMXLayer.h

#ifndef __CCTMX_LAYER_H__#define __CCTMX_LAYER_H__#include "CCTMXObjectGroup.h"#include "CCAtlasNode.h"#include "CCSpriteBatchNode.h"#include "CCTMXXMLParser.h"#include "ccCArray.h"NS_CC_BEGINclass TMXMapInfo;class TMXLayerInfo;class TMXTilesetInfo;struct _ccCArray;/** TMXLayer是SpriteBathNode的子类,并非Layer子类。图块的渲染使用TextureAtlas如果在程序运行时修改了图块,然后,图块会变成Sprite,否则没有Sprite产生这就意味着图块能够像Sprite一样放大缩小旋转等等操作层包含了一个叫做cc_vertexz属性,层会使用这个属性当做Opengl渲染的z轴深度值从另外一个方面来说 如果cc_vertexz是一个automatic(自动)值,图块也就拥有了一个自动变化的z轴值所有属于这个层的图块都会把这个值当做z轴值同时在图块被绘制之前,GL_ALPHA_TEST会开启,在绘制完毕后关闭,用于alpha功能实现glAlphaFunc( GL_GREATER, value )alpha的值可以时0,你也可以变更它,使用地图层的属性cc_alpha_func设置,手法与cc_vertexz一致默认数值为0*/class CC_DLL TMXLayer : public SpriteBatchNode{public:    /** 静态方法 依据tiled ,Layer ,map数据结构生成Layer */    static TMXLayer * create(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo);    TMXLayer();    virtual ~TMXLayer();    /** 使用tiled ,layer ,map数据初始化 这类手法在cocos太常见了 */    bool initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo);    /** 释放地图 一般不用管其中的实现 因为引擎已经封装好了 不懂的可以去看cocos2d-x内存机制    */    void releaseMap();    /** 以Sprite的形式返回参数数据位置上的图块     返回的同时也会添加到TMXLayer中,不要反复添加    可以对返回Sprite进行Sprite操作    也可以删除     - layer->removeChild(sprite, cleanup);    - or layer->removeTileAt(Point(x,y));    */    Sprite* getTileAt(const Point& tileCoordinate);    CC_DEPRECATED_ATTRIBUTE Sprite* tileAt(const Point& tileCoordinate) { return getTileAt(tileCoordinate); };        /** 根据地址返回图块gid,前提条件时map没有被显式释放     */    uint32_t getTileGIDAt(const Point& tileCoordinate, TMXTileFlags* flags = nullptr);    CC_DEPRECATED_ATTRIBUTE uint32_t tileGIDAt(const Point& tileCoordinate, TMXTileFlags* flags = nullptr){        return getTileGIDAt(tileCoordinate, flags);    };    /** 设置gid    */    void setTileGID(uint32_t gid, const Point& tileCoordinate);    /** 同上     */    void setTileGID(uint32_t gid, const Point& tileCoordinate, TMXTileFlags flags);    /** 移除一个地图块 */    void removeTileAt(const Point& tileCoordinate);    /** 以像素点为单位返回指定地图点上的位置 */    Point getPositionAt(const Point& tileCoordinate);    CC_DEPRECATED_ATTRIBUTE Point positionAt(const Point& tileCoordinate) { return getPositionAt(tileCoordinate); };    /** 返回属性的值 */    Value getProperty(const std::string& propertyName) const;    CC_DEPRECATED_ATTRIBUTE Value propertyNamed(const std::string& propertyName) const { return getProperty(propertyName); };    /** 标题  */    void setupTiles();    inline const std::string& getLayerName(){ return _layerName; }    inline void setLayerName(const std::string& layerName){ _layerName = layerName; }    /** size of the layer in tiles */    inline const Size& getLayerSize() const { return _layerSize; };    inline void setLayerSize(const Size& size) { _layerSize = size; };        /** 获取和设置图块大小 */    inline const Size& getMapTileSize() const { return _mapTileSize; };    inline void setMapTileSize(const Size& size) { _mapTileSize = size; };         uint32_t* getTiles() const { return _tiles; };    void setTiles(uint32_t* tiles) { _tiles = tiles; };        /** 返回层的数据 */    inline TMXTilesetInfo* getTileSet() const { return _tileSet; };    inline void setTileSet(TMXTilesetInfo* info) {        CC_SAFE_RETAIN(info);        CC_SAFE_RELEASE(_tileSet);        _tileSet = info;    };        /** 层的旋转角度 */    inline int getLayerOrientation() const { return _layerOrientation; };    inline void setLayerOrientation(int orientation) { _layerOrientation = orientation; };        /** 返回属性集 */    inline const ValueMap& getProperties() const { return _properties; };    inline ValueMap& getProperties() { return _properties; };    inline void setProperties(const ValueMap& properties) {        _properties = properties;    };    //    // Override    //    /**TMXLayer不支持添加Sprite,替代使用setTiledGID()      */    using SpriteBatchNode::addChild;    virtual void addChild(Node * child, int zOrder, int tag) override;    // super method    void removeChild(Node* child, bool cleanup) override;    virtual std::string getDescription() const override;private:// 私有方法主要是对内的操作    Point getPositionForIsoAt(const Point& pos);    Point getPositionForOrthoAt(const Point& pos);    Point getPositionForHexAt(const Point& pos);    Point calculateLayerOffset(const Point& offset);    /* 数据结构操作方法 */    Sprite* appendTileForGID(uint32_t gid, const Point& pos);    Sprite* insertTileForGID(uint32_t gid, const Point& pos);    Sprite* updateTileForGID(uint32_t gid, const Point& pos);    /* 解析属性 */    void parseInternalProperties();    void setupTileSprite(Sprite* sprite, Point pos, int gid);    Sprite* reusedTileWithRect(Rect rect);    int getVertexZForPos(const Point& pos);    // index    ssize_t atlasIndexForExistantZ(int z);    ssize_t atlasIndexForNewZ(int z);    protected:    //! 层的名字 相当于ID 在Map getlayer有明确使用    std::string _layerName;    //! TMX Layer supports opacity    unsigned char        _opacity;        //! 整个层的层级 以及是否使用自动变更层级    int                    _vertexZvalue;    bool                _useAutomaticVertexZ;    //! 供数据结构使用    Sprite            *_reusedTile;    ccCArray            *_atlasIndexArray;        // retina 效果    float               _contentScaleFactor;        /** 层的大小 */    Size _layerSize;    /** 地图的大小 */    Size _mapTileSize;    /** 指向地图块 */    uint32_t* _tiles;    /** 层的数据结构 */    TMXTilesetInfo* _tileSet;    /** 层的朝向 与地图的朝向原理一致*/    int _layerOrientation;    /** 属性 */    ValueMap _properties;};NS_CC_END#endif //__CCTMX_LAYER_H__
从头文件可以看到Layer对外的接口,Layer继承自SpriteBatchNode,大家都知道SpriteBatchNode的作用吧,不懂的自己去搜,SpriteBatchNode里面主要有Texture2D对象和一个存储要渲染的数组,实现大批次渲染。


下面是cpp的解析

TMXLayer * TMXLayer::create(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo){    TMXLayer *ret = new TMXLayer();    if (ret->initWithTilesetInfo(tilesetInfo, layerInfo, mapInfo))    {        ret->autorelease();        return ret;    }    return nullptr;}

转入bool TMXLayer::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo)

bool TMXLayer::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo){        // XXX: is 35% a good estimate ?    Size size = layerInfo->_layerSize;    float totalNumberOfTiles = size.width * size.height;    float capacity = totalNumberOfTiles * 0.35f + 1; // 35 percent is occupied ?// texture加载地图集图块,一个层只有一个地图集    Texture2D *texture = nullptr;    if( tilesetInfo )    {        texture = Director::getInstance()->getTextureCache()->addImage(tilesetInfo->_sourceImage.c_str());    }// 加载相关的地图信息    if (SpriteBatchNode::initWithTexture(texture, static_cast<ssize_t>(capacity)))    {        // 地图层数据        _layerName = layerInfo->_name;        _layerSize = size;        _tiles = layerInfo->_tiles;        _opacity = layerInfo->_opacity;        setProperties(layerInfo->getProperties());        _contentScaleFactor = Director::getInstance()->getContentScaleFactor();         // 地图图块数据        _tileSet = tilesetInfo;        CC_SAFE_RETAIN(_tileSet);        // 地图数据        _mapTileSize = mapInfo->getTileSize();        _layerOrientation = mapInfo->getOrientation();        // 地图层偏移        Point offset = this->calculateLayerOffset(layerInfo->_offset);        this->setPosition(CC_POINT_PIXELS_TO_POINTS(offset));        _atlasIndexArray = ccCArrayNew(totalNumberOfTiles);        this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(Size(_layerSize.width * _mapTileSize.width, _layerSize.height * _mapTileSize.height)));        _useAutomaticVertexZ = false;        _vertexZvalue = 0;                return true;    }    return false;}

加载完成地图层信息后,进入下一个函数    layer->setupTiles();// 放置地图集中的图块

关键部分

            if (gid != 0)             {                this->appendTileForGID(gid, Point(x, y));            }

跳入appendTileForGID函数中setupTileSprite函数是对精灵进行一些位置等等设置。

接下来比较关键的代码是这段

        insertQuadFromSprite(tile, indexForZ); //tled是精灵

从这段代码转入SpriteBatchNode,成功进行添加。


PS:当地图层设置为不可见时,地图的设置信息还是会加载,但是图层不会生成TMXLayer

代码void TMXTiledMap::buildWithMapInfo(TMXMapInfo* mapInfo)中

    auto& layers = mapInfo->getLayers();    for(const auto &layerInfo : layers) {        if (layerInfo->_visible)        {







0 0
原创粉丝点击