45度tile坐标转换

来源:互联网 发布:信息发布网站源码 编辑:程序博客网 时间:2024/04/28 00:39

45度地图 实际坐标与瓷砖坐标的互相转换

 (2012-02-28 16:37:59)
转载
标签: 

cocos2d

 

45度地图

 

it

分类: cocos2d

CCPoint DWMap::tilePosFromLocation(CCPoint location)
{
    // 触摸的位置信息必须减去瓷砖地图的位置信息,因为地图的位置可能在滚动变化
    CCPoint pos = ccpSub(location, m_pTileMap->getPosition());
   
    float halfMapWidth = m_pTileMap->getMapSize().width * 0.5f;
    float mapHeight    = m_pTileMap->getMapSize().height;
   
    float tileWidth    = 0.0f;
    float tileHeight   = 0.0f;
   
    //这里需要注意Retina中的TileSize
    if(CCDirector::sharedDirector()->isRetinaDisplay())
    {
        tileWidth    = m_pTileMap->getTileSize().width  / 2;
        tileHeight   = m_pTileMap->getTileSize().height / 2;
    }
    else
    {
        tileWidth    = m_pTileMap->getTileSize().width;
        tileHeight   = m_pTileMap->getTileSize().height;
    }
   
    CCPoint tilePosDiv = CCPointMake(pos.x / tileWidth, pos.y / tileHeight);
    float inverseTileY = mapHeight - tilePosDiv.y;
    // 将得到的计算结果转换成 int,以确保得到的是整数
    float posX = (int)(inverseTileY + tilePosDiv.x - halfMapWidth);
    float posY = (int)(inverseTileY - tilePosDiv.x + halfMapWidth);
   
    return CCPointMake(posX, posY);
}


CCPoint DWMap::LocationFromtilePos(CCPoint tilePos)
{
    float halfMapWidth = m_pTileMap->getMapSize().width * 0.5f;
    float mapHeight    = m_pTileMap->getMapSize().height;
   
    float tileWidth    = 0.0f;
    float tileHeight   = 0.0f;
   
    if(CCDirector::sharedDirector()->isRetinaDisplay())
    {
        tileWidth    = m_pTileMap->getTileSize().width  / 2;
        tileHeight   = m_pTileMap->getTileSize().height / 2;
    }
    else
    {
        tileWidth    = m_pTileMap->getTileSize().width;
        tileHeight   = m_pTileMap->getTileSize().height;
    }
   
    CCPoint tilePosDiv;
    CCPoint pos;
   
    tilePosDiv.y = mapHeight - (tilePos.x + tilePos.y)/2;
    tilePosDiv.x = (tilePos.x - tilePos.y)/2 + halfMapWidth;
   
    pos.x = tilePosDiv.x * tileWidth;
    pos.y = tilePosDiv.y * tileHeight;
   
    return ccpAdd(m_pTileMap->getPosition(),pos);
}
    



算法是建立在windows默认窗口坐标系下的,即X向右,Y向下为正方向。这个游戏世界里还有一个玩家角色,他显示在区域的中心。整个显示区域是随着他的移动而移动的。

 

    逻辑上的角色坐标应该是按照正方形来计算的。比如如果想往右边移动,只要增加角色的x属性数值,想往下移动只要增加角色的Y属性数值。反之则反之。我本来打算直接用像素为单位来表示万家x,y坐标,然后在屏幕上显示玩家位置的时候再把坐标转换成菱形里的坐标,可以借助公式:

 

 

x ’ = x * cos( -45 ) - y * sin( -45 );

 

y’  = x * sin( -45 ) + y * cos( -45 );

 

y’  /= 2;

 

ps:因为cos和sin是在笛卡尔坐标系中进行计算的,前面提到过的我把这个游戏建立在widnows默认坐标系上,下面我不再多说了。由于笛卡尔坐标系与windows坐标系的y轴是相反的,所以正方向旋转45度填入的参数应该是-45。考虑到使用习惯可以把系统提供的三角函数封装在自己写的函数里,只要把参数取反传给系统的三角函数即可。

 

由于在这个程序中我把整个游戏世界的大菱形显示在屏幕中央,y轴偏移了二分之一的屏幕高度,所以实际上这里代码还应该把y’加上屏幕高度的二分之一:

 

x ’ = x * cos( -45 ) - y * sin( -45 ) ;

 

y’  = x * sin( -45 ) + y * cos( -45 );

 

y’  /= 2;

 

y’ += GAME_SCREEN_HEIGHT;

 

但是这样做会遇到一些问题:

1 因为使用了浮点计算,所以可能会有精度上的问题存在。

2 用了cos和sin函数,存在效率问题,当然可以用查询表方法,但是第一个问题依然存在。

 

    前两天一个朋友告诉我人物的行走可以用小格表示,这给了我启发。一方面人的移动基本上不会是单个像素,所以没有必要以像素来作为单位,另一方面人物坐标的计算不一定非要从正方形地形的坐标转换成菱形地形的坐标。所以可以用格子的方法在菱形的地形上直接计算人物坐标。观察可以发现每当人物在正方形游戏地形中沿x轴正方向移动一个tile的时候,也就相当于在菱形游戏地形中沿着菱形的左上边方向移动一个菱形tile的边长,在windows窗口默认坐标系下就是x往正方向移动二分之一的菱形横对角线长度,y往负方向移动二分之一的菱形纵对角线长度。反之则反之,同样可以推出人物在正方形游戏地形中沿y轴移动该如何计算。当然,我们可以假设x和y是以一个小个子为单位的,如果把一个tile分成n个小格子,只要把上面的说的计算结果乘上1/n就可以了。这种方法避免了上面提出的2个问题带来的麻烦。最后的算法如下:

 

    x’ = ( PlayX + iPlayY ) * ( 64/2 )/n;
    y’ = ( iPlayY - iPlayX ) * ( 32/2 )/n; 

    y’ += GAME_SCREEN_HEIGHT / 2;

0 0