2012-04-19 14:35:52 +08:00
|
|
|
/****************************************************************************
|
2012-09-24 21:22:20 +08:00
|
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
2012-04-19 14:35:52 +08:00
|
|
|
Copyright (c) 2009-2010 Ricardo Quesada
|
|
|
|
Copyright (c) 2011 Zynga Inc.
|
|
|
|
|
|
|
|
http://www.cocos2d-x.org
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "CCTMXLayer.h"
|
|
|
|
#include "CCTMXXMLParser.h"
|
|
|
|
#include "CCTMXTiledMap.h"
|
2012-06-19 16:20:46 +08:00
|
|
|
#include "sprite_nodes/CCSprite.h"
|
|
|
|
#include "textures/CCTextureCache.h"
|
|
|
|
#include "shaders/CCShaderCache.h"
|
|
|
|
#include "shaders/CCGLProgram.h"
|
|
|
|
#include "support/CCPointExtension.h"
|
2012-04-19 14:35:52 +08:00
|
|
|
#include "support/data_support/ccCArray.h"
|
|
|
|
#include "CCDirector.h"
|
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
|
|
|
|
|
|
|
|
// CCTMXLayer - init & alloc & dealloc
|
2012-06-14 15:13:16 +08:00
|
|
|
|
|
|
|
CCTMXLayer * CCTMXLayer::create(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCTMXLayer *pRet = new CCTMXLayer();
|
|
|
|
if (pRet->initWithTilesetInfo(tilesetInfo, layerInfo, mapInfo))
|
|
|
|
{
|
|
|
|
pRet->autorelease();
|
|
|
|
return pRet;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
bool CCTMXLayer::initWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
|
|
|
|
{
|
|
|
|
// XXX: is 35% a good estimate ?
|
2013-06-15 14:03:30 +08:00
|
|
|
CCSize size = layerInfo->_layerSize;
|
2012-04-19 14:35:52 +08:00
|
|
|
float totalNumberOfTiles = size.width * size.height;
|
|
|
|
float capacity = totalNumberOfTiles * 0.35f + 1; // 35 percent is occupied ?
|
|
|
|
|
|
|
|
CCTexture2D *texture = NULL;
|
|
|
|
if( tilesetInfo )
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
texture = CCTextureCache::sharedTextureCache()->addImage(tilesetInfo->_sourceImage.c_str());
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CCSpriteBatchNode::initWithTexture(texture, (unsigned int)capacity))
|
|
|
|
{
|
|
|
|
// layerInfo
|
2013-06-15 14:03:30 +08:00
|
|
|
_layerName = layerInfo->_name;
|
|
|
|
_layerSize = size;
|
|
|
|
_tiles = layerInfo->_tiles;
|
|
|
|
_minGID = layerInfo->_minGID;
|
|
|
|
_maxGID = layerInfo->_maxGID;
|
|
|
|
_opacity = layerInfo->_opacity;
|
2012-07-23 22:49:11 +08:00
|
|
|
setProperties(CCDictionary::createWithDictionary(layerInfo->getProperties()));
|
2013-06-15 14:03:30 +08:00
|
|
|
_contentScaleFactor = CCDirector::sharedDirector()->getContentScaleFactor();
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// tilesetInfo
|
2013-06-15 14:03:30 +08:00
|
|
|
_tileSet = tilesetInfo;
|
|
|
|
CC_SAFE_RETAIN(_tileSet);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// mapInfo
|
2013-06-15 14:03:30 +08:00
|
|
|
_mapTileSize = mapInfo->getTileSize();
|
|
|
|
_layerOrientation = mapInfo->getOrientation();
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// offset (after layer orientation is set);
|
2013-06-15 14:03:30 +08:00
|
|
|
CCPoint offset = this->calculateLayerOffset(layerInfo->_offset);
|
2012-04-19 14:35:52 +08:00
|
|
|
this->setPosition(CC_POINT_PIXELS_TO_POINTS(offset));
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
_atlasIndexArray = ccCArrayNew((unsigned int)totalNumberOfTiles);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(CCSizeMake(_layerSize.width * _mapTileSize.width, _layerSize.height * _mapTileSize.height)));
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
_useAutomaticVertexZ = false;
|
|
|
|
_vertexZvalue = 0;
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
CCTMXLayer::CCTMXLayer()
|
2013-06-15 14:03:30 +08:00
|
|
|
:_layerSize(CCSizeZero)
|
|
|
|
,_mapTileSize(CCSizeZero)
|
|
|
|
,_tiles(NULL)
|
|
|
|
,_tileSet(NULL)
|
|
|
|
,_properties(NULL)
|
|
|
|
,_layerName("")
|
|
|
|
,_reusedTile(NULL)
|
|
|
|
,_atlasIndexArray(NULL)
|
2012-04-19 14:35:52 +08:00
|
|
|
{}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
CCTMXLayer::~CCTMXLayer()
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CC_SAFE_RELEASE(_tileSet);
|
|
|
|
CC_SAFE_RELEASE(_reusedTile);
|
|
|
|
CC_SAFE_RELEASE(_properties);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_atlasIndexArray)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
ccCArrayFree(_atlasIndexArray);
|
|
|
|
_atlasIndexArray = NULL;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
CC_SAFE_DELETE_ARRAY(_tiles);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
CCTMXTilesetInfo * CCTMXLayer::getTileSet()
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return _tileSet;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
void CCTMXLayer::setTileSet(CCTMXTilesetInfo* var)
|
|
|
|
{
|
|
|
|
CC_SAFE_RETAIN(var);
|
2013-06-15 14:03:30 +08:00
|
|
|
CC_SAFE_RELEASE(_tileSet);
|
|
|
|
_tileSet = var;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
void CCTMXLayer::releaseMap()
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_tiles)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
delete [] _tiles;
|
|
|
|
_tiles = NULL;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_atlasIndexArray)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
ccCArrayFree(_atlasIndexArray);
|
|
|
|
_atlasIndexArray = NULL;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - setup Tiles
|
|
|
|
void CCTMXLayer::setupTiles()
|
|
|
|
{
|
|
|
|
// Optimization: quick hack that sets the image size on the tileset
|
2013-06-15 14:03:30 +08:00
|
|
|
_tileSet->_imageSize = _textureAtlas->getTexture()->getContentSizeInPixels();
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// By default all the tiles are aliased
|
|
|
|
// pros:
|
|
|
|
// - easier to render
|
|
|
|
// cons:
|
|
|
|
// - difficult to scale / rotate / etc.
|
2013-06-15 14:03:30 +08:00
|
|
|
_textureAtlas->getTexture()->setAliasTexParameters();
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
//CFByteOrder o = CFByteOrderGetCurrent();
|
|
|
|
|
|
|
|
// Parse cocos2d properties
|
|
|
|
this->parseInternalProperties();
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
for (unsigned int y=0; y < _layerSize.height; y++)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
for (unsigned int x=0; x < _layerSize.width; x++)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int pos = (unsigned int)(x + _layerSize.width * y);
|
|
|
|
unsigned int gid = _tiles[ pos ];
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// gid are stored in little endian.
|
|
|
|
// if host is big endian, then swap
|
|
|
|
//if( o == CFByteOrderBigEndian )
|
|
|
|
// gid = CFSwapInt32( gid );
|
|
|
|
/* We support little endian.*/
|
|
|
|
|
|
|
|
// XXX: gid == 0 --> empty tile
|
2012-08-20 14:06:29 +08:00
|
|
|
if (gid != 0)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
this->appendTileForGID(gid, ccp(x, y));
|
|
|
|
|
|
|
|
// Optimization: update min and max GID rendered by the layer
|
2013-06-15 14:03:30 +08:00
|
|
|
_minGID = MIN(gid, _minGID);
|
|
|
|
_maxGID = MAX(gid, _maxGID);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert( _maxGID >= _tileSet->_firstGid &&
|
|
|
|
_minGID >= _tileSet->_firstGid, "TMX: Only 1 tileset per layer is supported");
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - Properties
|
|
|
|
CCString* CCTMXLayer::propertyNamed(const char *propertyName)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return (CCString*)_properties->objectForKey(propertyName);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCTMXLayer::parseInternalProperties()
|
|
|
|
{
|
|
|
|
// if cc_vertex=automatic, then tiles will be rendered using vertexz
|
|
|
|
|
|
|
|
CCString *vertexz = propertyNamed("cc_vertexz");
|
2012-08-20 14:06:29 +08:00
|
|
|
if (vertexz)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
// If "automatic" is on, then parse the "cc_alpha_func" too
|
2013-06-15 14:03:30 +08:00
|
|
|
if (vertexz->_string == "automatic")
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_useAutomaticVertexZ = true;
|
2012-04-19 14:35:52 +08:00
|
|
|
CCString *alphaFuncVal = propertyNamed("cc_alpha_func");
|
|
|
|
float alphaFuncValue = 0.0f;
|
|
|
|
if (alphaFuncVal != NULL)
|
|
|
|
{
|
|
|
|
alphaFuncValue = alphaFuncVal->floatValue();
|
|
|
|
}
|
|
|
|
setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColorAlphaTest));
|
|
|
|
|
|
|
|
GLint alphaValueLocation = glGetUniformLocation(getShaderProgram()->getProgram(), kCCUniformAlphaTestValue);
|
|
|
|
|
|
|
|
// NOTE: alpha test shader is hard-coded to use the equivalent of a glAlphaFunc(GL_GREATER) comparison
|
|
|
|
getShaderProgram()->setUniformLocationWith1f(alphaValueLocation, alphaFuncValue);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_vertexZvalue = vertexz->intValue();
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCTMXLayer::setupTileSprite(CCSprite* sprite, CCPoint pos, unsigned int gid)
|
|
|
|
{
|
|
|
|
sprite->setPosition(positionAt(pos));
|
|
|
|
sprite->setVertexZ((float)vertexZForPos(pos));
|
|
|
|
sprite->setAnchorPoint(CCPointZero);
|
2013-06-15 14:03:30 +08:00
|
|
|
sprite->setOpacity(_opacity);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
//issue 1264, flip can be undone as well
|
2012-06-14 05:26:28 +08:00
|
|
|
sprite->setFlipX(false);
|
2013-04-17 06:01:22 +08:00
|
|
|
sprite->setFlipY(false);
|
2012-06-14 05:26:28 +08:00
|
|
|
sprite->setRotation(0.0f);
|
|
|
|
sprite->setAnchorPoint(ccp(0,0));
|
|
|
|
|
|
|
|
// Rotation in tiled is achieved using 3 flipped states, flipping across the horizontal, vertical, and diagonal axes of the tiles.
|
|
|
|
if (gid & kCCTMXTileDiagonalFlag)
|
|
|
|
{
|
|
|
|
// put the anchor in the middle for ease of rotation.
|
|
|
|
sprite->setAnchorPoint(ccp(0.5f,0.5f));
|
|
|
|
sprite->setPosition(ccp(positionAt(pos).x + sprite->getContentSize().height/2,
|
|
|
|
positionAt(pos).y + sprite->getContentSize().width/2 ) );
|
|
|
|
|
|
|
|
unsigned int flag = gid & (kCCTMXTileHorizontalFlag | kCCTMXTileVerticalFlag );
|
|
|
|
|
|
|
|
// handle the 4 diagonally flipped states.
|
|
|
|
if (flag == kCCTMXTileHorizontalFlag)
|
|
|
|
{
|
|
|
|
sprite->setRotation(90.0f);
|
|
|
|
}
|
|
|
|
else if (flag == kCCTMXTileVerticalFlag)
|
|
|
|
{
|
|
|
|
sprite->setRotation(270.0f);
|
|
|
|
}
|
|
|
|
else if (flag == (kCCTMXTileVerticalFlag | kCCTMXTileHorizontalFlag) )
|
|
|
|
{
|
|
|
|
sprite->setRotation(90.0f);
|
|
|
|
sprite->setFlipX(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprite->setRotation(270.0f);
|
|
|
|
sprite->setFlipX(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (gid & kCCTMXTileHorizontalFlag)
|
|
|
|
{
|
|
|
|
sprite->setFlipX(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gid & kCCTMXTileVerticalFlag)
|
|
|
|
{
|
|
|
|
sprite->setFlipY(true);
|
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CCSprite* CCTMXLayer::reusedTileWithRect(CCRect rect)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
if (! _reusedTile)
|
2012-08-20 14:06:29 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_reusedTile = new CCSprite();
|
|
|
|
_reusedTile->initWithTexture(_textureAtlas->getTexture(), rect, false);
|
|
|
|
_reusedTile->setBatchNode(this);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-14 18:05:15 +08:00
|
|
|
// XXX HACK: Needed because if "batch node" is nil,
|
|
|
|
// then the Sprite'squad will be reset
|
2013-06-15 14:03:30 +08:00
|
|
|
_reusedTile->setBatchNode(NULL);
|
2012-11-14 18:05:15 +08:00
|
|
|
|
|
|
|
// Re-init the sprite
|
2013-06-15 14:03:30 +08:00
|
|
|
_reusedTile->setTextureRect(rect, false, rect.size);
|
2012-11-14 18:05:15 +08:00
|
|
|
|
|
|
|
// restore the batch node
|
2013-06-15 14:03:30 +08:00
|
|
|
_reusedTile->setBatchNode(this);
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
return _reusedTile;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - obtaining tiles/gids
|
|
|
|
CCSprite * CCTMXLayer::tileAt(const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert(pos.x < _layerSize.width && pos.y < _layerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
|
|
|
|
CCAssert(_tiles && _atlasIndexArray, "TMXLayer: the tiles map has been released");
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
CCSprite *tile = NULL;
|
|
|
|
unsigned int gid = this->tileGIDAt(pos);
|
|
|
|
|
|
|
|
// if GID == 0, then no tile is present
|
2012-08-20 14:06:29 +08:00
|
|
|
if (gid)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
int z = (int)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
tile = (CCSprite*) this->getChildByTag(z);
|
|
|
|
|
|
|
|
// tile not created yet. create it
|
2012-08-20 14:06:29 +08:00
|
|
|
if (! tile)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCRect rect = _tileSet->rectForGID(gid);
|
2012-04-19 14:35:52 +08:00
|
|
|
rect = CC_RECT_PIXELS_TO_POINTS(rect);
|
|
|
|
|
|
|
|
tile = new CCSprite();
|
|
|
|
tile->initWithTexture(this->getTexture(), rect);
|
|
|
|
tile->setBatchNode(this);
|
|
|
|
tile->setPosition(positionAt(pos));
|
|
|
|
tile->setVertexZ((float)vertexZForPos(pos));
|
|
|
|
tile->setAnchorPoint(CCPointZero);
|
2013-06-15 14:03:30 +08:00
|
|
|
tile->setOpacity(_opacity);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
unsigned int indexForZ = atlasIndexForExistantZ(z);
|
|
|
|
this->addSpriteWithoutQuad(tile, indexForZ, z);
|
|
|
|
tile->release();
|
|
|
|
}
|
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return tile;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CCTMXLayer::tileGIDAt(const CCPoint& pos)
|
|
|
|
{
|
|
|
|
return tileGIDAt(pos, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CCTMXLayer::tileGIDAt(const CCPoint& pos, ccTMXTileFlags* flags)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert(pos.x < _layerSize.width && pos.y < _layerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
|
|
|
|
CCAssert(_tiles && _atlasIndexArray, "TMXLayer: the tiles map has been released");
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
int idx = (int)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
// Bits on the far end of the 32-bit global tile ID are used for tile flags
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int tile = _tiles[idx];
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// issue1264, flipped tiles can be changed dynamically
|
|
|
|
if (flags)
|
|
|
|
{
|
|
|
|
*flags = (ccTMXTileFlags)(tile & kCCFlipedAll);
|
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return (tile & kCCFlippedMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - adding helper methods
|
|
|
|
CCSprite * CCTMXLayer::insertTileForGID(unsigned int gid, const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCRect rect = _tileSet->rectForGID(gid);
|
2012-04-19 14:35:52 +08:00
|
|
|
rect = CC_RECT_PIXELS_TO_POINTS(rect);
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
intptr_t z = (intptr_t)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
CCSprite *tile = reusedTileWithRect(rect);
|
|
|
|
|
|
|
|
setupTileSprite(tile, pos, gid);
|
|
|
|
|
|
|
|
// get atlas index
|
|
|
|
unsigned int indexForZ = atlasIndexForNewZ(z);
|
|
|
|
|
|
|
|
// Optimization: add the quad without adding a child
|
2012-11-14 18:05:15 +08:00
|
|
|
this->insertQuadFromSprite(tile, indexForZ);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// insert it into the local atlasindex array
|
2013-06-15 14:03:30 +08:00
|
|
|
ccCArrayInsertValueAtIndex(_atlasIndexArray, (void*)z, indexForZ);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// update possible children
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_children && _children->count()>0)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCObject* pObject = NULL;
|
2013-06-15 14:03:30 +08:00
|
|
|
CCARRAY_FOREACH(_children, pObject)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCSprite* pChild = (CCSprite*) pObject;
|
|
|
|
if (pChild)
|
|
|
|
{
|
|
|
|
unsigned int ai = pChild->getAtlasIndex();
|
|
|
|
if ( ai >= indexForZ )
|
|
|
|
{
|
|
|
|
pChild->setAtlasIndex(ai+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-15 14:03:30 +08:00
|
|
|
_tiles[z] = gid;
|
2012-04-19 14:35:52 +08:00
|
|
|
return tile;
|
|
|
|
}
|
|
|
|
CCSprite * CCTMXLayer::updateTileForGID(unsigned int gid, const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCRect rect = _tileSet->rectForGID(gid);
|
|
|
|
rect = CCRectMake(rect.origin.x / _contentScaleFactor, rect.origin.y / _contentScaleFactor, rect.size.width/ _contentScaleFactor, rect.size.height/ _contentScaleFactor);
|
|
|
|
int z = (int)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
CCSprite *tile = reusedTileWithRect(rect);
|
|
|
|
|
|
|
|
setupTileSprite(tile ,pos ,gid);
|
|
|
|
|
|
|
|
// get atlas index
|
|
|
|
unsigned int indexForZ = atlasIndexForExistantZ(z);
|
|
|
|
tile->setAtlasIndex(indexForZ);
|
|
|
|
tile->setDirty(true);
|
|
|
|
tile->updateTransform();
|
2013-06-15 14:03:30 +08:00
|
|
|
_tiles[z] = gid;
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
return tile;
|
|
|
|
}
|
|
|
|
|
|
|
|
// used only when parsing the map. useless after the map was parsed
|
|
|
|
// since lot's of assumptions are no longer true
|
|
|
|
CCSprite * CCTMXLayer::appendTileForGID(unsigned int gid, const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCRect rect = _tileSet->rectForGID(gid);
|
2012-04-19 14:35:52 +08:00
|
|
|
rect = CC_RECT_PIXELS_TO_POINTS(rect);
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
intptr_t z = (intptr_t)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
CCSprite *tile = reusedTileWithRect(rect);
|
|
|
|
|
|
|
|
setupTileSprite(tile ,pos ,gid);
|
|
|
|
|
|
|
|
// optimization:
|
|
|
|
// The difference between appendTileForGID and insertTileforGID is that append is faster, since
|
|
|
|
// it appends the tile at the end of the texture atlas
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int indexForZ = _atlasIndexArray->num;
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// don't add it using the "standard" way.
|
2012-11-14 18:05:15 +08:00
|
|
|
insertQuadFromSprite(tile, indexForZ);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// append should be after addQuadFromSprite since it modifies the quantity values
|
2013-06-15 14:03:30 +08:00
|
|
|
ccCArrayInsertValueAtIndex(_atlasIndexArray, (void*)z, indexForZ);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
return tile;
|
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - atlasIndex and Z
|
|
|
|
static inline int compareInts(const void * a, const void * b)
|
|
|
|
{
|
2012-08-20 14:06:29 +08:00
|
|
|
return ((*(int*)a) - (*(int*)b));
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
unsigned int CCTMXLayer::atlasIndexForExistantZ(unsigned int z)
|
|
|
|
{
|
|
|
|
int key=z;
|
2013-06-15 14:03:30 +08:00
|
|
|
int *item = (int*)bsearch((void*)&key, (void*)&_atlasIndexArray->arr[0], _atlasIndexArray->num, sizeof(void*), compareInts);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2012-08-20 14:06:29 +08:00
|
|
|
CCAssert(item, "TMX atlas index not found. Shall not happen");
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
int index = ((size_t)item - (size_t)_atlasIndexArray->arr) / sizeof(void*);
|
2012-04-19 14:35:52 +08:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
unsigned int CCTMXLayer::atlasIndexForNewZ(int z)
|
|
|
|
{
|
|
|
|
// XXX: This can be improved with a sort of binary search
|
|
|
|
unsigned int i=0;
|
2013-06-15 14:03:30 +08:00
|
|
|
for (i=0; i< _atlasIndexArray->num ; i++)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
int val = (size_t) _atlasIndexArray->arr[i];
|
2012-08-20 14:06:29 +08:00
|
|
|
if (z < val)
|
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
break;
|
2012-08-20 14:06:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// CCTMXLayer - adding / remove tiles
|
|
|
|
void CCTMXLayer::setTileGID(unsigned int gid, const CCPoint& pos)
|
|
|
|
{
|
|
|
|
setTileGID(gid, pos, (ccTMXTileFlags)0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCTMXLayer::setTileGID(unsigned int gid, const CCPoint& pos, ccTMXTileFlags flags)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert(pos.x < _layerSize.width && pos.y < _layerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
|
|
|
|
CCAssert(_tiles && _atlasIndexArray, "TMXLayer: the tiles map has been released");
|
|
|
|
CCAssert(gid == 0 || gid >= _tileSet->_firstGid, "TMXLayer: invalid gid" );
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
ccTMXTileFlags currentFlags;
|
|
|
|
unsigned int currentGID = tileGIDAt(pos, ¤tFlags);
|
|
|
|
|
2012-08-20 14:06:29 +08:00
|
|
|
if (currentGID != gid || currentFlags != flags)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
unsigned gidAndFlags = gid | flags;
|
|
|
|
|
|
|
|
// setting gid=0 is equal to remove the tile
|
2012-08-20 14:06:29 +08:00
|
|
|
if (gid == 0)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
removeTileAt(pos);
|
|
|
|
}
|
|
|
|
// empty tile. create a new one
|
2012-08-20 14:06:29 +08:00
|
|
|
else if (currentGID == 0)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
insertTileForGID(gidAndFlags, pos);
|
|
|
|
}
|
|
|
|
// modifying an existing tile with a non-empty tile
|
|
|
|
else
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int z = (unsigned int)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
CCSprite *sprite = (CCSprite*)getChildByTag(z);
|
2012-08-20 14:06:29 +08:00
|
|
|
if (sprite)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCRect rect = _tileSet->rectForGID(gid);
|
2012-04-19 14:35:52 +08:00
|
|
|
rect = CC_RECT_PIXELS_TO_POINTS(rect);
|
|
|
|
|
|
|
|
sprite->setTextureRect(rect, false, rect.size);
|
|
|
|
if (flags)
|
|
|
|
{
|
|
|
|
setupTileSprite(sprite, sprite->getPosition(), gidAndFlags);
|
|
|
|
}
|
2013-06-15 14:03:30 +08:00
|
|
|
_tiles[z] = gidAndFlags;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
updateTileForGID(gidAndFlags, pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void CCTMXLayer::addChild(CCNode * child, int zOrder, int tag)
|
|
|
|
{
|
|
|
|
CC_UNUSED_PARAM(child);
|
|
|
|
CC_UNUSED_PARAM(zOrder);
|
|
|
|
CC_UNUSED_PARAM(tag);
|
|
|
|
CCAssert(0, "addChild: is not supported on CCTMXLayer. Instead use setTileGID:at:/tileAt:");
|
|
|
|
}
|
|
|
|
void CCTMXLayer::removeChild(CCNode* node, bool cleanup)
|
|
|
|
{
|
|
|
|
CCSprite *sprite = (CCSprite*)node;
|
|
|
|
// allows removing nil objects
|
2012-08-20 14:06:29 +08:00
|
|
|
if (! sprite)
|
|
|
|
{
|
2012-04-19 14:35:52 +08:00
|
|
|
return;
|
2012-08-20 14:06:29 +08:00
|
|
|
}
|
2012-04-19 14:35:52 +08:00
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert(_children->containsObject(sprite), "Tile does not belong to TMXLayer");
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
unsigned int atlasIndex = sprite->getAtlasIndex();
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int zz = (size_t)_atlasIndexArray->arr[atlasIndex];
|
|
|
|
_tiles[zz] = 0;
|
|
|
|
ccCArrayRemoveValueAtIndex(_atlasIndexArray, atlasIndex);
|
2012-04-19 14:35:52 +08:00
|
|
|
CCSpriteBatchNode::removeChild(sprite, cleanup);
|
|
|
|
}
|
|
|
|
void CCTMXLayer::removeTileAt(const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCAssert(pos.x < _layerSize.width && pos.y < _layerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
|
|
|
|
CCAssert(_tiles && _atlasIndexArray, "TMXLayer: the tiles map has been released");
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
unsigned int gid = tileGIDAt(pos);
|
|
|
|
|
2012-08-20 14:06:29 +08:00
|
|
|
if (gid)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
unsigned int z = (unsigned int)(pos.x + pos.y * _layerSize.width);
|
2012-04-19 14:35:52 +08:00
|
|
|
unsigned int atlasIndex = atlasIndexForExistantZ(z);
|
|
|
|
|
|
|
|
// remove tile from GID map
|
2013-06-15 14:03:30 +08:00
|
|
|
_tiles[z] = 0;
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// remove tile from atlas position array
|
2013-06-15 14:03:30 +08:00
|
|
|
ccCArrayRemoveValueAtIndex(_atlasIndexArray, atlasIndex);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// remove it from sprites and/or texture atlas
|
|
|
|
CCSprite *sprite = (CCSprite*)getChildByTag(z);
|
2012-08-20 14:06:29 +08:00
|
|
|
if (sprite)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCSpriteBatchNode::removeChild(sprite, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
_textureAtlas->removeQuadAtIndex(atlasIndex);
|
2012-04-19 14:35:52 +08:00
|
|
|
|
|
|
|
// update possible children
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_children && _children->count()>0)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCObject* pObject = NULL;
|
2013-06-15 14:03:30 +08:00
|
|
|
CCARRAY_FOREACH(_children, pObject)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
CCSprite* pChild = (CCSprite*) pObject;
|
|
|
|
if (pChild)
|
|
|
|
{
|
|
|
|
unsigned int ai = pChild->getAtlasIndex();
|
|
|
|
if ( ai >= atlasIndex )
|
|
|
|
{
|
|
|
|
pChild->setAtlasIndex(ai-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//CCTMXLayer - obtaining positions, offset
|
|
|
|
CCPoint CCTMXLayer::calculateLayerOffset(const CCPoint& pos)
|
|
|
|
{
|
|
|
|
CCPoint ret = CCPointZero;
|
2013-06-15 14:03:30 +08:00
|
|
|
switch (_layerOrientation)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
case CCTMXOrientationOrtho:
|
2013-06-15 14:03:30 +08:00
|
|
|
ret = ccp( pos.x * _mapTileSize.width, -pos.y *_mapTileSize.height);
|
2012-04-19 14:35:52 +08:00
|
|
|
break;
|
|
|
|
case CCTMXOrientationIso:
|
2013-06-15 14:03:30 +08:00
|
|
|
ret = ccp((_mapTileSize.width /2) * (pos.x - pos.y),
|
|
|
|
(_mapTileSize.height /2 ) * (-pos.x - pos.y));
|
2012-04-19 14:35:52 +08:00
|
|
|
break;
|
|
|
|
case CCTMXOrientationHex:
|
2012-08-01 15:30:12 +08:00
|
|
|
CCAssert(pos.equals(CCPointZero), "offset for hexagonal map not implemented yet");
|
2012-04-19 14:35:52 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
CCPoint CCTMXLayer::positionAt(const CCPoint& pos)
|
|
|
|
{
|
|
|
|
CCPoint ret = CCPointZero;
|
2013-06-15 14:03:30 +08:00
|
|
|
switch (_layerOrientation)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
case CCTMXOrientationOrtho:
|
|
|
|
ret = positionForOrthoAt(pos);
|
|
|
|
break;
|
|
|
|
case CCTMXOrientationIso:
|
|
|
|
ret = positionForIsoAt(pos);
|
|
|
|
break;
|
|
|
|
case CCTMXOrientationHex:
|
|
|
|
ret = positionForHexAt(pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = CC_POINT_PIXELS_TO_POINTS( ret );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
CCPoint CCTMXLayer::positionForOrthoAt(const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCPoint xy = CCPointMake(pos.x * _mapTileSize.width,
|
|
|
|
(_layerSize.height - pos.y - 1) * _mapTileSize.height);
|
2012-04-19 14:35:52 +08:00
|
|
|
return xy;
|
|
|
|
}
|
|
|
|
CCPoint CCTMXLayer::positionForIsoAt(const CCPoint& pos)
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
CCPoint xy = CCPointMake(_mapTileSize.width /2 * (_layerSize.width + pos.x - pos.y - 1),
|
|
|
|
_mapTileSize.height /2 * ((_layerSize.height * 2 - pos.x - pos.y) - 2));
|
2012-04-19 14:35:52 +08:00
|
|
|
return xy;
|
|
|
|
}
|
|
|
|
CCPoint CCTMXLayer::positionForHexAt(const CCPoint& pos)
|
|
|
|
{
|
|
|
|
float diffY = 0;
|
2012-08-20 14:06:29 +08:00
|
|
|
if ((int)pos.x % 2 == 1)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
diffY = -_mapTileSize.height/2 ;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:03:30 +08:00
|
|
|
CCPoint xy = CCPointMake(pos.x * _mapTileSize.width*3/4,
|
|
|
|
(_layerSize.height - pos.y - 1) * _mapTileSize.height + diffY);
|
2012-04-19 14:35:52 +08:00
|
|
|
return xy;
|
|
|
|
}
|
|
|
|
int CCTMXLayer::vertexZForPos(const CCPoint& pos)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
unsigned int maxVal = 0;
|
2013-06-15 14:03:30 +08:00
|
|
|
if (_useAutomaticVertexZ)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
switch (_layerOrientation)
|
2012-04-19 14:35:52 +08:00
|
|
|
{
|
|
|
|
case CCTMXOrientationIso:
|
2013-06-15 14:03:30 +08:00
|
|
|
maxVal = (unsigned int)(_layerSize.width + _layerSize.height);
|
2012-04-19 14:35:52 +08:00
|
|
|
ret = (int)(-(maxVal - (pos.x + pos.y)));
|
|
|
|
break;
|
|
|
|
case CCTMXOrientationOrtho:
|
2013-06-15 14:03:30 +08:00
|
|
|
ret = (int)(-(_layerSize.height-pos.y));
|
2012-04-19 14:35:52 +08:00
|
|
|
break;
|
|
|
|
case CCTMXOrientationHex:
|
|
|
|
CCAssert(0, "TMX Hexa zOrder not supported");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CCAssert(0, "TMX invalid value");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
ret = _vertexZvalue;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
2012-08-20 14:06:29 +08:00
|
|
|
|
2012-04-19 14:35:52 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCDictionary * CCTMXLayer::getProperties()
|
|
|
|
{
|
2013-06-15 14:03:30 +08:00
|
|
|
return _properties;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
void CCTMXLayer::setProperties(CCDictionary* var)
|
|
|
|
{
|
|
|
|
CC_SAFE_RETAIN(var);
|
2013-06-15 14:03:30 +08:00
|
|
|
CC_SAFE_RELEASE(_properties);
|
|
|
|
_properties = var;
|
2012-04-19 14:35:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_CC_END
|
|
|
|
|