瓦片地图-坐标转换
2015-12-10 22:13
561 查看
先明确三点:
(1)屏幕坐标是以左上角为原点。而cocos2dx坐标即opengl坐标体系,是以左下角为原点。
(2)tile地图坐标是以左上角或上方(45°)为原点。tile瓦片的默认锚点是左下角。
一、地图坐标
Tiled地图一般常见的有3种不同的地图类型,即:普通、45度、45度交错,但是在所有类型的地图中的坐标都是按格子数算的,比如坐标(0,0)代表左上角的第一个格子,需要注意的是,由于3种类型地图的视角不同,所以坐标的起始与分布也有点差别,具体看下面几张图就明白了:
1、普通直角地图坐标
2、45度地图坐标
3、45度交错地图坐标
二、地图锚点
tiled地图的锚点默认的是在左下角,也就是opengl坐标系的(0,0)点,每一个瓦块的锚点也是如此,同样需要注意的是3种不同类型地图的锚点位置会因为视角的不同而有所差别,详见下面几张图:
1、普通直角地图锚点
2、45度地图锚点
3、45度交错地图锚点
三、坐标转换
很明显,tiled地图上的坐标不能直接用于在cocos的场景里,因为它们使用的坐标系是不一样的,所以如果要想正确的设置tiled地图坐标,必须对其坐标进行转换,关键代码如下(以下转换代码是基于坐标系对齐的情况下,即地图处在默认位置未移动,否则需要考虑加减地图坐标):
1、普通直角地图坐标转换
3、45度交错地图坐标转换
45度地图坐标转换 方案二:
来自:怎样制作基于Cocos2d-x的SLG游戏-第2章
http://www.cocos.com/doc/tutorial/show?id=1609
已测试过,可用!!
45度地图坐标转换方案三:
用向量来求坐标转换公式。
已知瓦片地图坐标(m-n)求屏幕坐标(x,y):
x=size_W/2+(m-n)*tile_H/2
y=size_H+(m+n)*(-tile_W/2)
已知屏幕坐标求瓦片地图坐标:
m=(x-size_W/2)/tile_H-(y-size_H)/tile_W;
n=-(x-size_W/2)/tile_H-(y-size_H)/tile_W;
转载自:http://blog.csdn.net/ftyszyx/article/details/9020101
在游戏中,为了在二维平面呈现立体效果常常需要使用45度角地图,最近有用到,原本以为很简单,结果搞了好几天才搞明白,因此记录下,以防以后忘记
首先要清楚几个概念:
如下是一张地图
地图宽:size_W
地图高:size_H
地图块高:tile_H
地图块宽:tile_W
具体如上图所示。
现在我们假设地图上有一点A,屏幕坐标第的原理在O点基向量为(X<
b6ef
/strong>,[b]Y),地图坐标系的原点在M点,基向量分别为(MX,MY)如下图:(注意,粗体是向量)
我们现在已知A点的屏幕坐标(x,y),地图原理M的屏幕坐标(size_W/2,size_H)要求A点的地图坐标(相对于地图坐标系),假设为(m,n)
因MA=mMX+nMY
而
MX=tile_H/2X+(-tile_W/2)Y
MY=(-tile_H/2)X+(-tile_W/2)Y
所以可得MA的屏幕坐标表示:(m-n)*tile_H/2 X +(m+n)*(-tile_W/2) Y
因OA=OM+MA
所以可得OA=(size_W/2+(m-n)*tile_H/2 ) X +(size_H+(m+n)*(-tile_W/2) ) Y,
于是有了这两个等式:
x=size_W/2+(m-n)*tile_H/2
y=size_H+(m+n)*(-tile_W/2)
求解可得m=(x-size_W/2)/tile_H-(y-size_H)/tile_W;
n=-(x-size_W/2)/tile_H-(y-size_H)/tile_W;
同理,也可以根据A的地图坐标求得A的屏幕坐标:
具体程序实现如下:
(1)屏幕坐标是以左上角为原点。而cocos2dx坐标即opengl坐标体系,是以左下角为原点。
(2)tile地图坐标是以左上角或上方(45°)为原点。tile瓦片的默认锚点是左下角。
一、地图坐标
Tiled地图一般常见的有3种不同的地图类型,即:普通、45度、45度交错,但是在所有类型的地图中的坐标都是按格子数算的,比如坐标(0,0)代表左上角的第一个格子,需要注意的是,由于3种类型地图的视角不同,所以坐标的起始与分布也有点差别,具体看下面几张图就明白了:
1、普通直角地图坐标
2、45度地图坐标
3、45度交错地图坐标
二、地图锚点
tiled地图的锚点默认的是在左下角,也就是opengl坐标系的(0,0)点,每一个瓦块的锚点也是如此,同样需要注意的是3种不同类型地图的锚点位置会因为视角的不同而有所差别,详见下面几张图:
1、普通直角地图锚点
2、45度地图锚点
3、45度交错地图锚点
三、坐标转换
很明显,tiled地图上的坐标不能直接用于在cocos的场景里,因为它们使用的坐标系是不一样的,所以如果要想正确的设置tiled地图坐标,必须对其坐标进行转换,关键代码如下(以下转换代码是基于坐标系对齐的情况下,即地图处在默认位置未移动,否则需要考虑加减地图坐标):
1、普通直角地图坐标转换
// OpenGL坐标转成格子坐标 Vec2 tileCoordForPosition(const Vec2& position) { Size mapSize = tiledMap->getMapSize(); // 获取以tiles数量为单位的地图尺寸 Size tileSize = tiledMap->getTileSize(); // 获取以像素点为单位的tile尺寸属性 int x = position.x / tileSize.width; int y = (mapSize.height*tileSize.height - position.y) / tileSize.height; return Vec2(x, y); } // tile坐标转成瓦片格子中心的OpenGL坐标 Vec2 positionForTileCoord(const Vec2& tileCoord) { Size mapSize = tiledMap->getMapSize(); Size tileSize = tiledMap->getTileSize(); int x = tileCoord.x * tileSize.width + tileSize.width/2; int y = (mapSize.height-tileCoord.y)*tileSize.height - tileSize.height/2; return Vec2(x, y); }2、45度地图坐标转换
3、45度交错地图坐标转换
// OpenGL坐标转成格子坐标 Vec2 staggeredCoordForPosition(CCPoint position) { Size mapSize = tiledMap->getMapSize(); Size tileSize = tiledMap->getTileSize(); int y = mapSize.height - 2 - ((2 * (int)position.y)/(int)tileSize.height); float x = position.x/tileSize.width - (y % 2)/2.0f; return Vec2(x, y); } // tile坐标转成瓦片格子中心的OpenGL坐标 Vec2 positionForStaggeredCoord(const Vec2& StaggeredCoord) { Size mapSize = tiledMap->getMapSize(); Size tileSize = tiledMap->getTileSize(); int x = StaggeredCoord.x*tileSize.width + ((int)StaggeredCoord.y%2)*tileSize.width/2; int y = (mapSize.height-(StaggeredCoord.y+1))*tileSize.height/2 - tileSize.height/2; return Vec2(x, y); }
45度地图坐标转换 方案二:
来自:怎样制作基于Cocos2d-x的SLG游戏-第2章
http://www.cocos.com/doc/tutorial/show?id=1609
已测试过,可用!!
Vec2 GameScene::convertTotileCoord(Vec2 position) { auto mapSize = map->getMapSize(); // 获取以tiles数量为单位的地图尺寸 // 计算当前缩放下,每块瓦片的长宽 auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width; auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height; // 把position转换为瓦片坐标,确保得到的是整数 int posx = mapSize.height - position.y / tileHeight + position.x / tileWidth - mapSize.width / 2; int posy = mapSize.height - position.y / tileHeight - position.x / tileWidth + mapSize.width / 2; return Point(posx, posy); }
// convertToScreenCoord函数中的数学公式其实就是convertTotileCoord函数中数学原理的一个反推公式 Vec2 GameScene::convertToScreenCoord(Vec2 position) { auto mapSize = map->getMapSize(); auto tileSize = map->getTileSize(); auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width; auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height; auto variable1 = (position.x + mapSize.width / 2 - mapSize.height) * tileWidth * tileHeight ; auto variable2 = (-position.y + mapSize.width / 2 + mapSize.height) * tileWidth * tileHeight ; int posx = (variable1 + variable2) / 2 / tileHeight; int posy = (variable2 - variable1) / 2 / tileWidth; return Point(posx, posy); }
45度地图坐标转换方案三:
用向量来求坐标转换公式。
已知瓦片地图坐标(m-n)求屏幕坐标(x,y):
x=size_W/2+(m-n)*tile_H/2
y=size_H+(m+n)*(-tile_W/2)
已知屏幕坐标求瓦片地图坐标:
m=(x-size_W/2)/tile_H-(y-size_H)/tile_W;
n=-(x-size_W/2)/tile_H-(y-size_H)/tile_W;
转载自:http://blog.csdn.net/ftyszyx/article/details/9020101
在游戏中,为了在二维平面呈现立体效果常常需要使用45度角地图,最近有用到,原本以为很简单,结果搞了好几天才搞明白,因此记录下,以防以后忘记
首先要清楚几个概念:
如下是一张地图
地图宽:size_W
地图高:size_H
地图块高:tile_H
地图块宽:tile_W
具体如上图所示。
现在我们假设地图上有一点A,屏幕坐标第的原理在O点基向量为(X<
b6ef
/strong>,[b]Y),地图坐标系的原点在M点,基向量分别为(MX,MY)如下图:(注意,粗体是向量)
我们现在已知A点的屏幕坐标(x,y),地图原理M的屏幕坐标(size_W/2,size_H)要求A点的地图坐标(相对于地图坐标系),假设为(m,n)
因MA=mMX+nMY
而
MX=tile_H/2X+(-tile_W/2)Y
MY=(-tile_H/2)X+(-tile_W/2)Y
所以可得MA的屏幕坐标表示:(m-n)*tile_H/2 X +(m+n)*(-tile_W/2) Y
因OA=OM+MA
所以可得OA=(size_W/2+(m-n)*tile_H/2 ) X +(size_H+(m+n)*(-tile_W/2) ) Y,
于是有了这两个等式:
x=size_W/2+(m-n)*tile_H/2
y=size_H+(m+n)*(-tile_W/2)
求解可得m=(x-size_W/2)/tile_H-(y-size_H)/tile_W;
n=-(x-size_W/2)/tile_H-(y-size_H)/tile_W;
同理,也可以根据A的地图坐标求得A的屏幕坐标:
具体程序实现如下:
//将标准坐标转为地图坐标 CCPoint MapScene::converttomapPonit(float x,float y) { //求map原点坐标 CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap); int tilewidth=map->getTileSize().width; int tilehigh=map->getTileSize().height; float mapOrginX=map->getPosition().x+map->getContentSize().width/2; float mapOrginy=map->getPosition().y+map->getContentSize().height; //O为地图的原点,A是要求的点,oa向量的值 float OA_x=x-mapOrginX; float OA_y=y-mapOrginy; //假设以地图的原点为初始坐标(正上方那个点),对应的所示点的坐标值为m,n //将地图坐标(m,n)转为标准坐标,则有: //(x,y)-(mapOrginX,mapOrginy)=m(tilewidth/2,-tilehigh/2)+n(-tilewidth/2,-tilehigh/2) //因此m=(OA_x/(tilewidth/2)+OA_y/(-tilehigh/2)/2=OA_x/tilewidth-OA_y/tilehigh //n=(OA_y/(-tilehigh/2)-OA_x/(tilewidth/2))/2=-(OA_y/tilehigh+OA_x/tilewidth) float m=OA_x/tilewidth-OA_y/tilehigh; float n=-(OA_y/tilehigh+OA_x/tilewidth); if(m<0 ) m=0; if(n<0) n=0; if(m>map->getMapSize().width-1) m=map->getMapSize().width-1; if(n>map->getMapSize().height-1) n=map->getMapSize().height-1; return CCPoint((int)m,(int)n); }
//将地图坐标转成屏幕坐标 CCPoint MapScene::convertTOSecenPoint(int x,int y) { //求map原点坐标 CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap); float tilewidth=map->getTileSize().width; float tilehigh=map->getTileSize().height; //原点下移了到方块的中心 int mapOrginX=map->getPosition().x+map->getContentSize().width/2; int mapOrginy=map->getPosition().y+map->getContentSize().height; if (x>map->getMapSize().width || x<0 || y>map->getMapSize().height || y<0) {//超出范围 return CCPoint(0,0); } float OA_x=(x-y)*tilewidth/2.0; float OA_y=-(x+y)*tilehigh/2.0; return CCPoint(mapOrginX+OA_x,mapOrginy+OA_y); }
相关文章推荐
- 自适应高度 —  按照文字 设置显示控件自适应 高度
- Java回炉之反射(一)
- IOS吐槽狂人:找工程文件
- 查看oracle数据库的连接数以及用户
- Delphi XE的RTTI增强,动态Hook某些内部事件
- 大网技术总结
- hdu5592&bestcoder Round #65 1003题
- 简单典型DFS---(解题报告)HDU1312---Red and Black
- python 中__name__ = '__main__' 的作用
- CME上配置IP phone
- 图像处理与计算机视觉基础,经典以及最近发展
- C/C++ 浮点数比较问题
- HDU 1006 Tick and Tick 模拟
- C/C++ 浮点数比较问题
- IOS吐槽狂人:卡顿和闪退
- Make 命令
- 计算机网络:应用层
- 浏览器-03 WebKit 渲染1
- hdoj The Euler function 2824 (欧拉函数打表)
- 史上最全的SpringMVC学习笔记