// TMXLayer - obtaining tiles/gids Sprite * TMXLayer::getTileAt(const Point& pos) { 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"); Sprite *tile = nullptr; int gid = this->getTileGIDAt(pos); // if GID == 0, then no tile is present if (gid) { int z = (int)(pos.x + pos.y * _layerSize.width); tile = static_cast<Sprite*>(this->getChildByTag(z)); // tile not created yet. create it if (! tile) { Rect rect = _tileSet->rectForGID(gid); rect = CC_RECT_PIXELS_TO_POINTS(rect); tile = Sprite::createWithTexture(this->getTexture(), rect); tile->setBatchNode(this); tile->setPosition(getPositionAt(pos)); tile->setVertexZ((float)getVertexZForPos(pos)); tile->setAnchorPoint(Point::ZERO); tile->setOpacity(_opacity); ssize_t indexForZ = atlasIndexForExistantZ(z); this->addSpriteWithoutQuad(tile, static_cast<int>(indexForZ), z); } } return tile; }
void TMXLayer::setupTileSprite(Sprite* sprite, Point pos, unsigned int gid) { sprite->setPosition(getPositionAt(pos)); sprite->setVertexZ((float)getVertexZForPos(pos)); sprite->setAnchorPoint(Point::ZERO); sprite->setOpacity(m_cOpacity); //issue 1264, flip can be undone as well sprite->setFlippedX(false); sprite->setFlippedY(false); sprite->setRotation(0.0f); sprite->setAnchorPoint(Point(0,0)); // Rotation in tiled is achieved using 3 flipped states, flipping across the horizontal, vertical, and diagonal axes of the tiles. if (gid & kTMXTileDiagonalFlag) { // put the anchor in the middle for ease of rotation. sprite->setAnchorPoint(Point(0.5f,0.5f)); sprite->setPosition(Point(getPositionAt(pos).x + sprite->getContentSize().height/2, getPositionAt(pos).y + sprite->getContentSize().width/2 ) ); unsigned int flag = gid & (kTMXTileHorizontalFlag | kTMXTileVerticalFlag ); // handle the 4 diagonally flipped states. if (flag == kTMXTileHorizontalFlag) { sprite->setRotation(90.0f); } else if (flag == kTMXTileVerticalFlag) { sprite->setRotation(270.0f); } else if (flag == (kTMXTileVerticalFlag | kTMXTileHorizontalFlag) ) { sprite->setRotation(90.0f); sprite->setFlippedX(true); } else { sprite->setRotation(270.0f); sprite->setFlippedX(true); } } else { if (gid & kTMXTileHorizontalFlag) { sprite->setFlippedX(true); } if (gid & kTMXTileVerticalFlag) { sprite->setFlippedY(true); } } }
// removing / getting tiles Sprite* TMXLayer::getTileAt(const Vec2& tileCoordinate) { CCASSERT( tileCoordinate.x < _layerSize.width && tileCoordinate.y < _layerSize.height && tileCoordinate.x >=0 && tileCoordinate.y >=0, "TMXLayer: invalid position"); CCASSERT( _tiles, "TMXLayer: the tiles map has been released"); Sprite *tile = nullptr; int gid = this->getTileGIDAt(tileCoordinate); // if GID == 0, then no tile is present if( gid ) { int index = tileCoordinate.x + tileCoordinate.y * _layerSize.width; auto it = _spriteContainer.find(index); if (it != _spriteContainer.end()) { tile = it->second.first; } else { // tile not created yet. create it Rect rect = _tileSet->getRectForGID(gid); rect = CC_RECT_PIXELS_TO_POINTS(rect); tile = Sprite::createWithTexture(_texture, rect); Vec2 p = this->getPositionAt(tileCoordinate); tile->setAnchorPoint(Vec2::ZERO); tile->setPosition(p); tile->setPositionZ((float)getVertexZForPos(tileCoordinate)); tile->setOpacity(this->getOpacity()); tile->setTag(index); this->addChild(tile, index); _spriteContainer.insert(std::pair<int, std::pair<Sprite*, int> >(index, std::pair<Sprite*, int>(tile, gid))); // tile is converted to sprite. setFlaggedTileGIDByIndex(index, 0); } } return tile; }
void TMXLayer::updateTotalQuads() { if(_quadsDirty) { Size tileSize = CC_SIZE_PIXELS_TO_POINTS(_tileSet->_tileSize); Size texSize = _tileSet->_imageSize; _tileToQuadIndex.clear(); (*_totalQuads).resize(int(_layerSize.width * _layerSize.height)); //[CY MOD] (*_indices).resize(6 * int(_layerSize.width * _layerSize.height)); //[CY MOD] _tileToQuadIndex.resize(int(_layerSize.width * _layerSize.height),-1); _indicesVertexZOffsets.clear(); int quadIndex = 0; for(int y = 0; y < _layerSize.height; ++y) { for(int x =0; x < _layerSize.width; ++x) { int tileIndex = getTileIndexByPos(x, y); int tileGID = _tiles[tileIndex]; if(tileGID == 0) continue; _tileToQuadIndex[tileIndex] = quadIndex; auto& quad = (*_totalQuads)[quadIndex]; //[CY MOD] Vec3 nodePos(float(x), float(y), 0); _tileToNodeTransform.transformPoint(&nodePos); float left, right, top, bottom, z; z = getVertexZForPos(Vec2(x, y)); auto iter = _indicesVertexZOffsets.find(z); if(iter == _indicesVertexZOffsets.end()) { _indicesVertexZOffsets[z] = 1; } else { iter->second++; } // vertices if (tileGID & kTMXTileDiagonalFlag) { left = nodePos.x; right = nodePos.x + tileSize.height; bottom = nodePos.y + tileSize.width; top = nodePos.y; } else { left = nodePos.x; right = nodePos.x + tileSize.width; bottom = nodePos.y + tileSize.height; top = nodePos.y; } if(tileGID & kTMXTileVerticalFlag) std::swap(top, bottom); if(tileGID & kTMXTileHorizontalFlag) std::swap(left, right); if(tileGID & kTMXTileDiagonalFlag) { // FIXME: not working correcly quad.bl.vertices.x = left; quad.bl.vertices.y = bottom; quad.bl.vertices.z = z; quad.br.vertices.x = left; quad.br.vertices.y = top; quad.br.vertices.z = z; quad.tl.vertices.x = right; quad.tl.vertices.y = bottom; quad.tl.vertices.z = z; quad.tr.vertices.x = right; quad.tr.vertices.y = top; quad.tr.vertices.z = z; } else { quad.bl.vertices.x = left; quad.bl.vertices.y = bottom; quad.bl.vertices.z = z; quad.br.vertices.x = right; quad.br.vertices.y = bottom; quad.br.vertices.z = z; quad.tl.vertices.x = left; quad.tl.vertices.y = top; quad.tl.vertices.z = z; quad.tr.vertices.x = right; quad.tr.vertices.y = top; quad.tr.vertices.z = z; } // texcoords Rect tileTexture = _tileSet->getRectForGID(tileGID); left = (tileTexture.origin.x) / texSize.width; right = (tileTexture.origin.x+tileTexture.size.width) / texSize.width; bottom = (tileTexture.origin.y)/ texSize.height; top = (tileTexture.origin.y+tileTexture.size.height) / texSize.height; quad.bl.texCoords.u = left; quad.bl.texCoords.v = bottom; quad.br.texCoords.u = right; quad.br.texCoords.v = bottom; quad.tl.texCoords.u = left; quad.tl.texCoords.v = top; quad.tr.texCoords.u = right; quad.tr.texCoords.v = top; quad.bl.colors = Color4B::WHITE; quad.br.colors = Color4B::WHITE; quad.tl.colors = Color4B::WHITE; quad.tr.colors = Color4B::WHITE; ++quadIndex; } } int offset = 0; for(auto iter = _indicesVertexZOffsets.begin(); iter != _indicesVertexZOffsets.end(); ++iter) { std::swap(offset, iter->second); offset += iter->second; } updateVertexBuffer(); _quadsDirty = false; } }
void TMXLayer::updateTiles(const Rect& culledRect) { Rect visibleTiles = culledRect; Size mapTileSize = CC_SIZE_PIXELS_TO_POINTS(_mapTileSize); Size tileSize = CC_SIZE_PIXELS_TO_POINTS(_tileSet->_tileSize); Mat4 nodeToTileTransform = _tileToNodeTransform.getInversed(); //transform to tile visibleTiles = RectApplyTransform(visibleTiles, nodeToTileTransform); // tile coordinate is upside-down, so we need to make the tile coordinate use top-left for the start point. visibleTiles.origin.y += 1; // if x=0.7, width=9.5, we need to draw number 0~10 of tiles, and so is height. visibleTiles.size.width = ceil(visibleTiles.origin.x + visibleTiles.size.width) - floor(visibleTiles.origin.x); visibleTiles.size.height = ceil(visibleTiles.origin.y + visibleTiles.size.height) - floor(visibleTiles.origin.y); visibleTiles.origin.x = floor(visibleTiles.origin.x); visibleTiles.origin.y = floor(visibleTiles.origin.y); // for the bigger tiles. int tilesOverX = 0; int tilesOverY = 0; // for diagonal oriention tiles float tileSizeMax = std::max(tileSize.width, tileSize.height); if (_layerOrientation == FAST_TMX_ORIENTATION_ORTHO) { tilesOverX = ceil(tileSizeMax / mapTileSize.width) - 1; tilesOverY = ceil(tileSizeMax / mapTileSize.height) - 1; if (tilesOverX < 0) tilesOverX = 0; if (tilesOverY < 0) tilesOverY = 0; } else if(_layerOrientation == FAST_TMX_ORIENTATION_ISO) { Rect overTileRect(0, 0, tileSizeMax - mapTileSize.width, tileSizeMax - mapTileSize.height); if (overTileRect.size.width < 0) overTileRect.size.width = 0; if (overTileRect.size.height < 0) overTileRect.size.height = 0; overTileRect = RectApplyTransform(overTileRect, nodeToTileTransform); tilesOverX = ceil(overTileRect.origin.x + overTileRect.size.width) - floor(overTileRect.origin.x); tilesOverY = ceil(overTileRect.origin.y + overTileRect.size.height) - floor(overTileRect.origin.y); } else { //do nothing, do not support //CCASSERT(0, "TMX invalid value"); } _indicesVertexZNumber.clear(); for(const auto& iter : _indicesVertexZOffsets) { _indicesVertexZNumber[iter.first] = iter.second; } int yBegin = std::max(0.f,visibleTiles.origin.y - tilesOverY); int yEnd = std::min(_layerSize.height,visibleTiles.origin.y + visibleTiles.size.height + tilesOverY); int xBegin = std::max(0.f,visibleTiles.origin.x - tilesOverX); int xEnd = std::min(_layerSize.width,visibleTiles.origin.x + visibleTiles.size.width + tilesOverX); for (int y = yBegin; y < yEnd; ++y) { for (int x = xBegin; x < xEnd; ++x) { int tileIndex = getTileIndexByPos(x, y); if(_tiles[tileIndex] == 0) continue; int vertexZ = getVertexZForPos(Vec2(x,y)); auto iter = _indicesVertexZNumber.find(vertexZ); int offset = iter->second; iter->second++; int quadIndex = _tileToQuadIndex[tileIndex]; CC_ASSERT(-1 != quadIndex); (*_indices)[6 * offset + 0] = quadIndex * 4 + 0; //[CY MOD] (*_indices)[6 * offset + 1] = quadIndex * 4 + 1; //[CY MOD] (*_indices)[6 * offset + 2] = quadIndex * 4 + 2; //[CY MOD] (*_indices)[6 * offset + 3] = quadIndex * 4 + 3; //[CY MOD] (*_indices)[6 * offset + 4] = quadIndex * 4 + 2; //[CY MOD] (*_indices)[6 * offset + 5] = quadIndex * 4 + 1; //[CY MOD] } // for x } // for y for(const auto& iter : _indicesVertexZOffsets) { _indicesVertexZNumber[iter.first] -= iter.second; if(_indicesVertexZNumber[iter.first] == 0) { _indicesVertexZNumber.erase(iter.first); } } }