diff --git a/cocos/2d/CCTMXLayer.cpp b/cocos/2d/CCTMXLayer.cpp index f4bc2ee17da7..546cb8b2e9c3 100644 --- a/cocos/2d/CCTMXLayer.cpp +++ b/cocos/2d/CCTMXLayer.cpp @@ -220,9 +220,18 @@ void TMXLayer::setupTiles() if (gid != 0) { this->appendTileForGID(gid, Vec2(newX, y)); + if(_tileSet->_animationInfo.at(gid)) + { + _animTileCoord[gid].push_back(Vec2(newX, y)); + } } } } + if(hasTileAnimation()) + { + _tileAnimManager = TMXTileAnimManager::create(this); + CC_SAFE_RETAIN(_tileAnimManager); + } } // TMXLayer - Properties @@ -843,5 +852,97 @@ std::string TMXLayer::getDescription() const return StringUtils::format("", _tag, (int)_mapTileSize.width, (int)_mapTileSize.height); } +TMXTileAnimManager::TMXTileAnimManager(TMXLayer *layer) +{ + _layer = layer; + for(const auto &p : *_layer->getAnimTileCoord()) + { + for(auto tilePos : p.second) + { + _tasks.pushBack(TMXTileAnimTask::create(_layer, _layer->getTileSet()->_animationInfo.at(p.first), tilePos)); + } + } +} + +TMXTileAnimManager *TMXTileAnimManager::create(TMXLayer *layer) +{ + TMXTileAnimManager *ret = new (std::nothrow) TMXTileAnimManager(layer); + if (ret) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +void TMXTileAnimManager::startAll() +{ + if(_started || _tasks.empty()) + return; + _started = true; + for(auto &task : _tasks) + { + task->start(); + } +} + +void TMXTileAnimManager::stopAll() +{ + if(!_started) + return; + _started = false; + for(auto &task : _tasks) + { + task->stop(); + } +} + +TMXTileAnimTask::TMXTileAnimTask(TMXLayer *layer, TMXTileAnimInfo *animation, const Vec2 &tilePos) +{ + _layer = layer; + _animation = animation; + _frameCount = static_cast(_animation->_frames.size()); + _tilePosition = tilePos; + std::stringstream ss; + ss << "TickAnimOnTilePos(" << _tilePosition.x << "," << _tilePosition.y << ")"; + _key = ss.str(); +} + +void TMXTileAnimTask::tickAndScheduleNext(float dt) +{ + setCurrFrame(); + _layer->getParent()->scheduleOnce(CC_CALLBACK_1(TMXTileAnimTask::tickAndScheduleNext, this), _animation->_frames[_currentFrame]._duration/1000.0f, _key); +} + +void TMXTileAnimTask::start() +{ + _isRunning = true; + tickAndScheduleNext(0.0f); +} + +void TMXTileAnimTask::stop() +{ + _isRunning = false; + _layer->getParent()->unschedule(_key); +} + +void TMXTileAnimTask::setCurrFrame() +{ + _layer->setTileGID(_animation->_frames[_currentFrame]._tileID, _tilePosition); + _currentFrame = (_currentFrame + 1) % _frameCount; +} + +TMXTileAnimTask *TMXTileAnimTask::create(TMXLayer *layer, TMXTileAnimInfo *animation, const Vec2 &tilePos) +{ + TMXTileAnimTask *ret = new (std::nothrow) TMXTileAnimTask(layer, animation, tilePos); + if (ret) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} NS_CC_END diff --git a/cocos/2d/CCTMXLayer.h b/cocos/2d/CCTMXLayer.h index 4b3705495ad3..59f8a338ec38 100644 --- a/cocos/2d/CCTMXLayer.h +++ b/cocos/2d/CCTMXLayer.h @@ -36,6 +36,7 @@ NS_CC_BEGIN class TMXMapInfo; class TMXLayerInfo; class TMXTilesetInfo; +class TMXTileAnimManager; struct _ccCArray; /** @@ -276,6 +277,22 @@ class CC_DLL TMXLayer : public SpriteBatchNode */ virtual std::string getDescription() const override; + /** Map from gid of animated tile to its instance. + * + * @return Map from gid of animated tile to its instance. + */ + const std::map>* getAnimTileCoord() { + return &_animTileCoord; + } + + bool hasTileAnimation() const { + return !_animTileCoord.empty(); + } + + TMXTileAnimManager* getTileAnimManager() const { + return _tileAnimManager; + } + protected: Vec2 getPositionForIsoAt(const Vec2& pos); Vec2 getPositionForOrthoAt(const Vec2& pos); @@ -337,6 +354,72 @@ class CC_DLL TMXLayer : public SpriteBatchNode ValueMap _properties; }; + /** map from gid of animated tile to its instance. Also useful for optimization*/ + std::map> _animTileCoord; + /** pointer to the tile animation manager of this layer */ + TMXTileAnimManager *_tileAnimManager = nullptr; +}; + +/** @brief TMXTileAnimTask represents the frame-tick task of an animated tile. + * It is a assistant class for TMXTileAnimTicker. + */ +class CC_DLL TMXTileAnimTask : public Ref +{ +public: + TMXTileAnimTask(TMXLayer *layer, TMXTileAnimInfo *animation, const Vec2 &tilePos); + static TMXTileAnimTask * create(TMXLayer *layer, TMXTileAnimInfo *animation, const Vec2 &tilePos); + /** start the animation task */ + void start(); + /** stop the animation task */ + void stop(); + bool isRunning() const { + return _isRunning; + } + +protected: + /** set texture of tile to current frame */ + void setCurrFrame(); + /** tick to next frame and schedule next tick */ + void tickAndScheduleNext(float dt); + + bool _isRunning = false; + /** key of schedule task for specific animated tile */ + std::string _key; + TMXLayer *_layer = nullptr; + /** position of the animated tile */ + Vec2 _tilePosition; + /** AnimationInfo on this tile */ + TMXTileAnimInfo *_animation = nullptr; + /** Index of the frame that should be drawn currently */ + uint32_t _currentFrame = 0; + uint32_t _frameCount = 0; +}; + +/** @brief TMXTileAnimManager controls all tile animation of a layer. + */ +class CC_DLL TMXTileAnimManager : public Ref +{ +public: + static TMXTileAnimManager * create(TMXLayer *layer); + explicit TMXTileAnimManager(TMXLayer *layer); + + /** start all tile animations */ + void startAll(); + /** stop all tile animations */ + void stopAll(); + + /** get vector of tasks */ + const Vector& getTasks() const { + return _tasks; + } + +protected: + bool _started = false; + /** vector contains all tasks of this layer */ + Vector _tasks; + TMXLayer* _layer = nullptr; +}; + // end of tilemap_parallax_nodes group /** @} */ diff --git a/cocos/2d/CCTMXTiledMap.cpp b/cocos/2d/CCTMXTiledMap.cpp index bfe6a04b5fff..6c3e8200ab87 100644 --- a/cocos/2d/CCTMXTiledMap.cpp +++ b/cocos/2d/CCTMXTiledMap.cpp @@ -273,4 +273,22 @@ int TMXTiledMap::getLayerNum() return _tmxLayerNum; } +void TMXTiledMap::setTileAnimEnabled(bool enabled) +{ + for (auto& child : _children) + { + TMXLayer* layer = dynamic_cast(child); + if(layer) + { + if(layer->hasTileAnimation()) + { + if(enabled) + layer->getTileAnimManager()->startAll(); + else + layer->getTileAnimManager()->stopAll(); + } + } + } +} + NS_CC_END diff --git a/cocos/2d/CCTMXTiledMap.h b/cocos/2d/CCTMXTiledMap.h index 1db62c9cf130..3ba897b6aa8e 100644 --- a/cocos/2d/CCTMXTiledMap.h +++ b/cocos/2d/CCTMXTiledMap.h @@ -260,6 +260,12 @@ class CC_DLL TMXTiledMap : public Node int getLayerNum(); const std::string& getResourceFile() const { return _tmxFile; } + /** Set all tile animations enabled or not. + * animations are not enabled by default + */ + void setTileAnimEnabled(bool enabled); + + CC_CONSTRUCTOR_ACCESS: /** * @js ctor diff --git a/cocos/2d/CCTMXXMLParser.cpp b/cocos/2d/CCTMXXMLParser.cpp index 93e8bfb6eadf..ae55e553c225 100644 --- a/cocos/2d/CCTMXXMLParser.cpp +++ b/cocos/2d/CCTMXXMLParser.cpp @@ -665,6 +665,19 @@ void TMXMapInfo::startElement(void* /*ctx*/, const char *name, const char **atts dict["polylinePoints"] = Value(pointsArray); } } + else if(elementName == "animation") + { + TMXTilesetInfo* info = tmxMapInfo->getTilesets().back(); + info->_animationInfo.insert(tmxMapInfo->getParentGID(), TMXTileAnimInfo::create(tmxMapInfo->getParentGID())); + tmxMapInfo->setParentElement(TMXPropertyAnimation); + } + else if(elementName == "frame") + { + TMXTilesetInfo* info = tmxMapInfo->getTilesets().back(); + auto animInfo = info->_animationInfo.at(tmxMapInfo->getParentGID()); + // calculate gid of frame + animInfo->_frames.emplace_back(TMXTileAnimFrame(info->_firstGid + attributeDict["tileid"].asInt(), attributeDict["duration"].asFloat())); + } } void TMXMapInfo::endElement(void* /*ctx*/, const char *name) @@ -791,6 +804,10 @@ void TMXMapInfo::endElement(void* /*ctx*/, const char *name) { _recordFirstGID = true; } + else if (elementName == "animation") + { + tmxMapInfo->setParentElement(TMXPropertyNone); + } } void TMXMapInfo::textHandler(void* /*ctx*/, const char *ch, size_t len) @@ -806,4 +823,27 @@ void TMXMapInfo::textHandler(void* /*ctx*/, const char *ch, size_t len) } } +TMXTileAnimFrame::TMXTileAnimFrame(uint32_t tileID, float duration) +: _tileID(tileID) +, _duration(duration) +{ +} + +TMXTileAnimInfo::TMXTileAnimInfo(uint32_t tileID) +: _tileID(tileID) +{ +} + +TMXTileAnimInfo *TMXTileAnimInfo::create(uint32_t tileID) +{ + TMXTileAnimInfo *ret = new (std::nothrow) TMXTileAnimInfo(tileID); + if (ret) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + NS_CC_END diff --git a/cocos/2d/CCTMXXMLParser.h b/cocos/2d/CCTMXXMLParser.h index 1b25d029eb15..047b34d6fe1a 100644 --- a/cocos/2d/CCTMXXMLParser.h +++ b/cocos/2d/CCTMXXMLParser.h @@ -36,6 +36,7 @@ THE SOFTWARE. #include "platform/CCSAXParser.h" #include "base/CCVector.h" #include "base/CCValue.h" +#include "base/CCMap.h" #include "2d/CCTMXObjectGroup.h" // needed for Vector for binding #include @@ -72,7 +73,9 @@ enum { TMXPropertyLayer, TMXPropertyObjectGroup, TMXPropertyObject, - TMXPropertyTile + TMXPropertyTile, + TMXPropertyTile, + TMXPropertyAnimation }; typedef enum TMXTileFlags_ { @@ -119,6 +122,35 @@ class CC_DLL TMXLayerInfo : public Ref Vec2 _offset; }; +/** @brief TMXTileAnimFrame contains the information about the frame of a animated tile like: +- Frame gid +- duration of this frame + +This information is obtained from the TMX file. +*/ +struct CC_DLL TMXTileAnimFrame +{ + TMXTileAnimFrame(uint32_t tileID, float duration); + /** gid of the frame */ + uint32_t _tileID = 0; + /** duration of the frame */ + float _duration = 0.0f; +}; + +/** @brief TMXTileAnimInfo contains the information about the animated tile like: +- Animated Tile gid +- frames the animated tile contains + +This information is obtained from the TMX file. +*/ +struct CC_DLL TMXTileAnimInfo : public Ref +{ + static TMXTileAnimInfo * create(uint32_t tileID); + explicit TMXTileAnimInfo(uint32_t tileID); + uint32_t _tileID = 0; + std::vector _frames; +}; + /** @brief TMXTilesetInfo contains the information about the tilesets like: - Tileset name - Tileset spacing @@ -143,6 +175,9 @@ class CC_DLL TMXTilesetInfo : public Ref //! size in pixels of the image Size _imageSize; std::string _originSourceImage; + //! map from gid of animated tile to its animation info + Map _animationInfo; + public: /** diff --git a/tests/cpp-tests/Resources/TileMaps/tile_animation_test.tmx b/tests/cpp-tests/Resources/TileMaps/tile_animation_test.tmx new file mode 100644 index 000000000000..68c99dd5aa9e --- /dev/null +++ b/tests/cpp-tests/Resources/TileMaps/tile_animation_test.tmx @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + eJyTY2BgkBvFgwYDAEFHC7k= + + + + + eJxjYCAeMBLAtFI3kgAAHeAAGQ== + + + + + eJxjYBg+gIkAppU6agIAHDAAMQ== + + + \ No newline at end of file