
之前已经有一篇更基础的tilemap笔记了,这两天用了下3.3的tilemap发现以前有些东西又套用不了。所以又写了一篇札记,顿时感觉自己萌萌哒。
完全没有玩过的童鞋可以看看基础篇
主要实现目标:
1. 能够3倍缩放tiledMap
2. 能够鼠标滑动 tiledMap
3. 在缩放和滑动的情况下,点击一个tile 能够判断出 实际的格子坐标。
4. 永远让角色保持在屏幕中心
缩放和滑动这里就不再详细解释了,有很多的例子,末尾呈上完整代码。主要说一下第三条的实现。
可以从图中看出,我建了一个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 0 tileY 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()); <span > ret = CC_POINT_PIXELS_TO_POINTS( ret );</span> 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_FACTOROn 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,iphoneRetina 是 2 : 1,低分辨率就会更大。我们就把这个比值像素尺寸因子吧
2. 通过CC_POINT_PIXELS_TO_POINTS 能够把 tilemap上面的坐标值转换成 设备上面的坐标值。
3. 这个setScale getScale做的是类似的事情,但是要区分开来计算。
此外,因为我们的tilemap可以滑动点击,所以在从触摸点转换 tilemap绝对坐标的时候需要额外做两点:
1. 把tilemapLayer的坐标作为偏移量
bool HelloWorld::ontouchBegan(touch *touch,Event *event){ cclOG("HelloWorld::ontouchBegan"); Point touchPoint = touch->getLocation(); Point mapPoint = _tiledMap->getposition(); <span >Point realPoint = touchPoint - mapPoint;</span> Point tilePoint = covertPointToTiledPoint(realPoint); cclOG("tilePoint x:%f y:%f",tilePoint.x,tilePoint.y); tryGetobjectPropertyByposition(realPoint); return true;}
2. 除以缩放系数
注意:在scale的情况下,因为touchPoint 和 mapPoint 经过缩放,已经在scale的作用产生变化了
所以:
PointrealPoint = (touchPoint - mapPoint)/_tiledMap->getScale();
bool HelloWorld::ontouchBegan(touch *touch,Event *event){ cclOG("HelloWorld::ontouchBegan================"); Point touchPoint = touch->getLocation(); Point mapPoint = _tiledMap->getposition(); Point realPoint = (touchPoint - mapPoint)/getTileMapScale();}
接下来再逆推一下从 触摸点 转换到 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;
}
测试发现,上述方法还是计算有偏差,补上一个正确的计算方法
Point HelloWorld::tileCoordForposition(const Point &position) const{ float factor = CC_CONTENT_SCALE_FACTOR(); int x = position.x * factor/ _tiledMap->getTileSize().wIDth; int y = ((_tiledMap->getMapSize().height * _tiledMap->getTileSize().height) - position.y * factor) / _tiledMap->getTileSize().height; return Point(x,y);}Point HelloWorld::positionForTileCoord(const Point &tileCoord) const{ float factor = CC_CONTENT_SCALE_FACTOR(); int x = (tileCoord.x * _tiledMap->getTileSize().wIDth) + _tiledMap->getTileSize().wIDth / 2; int y = (_tiledMap->getMapSize().height * _tiledMap->getTileSize().height) - (tileCoord.y * _tiledMap->getTileSize().height) - _tiledMap->getTileSize().height / 2; return Point(x/factor,y/factor);}
注意:在进行了scale缩放的情况下,positionForTileCoord 得出来的坐标是在 tilemap上面的相对坐标 relativePoint;
如果用来设置 tileMap 上面的子对象的坐标,那么不需要额外加工了,因为计算子结点相对坐标是不需要考虑scale的。
最后说一下关注角色居中的问题:
先上代码
voID HelloWorld::setVIEwpointCenter2(const Point &RolePoint){ Size winSize = Director::getInstance()->getWinSize(); Point centerOfVIEw(winSize.wIDth / 2,winSize.height / 2); Point tileMapPoint = _tiledMap->getposition(); Point centerPoint = (centerOfVIEw - tileMapPoint)/_tiledMap->getScale(); Point OffsetVec = centerPoint - RolePoint; _tiledMap->setposition(tileMapPoint + OffsetVec);}
假设图中的黑框就是设备,那么我们现在要做的就是移动地图,让小猫处在设备中心,也就是蓝圈的位置。
1.中心位置,在屏幕坐标系上恒定不变,永远是 Point centerOfVIEw(winSize.wIDth / 2,winSize.height / 2);
2. 地图的坐标是相对屏幕坐标系的坐标(受到scale影响),这样 (centerOfVIEw - tileMapPoint) / scale 就得到了蓝圈在 地图坐标系的坐标centerPoint
3. 角色坐标(RolePoint) + 偏移量(offsetVec)= centerPoint
4. tileMap的新位置 = tileMapPoint+ 偏移量
代码下载
总结以上是内存溢出为你收集整理的cocos2dx 3.3 tilemap 缩放滑动并且准确点击对象全部内容,希望文章能够帮你解决cocos2dx 3.3 tilemap 缩放滑动并且准确点击对象所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)