首先我們需要知道,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