Sync missing feature from v3, and API compatible

This commit is contained in:
halx99 2020-08-28 16:33:52 +08:00
parent ae99a5965b
commit 8b7505e171
9 changed files with 409 additions and 3 deletions

View File

@ -93,6 +93,8 @@ bool FastTMXLayer::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo
// mapInfo
_mapTileSize = mapInfo->getTileSize();
_layerOrientation = mapInfo->getOrientation();
_staggerAxis = mapInfo->getStaggerAxis();
_staggerIndex = mapInfo->getStaggerIndex();
// offset (after layer orientation is set);
Vec2 offset = this->calculateLayerOffset(layerInfo->_offset);
@ -321,6 +323,57 @@ void FastTMXLayer::setupTiles()
_screenTileCount = (int)(_screenGridSize.width * _screenGridSize.height);
if (!_tileSet->_animationInfo.empty()) {
/// FastTMXLayer: anim support
for (int y = 0; y < _layerSize.height; y++)
{
for (int x = 0; x < _layerSize.width; x++)
{
int newX = x;
// fix correct render ordering in Hexagonal maps when stagger axis == x
if (_staggerAxis == TMXStaggerAxis_X && _layerOrientation == TMXOrientationHex)
{
if (_staggerIndex == TMXStaggerIndex_Odd)
{
if (x >= _layerSize.width / 2)
newX = (x - std::ceil(_layerSize.width / 2)) * 2 + 1;
else
newX = x * 2;
}
else {
// TMXStaggerIndex_Even
if (x >= static_cast<int>(_layerSize.width / 2))
newX = (x - static_cast<int>(_layerSize.width / 2)) * 2;
else
newX = x * 2 + 1;
}
}
int pos = static_cast<int>(newX + _layerSize.width * y);
int gid = _tiles[pos];
// gid are stored in little endian.
// if host is big endian, then swap
//if( o == CFByteOrderBigEndian )
// gid = CFSwapInt32( gid );
/* We support little endian.*/
// FIXME:: gid == 0 --> empty tile
if (gid != 0)
{
if (_tileSet->_animationInfo.find(gid) != _tileSet->_animationInfo.end())
{
_animTileCoord[gid].push_back(Vec2(newX, y));
}
}
}
}
if (hasTileAnimation())
{
_tileAnimManager = new TMXTileAnimManager(this);
}
}
}
Mat4 FastTMXLayer::tileToNodeTransform()
@ -910,5 +963,97 @@ std::string FastTMXLayer::getDescription() const
return StringUtils::format("<FastTMXLayer | tag = %d, size = %d,%d>", _tag, (int)_mapTileSize.width, (int)_mapTileSize.height);
}
TMXTileAnimManager::TMXTileAnimManager(FastTMXLayer* 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(FastTMXLayer* 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(FastTMXLayer* layer, TMXTileAnimInfo* animation, const Vec2& tilePos)
{
_layer = layer;
_animation = animation;
_frameCount = static_cast<uint32_t>(_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(FastTMXLayer* 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

View File

@ -37,6 +37,7 @@ NS_CC_BEGIN
class TMXMapInfo;
class TMXLayerInfo;
class TMXTilesetInfo;
class TMXTileAnimManager;
class Texture2D;
class Sprite;
@ -275,6 +276,21 @@ public:
virtual void draw(Renderer *renderer, const Mat4& transform, uint32_t flags) override;
void removeChild(Node* child, bool cleanup = true) override;
/** Map from gid of animated tile to its instance.
*
* @return Map from gid of animated tile to its instance.
*/
const std::unordered_map<uint32_t, std::vector<Vec2>>* getAnimTileCoord() {
return &_animTileCoord;
}
bool hasTileAnimation() const {
return !_animTileCoord.empty();
}
TMXTileAnimManager* getTileAnimManager() const {
return _tileAnimManager;
}
protected:
virtual void setOpacity(uint8_t opacity) override;
@ -315,9 +331,16 @@ protected:
TMXTilesetInfo* _tileSet = nullptr;
/** Layer orientation, which is the same as the map orientation */
int _layerOrientation = FAST_TMX_ORIENTATION_ORTHO;
int _staggerAxis = TMXStaggerAxis_Y;
int _staggerIndex = TMXStaggerIndex_Even;
/** properties from the layer. They can be added using Tiled */
ValueMap _properties;
/** map from gid of animated tile to its instance. Also useful for optimization*/
std::unordered_map<uint32_t, std::vector<Vec2>> _animTileCoord;
/** pointer to the tile animation manager of this layer */
TMXTileAnimManager* _tileAnimManager = nullptr;
Texture2D *_texture = nullptr;
/** container for sprite children. map<index, pair<sprite, gid> > */
@ -356,6 +379,69 @@ protected:
backend::UniformLocation _alphaValueLocation;
};
/** @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(FastTMXLayer* layer, TMXTileAnimInfo* animation, const Vec2& tilePos);
static TMXTileAnimTask* create(FastTMXLayer* 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;
FastTMXLayer* _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(FastTMXLayer* layer);
explicit TMXTileAnimManager(FastTMXLayer* layer);
/** start all tile animations */
void startAll();
/** stop all tile animations */
void stopAll();
/** get vector of tasks */
const Vector<TMXTileAnimTask*>& getTasks() const {
return _tasks;
}
protected:
bool _started = false;
/** vector contains all tasks of this layer */
Vector<TMXTileAnimTask*> _tasks;
FastTMXLayer* _layer = nullptr;
};
// @API compatible
typedef FastTMXLayer TMXLayer;
// end of tilemap_parallax_nodes group
/// @}
NS_CC_END

View File

@ -257,4 +257,22 @@ std::string FastTMXTiledMap::getDescription() const
return StringUtils::format("<FastTMXTiledMap | Tag = %d, Layers = %d", _tag, static_cast<int>(_children.size()));
}
void FastTMXTiledMap::setTileAnimEnabled(bool enabled)
{
for (auto& child : _children)
{
FastTMXLayer* layer = dynamic_cast<FastTMXLayer*>(child);
if (layer)
{
if (layer->hasTileAnimation())
{
if (enabled)
layer->getTileAnimManager()->startAll();
else
layer->getTileAnimManager()->stopAll();
}
}
}
}
NS_CC_END

View File

@ -201,6 +201,10 @@ public:
virtual std::string getDescription() const override;
/** Set all tile animations enabled or not.
* animations are not enabled by default
*/
void setTileAnimEnabled(bool enabled);
protected:
/**
* @js ctor
@ -243,6 +247,8 @@ private:
// end of tilemap_parallax_nodes group
/** @} */
// @API compatible
typedef FastTMXTiledMap TMXTiledMap;
NS_CC_END

View File

@ -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)
@ -785,6 +798,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)
@ -800,4 +817,28 @@ 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

View File

@ -35,6 +35,7 @@ THE SOFTWARE.
#include "math/CCGeometry.h"
#include "platform/CCSAXParser.h"
#include "base/CCVector.h"
#include "base/CCMap.h"
#include "base/CCValue.h"
#include "2d/CCTMXObjectGroup.h" // needed for Vector<TMXObjectGroup*> for binding
@ -72,7 +73,8 @@ enum {
TMXPropertyLayer,
TMXPropertyObjectGroup,
TMXPropertyObject,
TMXPropertyTile
TMXPropertyTile,
TMXPropertyAnimation
};
typedef enum TMXTileFlags_ {
@ -125,6 +127,35 @@ enum
TMXStaggerIndex_Even,
};
/** @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<TMXTileAnimFrame> _frames;
};
// Bits on the far end of the 32-bit global tile ID (GID's) are used for tile flags
/** @brief TMXLayerInfo contains the information about the layers like:
@ -185,7 +216,8 @@ public:
//! size in pixels of the image
Size _imageSize;
std::string _originSourceImage;
//! map from gid of animated tile to its animation info
Map<uint32_t, TMXTileAnimInfo*> _animationInfo;
public:
/**
* @js ctor

View File

@ -66,6 +66,7 @@ FastTileMapTests::FastTileMapTests()
ADD_TEST_CASE(TMXBug987New);
ADD_TEST_CASE(TMXBug787New);
ADD_TEST_CASE(TMXGIDObjectsTestNew);
ADD_TEST_CASE(TileAnimTestNew);
}
TileDemoNew::TileDemoNew()
@ -1386,3 +1387,35 @@ std::string TMXGIDObjectsTestNew::subtitle() const
{
return "Tiles are created from an object group";
}
//------------------------------------------------------------------
//
// TileAnimTestNew
//
//------------------------------------------------------------------
TileAnimTestNew::TileAnimTestNew()
{
map = FastTMXTiledMap::create("TileMaps/tile_animation_test.tmx");
addChild(map, 0, kTagTileMap);
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(TileAnimTestNew::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
Size CC_UNUSED s = map->getContentSize();
CCLOG("ContentSize: %f, %f", s.width, s.height);
map->setTileAnimEnabled(_animStarted);
}
std::string TileAnimTestNew::title() const
{
return "Tile animation test. Click to toggle the animation";
}
void TileAnimTestNew::onTouchBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
_animStarted = !_animStarted;
map->setTileAnimEnabled(_animStarted);
}

View File

@ -334,4 +334,16 @@ public:
virtual std::string subtitle() const override;
};
class TileAnimTestNew : public TileDemoNew
{
public:
CREATE_FUNC(TileAnimTestNew);
TileAnimTestNew();
virtual std::string title() const override;
cocos2d::FastTMXTiledMap* map;
bool _animStarted = true;
void onTouchBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event);
};
#endif

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.2.5" orientation="orthogonal" renderorder="right-down" width="10" height="10" tilewidth="32" tileheight="32" infinite="0" nextlayerid="4" nextobjectid="1">
<tileset firstgid="1" name="tileset" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
<image source="./tmw_desert_spacing.png" width="265" height="199"/>
<tile id="0">
<animation>
<frame tileid="37" duration="200"/>
<frame tileid="39" duration="200"/>
</animation>
</tile>
<tile id="1">
<animation>
<frame tileid="46" duration="200"/>
<frame tileid="47" duration="200"/>
</animation>
</tile>
</tileset>
<layer id="1" name="Tile Layer 1" width="10" height="10">
<data encoding="base64" compression="zlib">
eJyTY2BgkBvFgwYDAEFHC7k=
</data>
</layer>
<layer id="2" name="Tile Layer 2" width="10" height="10">
<data encoding="base64" compression="zlib">
eJxjYCAeMBLAtFI3kgAAHeAAGQ==
</data>
</layer>
<layer id="3" name="Tile Layer 3" width="10" height="10">
<data encoding="base64" compression="zlib">
eJxjYBg+gIkAppU6agIAHDAAMQ==
</data>
</layer>
</map>