首页 > 代码库 > cocos2d-x 使用tmx地图总结
cocos2d-x 使用tmx地图总结
首先我们需要知道,tmx地图的坐标为格子坐标,左上角为原点(0,0),而cocos里面一般使用opengl坐标系,即左下角为原点(0,0)。
我们可以这样子来转换tmx地图和opengl的坐标:
Point HelloLayer::tiledCoorForPosition(const Point& position) //转成格子坐标 { Size mapSize = _tiledMap->getMapSize(); Size tileSize = _tiledMap->getTileSize(); int x = (position.x ) / tileSize.width; int y = (mapSize.height * tileSize.height - position.y ) / tileSize.height; return Point(x,y); } Point HelloLayer::positionForTiledCoor(const Point& tiledCoor) //转成oepngl坐标 { Size mapSize = _tiledMap->getMapSize(); Size tileSize = _tiledMap->getTileSize(); int x = tiledCoor.x * tileSize.width + tileSize.width / 2; int y = (mapSize.height * tileSize.height) - (tiledCoor.y * tileSize.height + tileSize.height / 2); return Point(x,y); }
layer的锚点为(0,0),tmx地图的锚点默认是(0,0),如果我们在layer中添加tmx地图,比如这样子:
bool HelloLayer::init() { if(!Layer::init()) { return false; } //地图 _tileMap = TMXTiledMap::create("map.tmx"); this->addChild(_tileMap); //精灵 _sprite = Sprite::create("sp.png"); this.addChild(_sprite); }
1.地图随主角移动
以sprite为焦点来调整地图的位置:
void HelloLayer::setViewPoint(const Point& point) { Size winSize = Director::getInstance()->getWinSize(); int x = MAX(point.x, winSize.width / 2); int y = MAX(point.y, winSize.height / 2); x = MIN(x, _tiledMap->getMapSize().width * _tiledMap->getTileSize().width - winSize.width / 2); y = MIN(y, _tiledMap->getMapSize().height * _tiledMap->getTileSize().height - winSize.height / 2); Point actualPoint(x,y); Point centerOfView(winSize.width / 2, winSize.height / 2); Point viewPoint = centerOfView - actualPoint; _tiledMap->setPosition(viewPoint); }
然后不断的在update函数中不断的检测sprite的位置并设置地图位置就可以了
void HelloLayer::update(float dt) { this->setViewPoint(_sprite->getPosition()); }
2.地图拖动
地图移动主要是在onTouchMoved里面判断两个点的偏移向量vec,然后判断边界值避免出现黑边,具体如下
listener->onTouchMoved = [&] (Touch* touch, Event* event) { Point prePos = touch->getPreviousLocation(); Point curPos = touch->getLocation(); Point vec = curPos - prePos; Point mapPos = _tiledMap->getPosition(); Point viewPos = mapPos + vec; Size winSize = Director::getInstance()->getWinSize(); Size mapSize = _tiledMap->getMapSize(); Size tileSize = _tiledMap->getTileSize(); //若x坐标值超过边界值,则去掉x的偏移 if(viewPos.x < winSize.width - mapSize.width * tileSize.width || viewPos.x > 0 ) { viewPos.x -= vec.x; } //同理,若y坐标值超过边界值,则去掉y的偏移 if(viewPos.y < winSize.height - mapSize.height * tileSize.height || viewPos.y >0 ) { viewPos.y -= vec.y; } _tiledMap->setPosition(viewPos); };
3.地图缩放
下面来实现地图的放大功能,具体为点击一个点p1,然后以p1为屏幕的焦点不断去放大地图
listener->onTouchBegan = [this] (Touch* touch, Event* event) { //点击位置p1 Point touchLocation = _tiledMap->convertTouchToNodeSpace(touch); _touchPos = touchLocation; //缩放 _tiledMap->runAction(ScaleBy::create(1.0f,1.2f,1.2f,1.0f)); this->scheduleUpdate(); return true; } void HelloLayer::update(float dt) { //缩放的同时不断更新焦点p1的位置(因为地图放大,地图中的点的坐标也要相应放大) float scale = _tiledMap->getScale(); Point viewPos(scale * _touchPos.x,scale * _touchPos.y); //根据p1不断设置地图的位置 this->setViewPointByScale(viewPos,scale); } void HelloLayer::setViewPointByScale(const Point& point,float scale) { Size winSize = Director::getInstance()->getWinSize(); int x = MAX(point.x, winSize.width / 2); int y = MAX(point.y, winSize.height / 2); //需要注意的是,地图放大后,mapSize和tileSize并没有变大,所以判断边界的时候我们需要手动 * scale x = MIN(x, _tiledMap->getMapSize().width * _tiledMap->getTileSize().width * scale - winSize.width / 2); y = MIN(y, _tiledMap->getMapSize().height * _tiledMap->getTileSize().height * scale - winSize.height / 2); Point actualPoint(x,y); Point centerOfView(winSize.width / 2, winSize.height / 2); Point viewPoint = centerOfView - actualPoint; _tiledMap->setPosition(viewPoint); }
以上是一个比较简单的思路,比如我们要实现双指缩放,可以参照上面的思路这样子做:
listener->onTouchesBegan = [&] (const std::vector<Touch*>& touches, Event* event) { if(touches.size() >= 2) { Point p1 = _tiledMap->convertTouchToNodeSpace(touches[0]); Point p2 = _tiledMap->convertTouchToNodeSpace(touches[1]); //算出亮点距离,保存到类变量中 _distance = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } return true; } listener->onTouchesMoved = [&] (const std::vector<Touch*> &touches, Event* event) { if(touches.size() >= 2) { Point p1 = _tiledMap->convertTouchToNodeSpace(touches[0]); Point p2 = _tiledMap->convertTouchToNodeSpace(touches[1]); //算出缩放倍数,并保存新的距离 float new_distance = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); float scale = new_distance / _distance; _distance = new_distance; //取p1和p2中点,缩放地图并设置屏幕焦点 Point pCenter ((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); _tiledMap->setScale(scale); this->setViewPointByScale(pCenter,scale); } }
4.碰撞检测
碰撞检测比较简单,现有地图如下:(因为正在看A*算法,所以就拿这地图举例了,A*寻路算法原文地址如下 http://blog.csdn.net/akof1314/article/details/19333255)
现在我们来判断鼠标点击的是不是障碍物:
listener->onTouchBegan = [this] (Touch* touch, Event* event) { Point touchLocation = _tiledMap->convertTouchToNodeSpace(touch); Point tileCoord = this->tiledCoorForPosition(touchLocation); if(this->isWallAtTileCoord(tileCoord)) //检测是否为墙壁 { CCLOG("isWall"); } } bool HelloLayer::isWallAtTileCoord(const Point &tileCoord) const { //先获取格子的gid值,再获取属性值 int gid = _bgLayer->getTileGIDAt(tileCoord); Value properties = _tiledMap->getPropertiesForGID(gid); if (properties.isNull()) { return false; } return properties.asValueMap().find("Wall") != properties.asValueMap().end(); }
恩,大致就这些了。
转载请注明出处:http://blog.csdn.net/shun_fzll/article/details/39480393
cocos2d-x 使用tmx地图总结
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。