瓦片地图转换详解

1、普通直角地图坐标转换

[cpp] view plain copy
  1. // OpenGL坐标转成格子坐标  
  2. Vec2 tileCoordForPosition(const Vec2& position)  
  3. {  
  4.     Size mapSize = tiledMap->getMapSize();      // 获取以tiles数量为单位的地图尺寸  
  5.     Size tileSize = tiledMap->getTileSize();    // 获取以像素点为单位的tile尺寸属性  
  6.     int x = position.x / tileSize.width;  
  7.     int y = (mapSize.height*tileSize.height - position.y) / tileSize.height;  
  8.     return Vec2(x, y);  
  9. }  
  10. // tile坐标转成瓦片格子中心的OpenGL坐标  
  11. Vec2 positionForTileCoord(const Vec2& tileCoord)   
  12. {  
  13.     Size mapSize = tiledMap->getMapSize();  
  14.     Size tileSize = tiledMap->getTileSize();  
  15.     int x = tileCoord.x * tileSize.width + tileSize.width/2;  
  16.     int y = (mapSize.height-tileCoord.y)*tileSize.height - tileSize.height/2;  
  17.     return Vec2(x, y);  
  18. }  
2、45度地图坐标转换 
3、45度交错地图坐标转换
[cpp] view plain copy
  1. // OpenGL坐标转成格子坐标  
  2. Vec2 staggeredCoordForPosition(CCPoint position)  
  3. {  
  4.     Size mapSize = tiledMap->getMapSize();  
  5.     Size tileSize = tiledMap->getTileSize();  
  6.     int y = mapSize.height - 2 - ((2 * (int)position.y)/(int)tileSize.height);  
  7.     float x = position.x/tileSize.width - (y % 2)/2.0f;  
  8.     return Vec2(x, y);  
  9. }  
  10. // tile坐标转成瓦片格子中心的OpenGL坐标  
  11. Vec2 positionForStaggeredCoord(const Vec2& StaggeredCoord)  
  12. {  
  13.     Size mapSize = tiledMap->getMapSize();  
  14.     Size tileSize = tiledMap->getTileSize();  
  15.     int x = StaggeredCoord.x*tileSize.width + ((int)StaggeredCoord.y%2)*tileSize.width/2;  
  16.     int y = (mapSize.height-(StaggeredCoord.y+1))*tileSize.height/2 - tileSize.height/2;  
  17.     return Vec2(x, y);  
  18. }  

45度地图坐标转换 方案二:
来自:怎样制作基于Cocos2d-x的SLG游戏-第2章
已测试过,可用!!

[cpp] view plain copy
  1. Vec2 GameScene::convertTotileCoord(Vec2 position)  
  2. {  
  3.     auto mapSize = map->getMapSize();        // 获取以tiles数量为单位的地图尺寸  
  4.     // 计算当前缩放下,每块瓦片的长宽  
  5.     auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width;  
  6.     auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height;  
  7.     // 把position转换为瓦片坐标,确保得到的是整数  
  8.     int posx = mapSize.height - position.y / tileHeight + position.x / tileWidth - mapSize.width / 2;  
  9.     int posy = mapSize.height - position.y / tileHeight - position.x / tileWidth + mapSize.width / 2;  
  10.    
  11.     return Point(posx, posy);  
  12. }  
[cpp] view plain copy
  1. // convertToScreenCoord函数中的数学公式其实就是convertTotileCoord函数中数学原理的一个反推公式  
  2. Vec2 GameScene::convertToScreenCoord(Vec2 position)  
  3. {  
  4.     auto mapSize = map->getMapSize();  
  5.     auto tileSize = map->getTileSize();  
  6.     auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width;  
  7.     auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height;  
  8.    
  9.     auto variable1 = (position.x + mapSize.width / 2 - mapSize.height) * tileWidth * tileHeight ;  
  10.     auto variable2 = (-position.y + mapSize.width / 2 + mapSize.height) * tileWidth * tileHeight ;  
  11.    
  12.     int posx = (variable1 + variable2) / 2 / tileHeight;  
  13.     int posy = (variable2 - variable1) / 2 / tileWidth;  
  14.    
  15.     return Point(posx, posy);  
  16. }  




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.****.net/ftyszyx/article/details/9020101

在游戏中,为了在二维平面呈现立体效果常常需要使用45度角地图,最近有用到,原本以为很简单,结果搞了好几天才搞明白,因此记录下,以防以后忘记

首先要清楚几个概念:

如下是一张地图

瓦片地图转换详解

地图宽:size_W

地图高:size_H

地图块高:tile_H

地图块宽:tile_W

具体如上图所示。


现在我们假设地图上有一点A,屏幕坐标第的原理在O点基向量为(XY),地图坐标系的原点在M点,基向量分别为(MXMY)如下图:(注意,粗体是向量)

瓦片地图转换详解

我们现在已知A点的屏幕坐标(x,y),地图原理M的屏幕坐标(size_W/2,size_H)要求A点的地图坐标(相对于地图坐标系),假设为(m,n)

MA=mMX+nMY

MX=tile_W/2X+(-tile_H/2)Y

MY=(-tile_W/2)X+(-tile_H/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的屏幕坐标:

具体程序实现如下:

[cpp] view plain copy
  1. //将标准坐标转为地图坐标    
  2. CCPoint MapScene::converttomapPonit(float x,float y)    
  3. {    
  4.     //求map原点坐标    
  5.     CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);    
  6.     int tilewidth=map->getTileSize().width;    
  7.     int tilehigh=map->getTileSize().height;    
  8.     float mapOrginX=map->getPosition().x+map->getContentSize().width/2;    
  9.     float mapOrginy=map->getPosition().y+map->getContentSize().height;    
  10.     //O为地图的原点,A是要求的点,oa向量的值    
  11.     float OA_x=x-mapOrginX;    
  12.     float OA_y=y-mapOrginy;    
  13.     //假设以地图的原点为初始坐标(正上方那个点),对应的所示点的坐标值为m,n    
  14.     //将地图坐标(m,n)转为标准坐标,则有:    
  15.     //(x,y)-(mapOrginX,mapOrginy)=m(tilewidth/2,-tilehigh/2)+n(-tilewidth/2,-tilehigh/2)    
  16.     //因此m=(OA_x/(tilewidth/2)+OA_y/(-tilehigh/2)/2=OA_x/tilewidth-OA_y/tilehigh    
  17.     //n=(OA_y/(-tilehigh/2)-OA_x/(tilewidth/2))/2=-(OA_y/tilehigh+OA_x/tilewidth)    
  18.     float m=OA_x/tilewidth-OA_y/tilehigh;    
  19.     float n=-(OA_y/tilehigh+OA_x/tilewidth);    
  20.     if(m<0 ) m=0;    
  21.     if(n<0) n=0;    
  22.     if(m>map->getMapSize().width-1) m=map->getMapSize().width-1;    
  23.     if(n>map->getMapSize().height-1) n=map->getMapSize().height-1;    
  24.     return CCPoint((int)m,(int)n);    
  25. }    
[cpp] view plain copy
  1. //将地图坐标转成屏幕坐标    
  2. CCPoint MapScene::convertTOSecenPoint(int x,int y)    
  3. {    
  4.     //求map原点坐标    
  5.     CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);    
  6.     float tilewidth=map->getTileSize().width;    
  7.     float tilehigh=map->getTileSize().height;    
  8.     //原点下移了到方块的中心    
  9.     int mapOrginX=map->getPosition().x+map->getContentSize().width/2;    
  10.     int mapOrginy=map->getPosition().y+map->getContentSize().height;    
  11.     if (x>map->getMapSize().width || x<0    
  12.         || y>map->getMapSize().height || y<0)    
  13.     {//超出范围    
  14.         return CCPoint(0,0);    
  15.     }    
  16.     float OA_x=(x-y)*tilewidth/2.0;    
  17.     float OA_y=-(x+y)*tilehigh/2.0;    
  18.     return CCPoint(mapOrginX+OA_x,mapOrginy+OA_y);    
  19. }    

1、普通直角地图坐标转换

[cpp] view plain copy
  1. // OpenGL坐标转成格子坐标  
  2. Vec2 tileCoordForPosition(const Vec2& position)  
  3. {  
  4.     Size mapSize = tiledMap->getMapSize();      // 获取以tiles数量为单位的地图尺寸  
  5.     Size tileSize = tiledMap->getTileSize();    // 获取以像素点为单位的tile尺寸属性  
  6.     int x = position.x / tileSize.width;  
  7.     int y = (mapSize.height*tileSize.height - position.y) / tileSize.height;  
  8.     return Vec2(x, y);  
  9. }  
  10. // tile坐标转成瓦片格子中心的OpenGL坐标  
  11. Vec2 positionForTileCoord(const Vec2& tileCoord)   
  12. {  
  13.     Size mapSize = tiledMap->getMapSize();  
  14.     Size tileSize = tiledMap->getTileSize();  
  15.     int x = tileCoord.x * tileSize.width + tileSize.width/2;  
  16.     int y = (mapSize.height-tileCoord.y)*tileSize.height - tileSize.height/2;  
  17.     return Vec2(x, y);  
  18. }  
2、45度地图坐标转换 
3、45度交错地图坐标转换
[cpp] view plain copy
  1. // OpenGL坐标转成格子坐标  
  2. Vec2 staggeredCoordForPosition(CCPoint position)  
  3. {  
  4.     Size mapSize = tiledMap->getMapSize();  
  5.     Size tileSize = tiledMap->getTileSize();  
  6.     int y = mapSize.height - 2 - ((2 * (int)position.y)/(int)tileSize.height);  
  7.     float x = position.x/tileSize.width - (y % 2)/2.0f;  
  8.     return Vec2(x, y);  
  9. }  
  10. // tile坐标转成瓦片格子中心的OpenGL坐标  
  11. Vec2 positionForStaggeredCoord(const Vec2& StaggeredCoord)  
  12. {  
  13.     Size mapSize = tiledMap->getMapSize();  
  14.     Size tileSize = tiledMap->getTileSize();  
  15.     int x = StaggeredCoord.x*tileSize.width + ((int)StaggeredCoord.y%2)*tileSize.width/2;  
  16.     int y = (mapSize.height-(StaggeredCoord.y+1))*tileSize.height/2 - tileSize.height/2;  
  17.     return Vec2(x, y);  
  18. }  

45度地图坐标转换 方案二:来自:怎样制作基于Cocos2d-x的SLG游戏-第2章http://www.cocos.com/doc/tutorial/show?id=1609已测试过,可用!!

[cpp] view plain copy
  1. Vec2 GameScene::convertTotileCoord(Vec2 position)  
  2. {  
  3.     auto mapSize = map->getMapSize();        // 获取以tiles数量为单位的地图尺寸  
  4.     // 计算当前缩放下,每块瓦片的长宽  
  5.     auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width;  
  6.     auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height;  
  7.     // 把position转换为瓦片坐标,确保得到的是整数  
  8.     int posx = mapSize.height - position.y / tileHeight + position.x / tileWidth - mapSize.width / 2;  
  9.     int posy = mapSize.height - position.y / tileHeight - position.x / tileWidth + mapSize.width / 2;  
  10.    
  11.     return Point(posx, posy);  
  12. }  
[cpp] view plain copy
  1. // convertToScreenCoord函数中的数学公式其实就是convertTotileCoord函数中数学原理的一个反推公式  
  2. Vec2 GameScene::convertToScreenCoord(Vec2 position)  
  3. {  
  4.     auto mapSize = map->getMapSize();  
  5.     auto tileSize = map->getTileSize();  
  6.     auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width;  
  7.     auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height;  
  8.    
  9.     auto variable1 = (position.x + mapSize.width / 2 - mapSize.height) * tileWidth * tileHeight ;  
  10.     auto variable2 = (-position.y + mapSize.width / 2 + mapSize.height) * tileWidth * tileHeight ;  
  11.    
  12.     int posx = (variable1 + variable2) / 2 / tileHeight;  
  13.     int posy = (variable2 - variable1) / 2 / tileWidth;  
  14.    
  15.     return Point(posx, posy);  
  16. }  




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.****.net/ftyszyx/article/details/9020101

在游戏中,为了在二维平面呈现立体效果常常需要使用45度角地图,最近有用到,原本以为很简单,结果搞了好几天才搞明白,因此记录下,以防以后忘记

首先要清楚几个概念:

如下是一张地图

瓦片地图转换详解

地图宽:size_W

地图高:size_H

地图块高:tile_H

地图块宽:tile_W

具体如上图所示。


现在我们假设地图上有一点A,屏幕坐标第的原理在O点基向量为(XY),地图坐标系的原点在M点,基向量分别为(MXMY)如下图:(注意,粗体是向量)

瓦片地图转换详解

我们现在已知A点的屏幕坐标(x,y),地图原理M的屏幕坐标(size_W/2,size_H)要求A点的地图坐标(相对于地图坐标系),假设为(m,n)

MA=mMX+nMY

MX=tile_W/2X+(-tile_H/2)Y

MY=(-tile_W/2)X+(-tile_H/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的屏幕坐标:

具体程序实现如下:

[cpp] view plain copy
  1. //将标准坐标转为地图坐标    
  2. CCPoint MapScene::converttomapPonit(float x,float y)    
  3. {    
  4.     //求map原点坐标    
  5.     CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);    
  6.     int tilewidth=map->getTileSize().width;    
  7.     int tilehigh=map->getTileSize().height;    
  8.     float mapOrginX=map->getPosition().x+map->getContentSize().width/2;    
  9.     float mapOrginy=map->getPosition().y+map->getContentSize().height;    
  10.     //O为地图的原点,A是要求的点,oa向量的值    
  11.     float OA_x=x-mapOrginX;    
  12.     float OA_y=y-mapOrginy;    
  13.     //假设以地图的原点为初始坐标(正上方那个点),对应的所示点的坐标值为m,n    
  14.     //将地图坐标(m,n)转为标准坐标,则有:    
  15.     //(x,y)-(mapOrginX,mapOrginy)=m(tilewidth/2,-tilehigh/2)+n(-tilewidth/2,-tilehigh/2)    
  16.     //因此m=(OA_x/(tilewidth/2)+OA_y/(-tilehigh/2)/2=OA_x/tilewidth-OA_y/tilehigh    
  17.     //n=(OA_y/(-tilehigh/2)-OA_x/(tilewidth/2))/2=-(OA_y/tilehigh+OA_x/tilewidth)    
  18.     float m=OA_x/tilewidth-OA_y/tilehigh;    
  19.     float n=-(OA_y/tilehigh+OA_x/tilewidth);    
  20.     if(m<0 ) m=0;    
  21.     if(n<0) n=0;    
  22.     if(m>map->getMapSize().width-1) m=map->getMapSize().width-1;    
  23.     if(n>map->getMapSize().height-1) n=map->getMapSize().height-1;    
  24.     return CCPoint((int)m,(int)n);    
  25. }    
[cpp] view plain copy
  1. //将地图坐标转成屏幕坐标    
  2. CCPoint MapScene::convertTOSecenPoint(int x,int y)    
  3. {    
  4.     //求map原点坐标    
  5.     CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);    
  6.     float tilewidth=map->getTileSize().width;    
  7.     float tilehigh=map->getTileSize().height;    
  8.     //原点下移了到方块的中心    
  9.     int mapOrginX=map->getPosition().x+map->getContentSize().width/2;    
  10.     int mapOrginy=map->getPosition().y+map->getContentSize().height;    
  11.     if (x>map->getMapSize().width || x<0    
  12.         || y>map->getMapSize().height || y<0)    
  13.     {//超出范围    
  14.         return CCPoint(0,0);    
  15.     }    
  16.     float OA_x=(x-y)*tilewidth/2.0;    
  17.     float OA_y=-(x+y)*tilehigh/2.0;    
  18.     return CCPoint(mapOrginX+OA_x,mapOrginy+OA_y);    
  19. }    
[cpp] view plain copy
  1. // convertToScreenCoord函数中的数学公式其实就是convertTotileCoord函数中数学原理的一个反推公式  
  2. Vec2 GameScene::convertToScreenCoord(Vec2 position)  
  3. {  
  4.     auto mapSize = map->getMapSize();  
  5.     auto tileSize = map->getTileSize();  
  6.     auto tileWidth = map->getBoundingBox().size.width / map->getMapSize().width;  
  7.     auto tileHeight = map->getBoundingBox().size.height / map->getMapSize().height;  
  8.    
  9.     auto variable1 = (position.x + mapSize.width / 2 - mapSize.height) * tileWidth * tileHeight ;  
  10.     auto variable2 = (-position.y + mapSize.width / 2 + mapSize.height) * tileWidth * tileHeight ;  
  11.    
  12.     int posx = (variable1 + variable2) / 2 / tileHeight;  
  13.     int posy = (variable2 - variable1) / 2 / tileWidth;  
  14.    
  15.     return Point(posx, posy);  
  16. }