之前已经有一篇更基础的tilemap笔记了,这两天用了下3.3的tilemap发现以前有些东西又套用不了。所以又写了一篇札记,顿时感觉自己萌萌哒。

没有学会的童鞋注意了:

主要实现目标: 

1. 能够3倍缩放tiledMap

2. 能够鼠标滑动 tiledMap

3. 在缩放和滑动的情况下,点击一个tile 能够判断出 实际的格子坐标。

缩放和滑动这里就不再详细解释了,有很多的例子,末尾呈上完整代码。主要说一下第三条的实现。

可以从图中看出,我建了一个points对象组,然后建立了两个对象 startPos 和endPos

startPos 大概覆盖了 4个tiled [0,24] [1,24] [0,25] [1,25]

并且给startPos设置了一个 自定义属性:id 。我需要的就是点击到 上面4块tiled的时候能够 获取到这个对象的id值。





首先写了个函数来读地图对象

void HelloWorld::parseTileMap()

{

CCLOG(“parseTileMap”);

if(_tiledMap == NULL)

return;

_objectsGroup = _tiledMap->getObjectGroup(“points”);

//tileX 0tileY 24

ValueMap startPos = _objectsGroup->getObject(“startPos”);

std::string name = startPos[“name”].asString();

float pointX = startPos[“x”].asFloat();

float pointY = startPos[“y”].asFloat();;

float PointWidth = startPos[“width”].asFloat();

float PointHeight = startPos[“height”].asFloat();

Size winSize = Director::getInstance()->getWinSize();

Point mapPoint = _tiledMap->getPosition();

Point centerPos = covertTiledPointToCenterPoint(Point(0,24));

Point tilePos = covertPointToTiledPoint(Point(pointX,pointY));

Point tilePos2 = covertPointToTiledPoint(centerPos);

}

很顺利的拿到startPos对象的 pointX 和pointY , 但是值却是(0,296) , 不是期待的(1,768) 忽然有点凌乱 -_- !!了。

直到看了一下源码TMXLayer 的getPositionAt才发现,原来这个(0,296) 是已经经过 “分辨率转换“了。

Vec2 TMXLayer::getPositionAt(const Vec2& pos)

{

Vec2 ret = Vec2::ZERO;

switch (_layerOrientation)

{

case TMXOrientationOrtho:

ret = getPositionForOrthoAt(pos);

break;

case TMXOrientationIso:

ret = getPositionForIsoAt(pos);

break;

case TMXOrientationHex:

ret = getPositionForHexAt(pos);

break;

case TMXOrientationStaggered:

ret = getPositionForStaggeredAt(pos);

break;

}

CCLOG(“%f,%f,%f”,ret.x,ret.y,CC_CONTENT_SCALE_FACTOR());

ret = <span style=”color:#ff0000;”>CC_POINT_PIXELS_TO_POINTS</span>( ret );

return ret;

}

看一下宏的定义:

/** @def CC_POINT_PIXELS_TO_POINTS

Converts a rect in pixels to points

*/

#define CC_POINT_PIXELS_TO_POINTS(__pixels__)\

Vec2( (__pixels__).x / CC_CONTENT_SCALE_FACTOR(), (__pixels__).y / CC_CONTENT_SCALE_FACTOR())

/** @def CC_CONTENT_SCALE_FACTOR

On Mac it returns 1;

On iPhone it returns 2 if RetinaDisplay is On. Otherwise it returns 1

*/

#define CC_CONTENT_SCALE_FACTOR() Director::getInstance()->getContentScaleFactor()

从源码可以看到:

1 . 我们可以确定的是tilemap 上面 pixel : point 的比例是1 : 1, 而设备上面却并不一定。

mac 设备上面 pixel : point = 1: 1 , iphone Retina 是 2 : 1, 低分辨率就会更大。我们就把这个比值像素尺寸因子吧

2. 通过 CC_POINT_PIXELS_TO_POINTS 能够把 tilemap上面的坐标值转换成 设备上面的坐标值。

3. 这个setScale getScale做的是类似的事情,但是要区分开来计算。

此外,因为我们的tilemap可以滑动点击,所以在从触摸点转换 tilemap绝对坐标的时候需要额外做两点:

1.把tilemapLayer的坐标作为偏移量

bool HelloWorld:nTouchBegan(Touch *touch, Event*event)

{

CCLOG(“HelloWorld:nTouchBegan”);

Point touchPoint = touch->getLocation();

Point mapPoint = _tiledMap->getPosition();

<span style=”color:#ff0000;”>oint realPoint = touchPoint – mapPoint;</span>

Point tilePoint = covertPointToTiledPoint(realPoint);

CCLOG(“tilePoint x:%f y:%f”,tilePoint.x,tilePoint.y);

tryGetObjectPropertyByPosition(realPoint);

return true;

}

2. 乘以缩放系数

//参数:触摸坐标

string HelloWorld::tryGetObjectPropertyByPosition(Point position)

{

float scale = _tiledMap->getScale();

float factor = CC_CONTENT_SCALE_FACTOR();

<span style=”color:#ff0000;”>float realPointX = position.x / scale;

float realPointY = position.y / scale;</span>

for (auto item : _objectsGroup->getObjects())

{

ValueMap curObject = item.asValueMap();

float pointX = curObject[“x”].asFloat();

float pointY = curObject[“y”].asFloat();;

float PointWidth = curObject[“width”].asFloat();

float PointHeight = curObject[“height”].asFloat();

if(realPointX >= pointX and realPointX <= pointX + PointWidth

and realPointY >= pointY and realPointY <= pointY + PointHeight)

{

string objectId = curObject[“id”].asString();

CCLOG(“HelloWorld:tryGetObjectPropertyByPosition: %s”,objectId.c_str());

return objectId;

}

}

return “”;

}

接下来再逆推一下从 触摸点 转换到 tilemapPoint 的方法就非常简单了

Point HelloWorld::covertTiledPointToCenterPoint(Point p)

{

float scale = _tiledMap->getScale();

float factor = CC_CONTENT_SCALE_FACTOR();

CCLOG(“HelloWorld::covertTiledPointToCenterPoint scale:%f factor:%f”,scale,factor);

int offsetX = _tiledMap->getTileSize().width / (2 * factor);

int offsetY = _tiledMap->getTileSize().height / (2 * factor);

TMXLayer* layer = _tiledMap->layerNamed(“background”);

Point point = layer->getPositionAt(p);

point = Point(point.x+ offsetX,point.y – offsetY);

point = Point(point.x * scale, point.y * scale);

return point;

}