<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
嚴格來說,瓦片的角度並不是45度。因為為了美術作圖方便,圖片的寬高比一般為2:1,如下圖所示,它的實際角度為arctan(1/2),不過這個數值對我們不重要。正如魚香肉絲沒有魚一般,叫它45度瓦片也無妨,由於它是一個菱形,所以這裡我們稱它為菱形瓦片。
寬高比為2:1的菱形瓦片
或許有人認為任意角度的瓦片都是可以的,其實不然,因為我們要考慮線條鋸齒的畫法,如果採用非整數比,則線條不是規律的(非畫素遊戲或許可以試試)。所以最常見的比例為2:1,其次是1:1。
還有一個問題,我們觀察菱形的四分之一部分,它將一個矩形一分為二。我們當然期望它是平分的,然而這根本做不到,因為它不是理論的對角線。對於正方形瓦片來說,邊緣是不會重疊的。而菱形瓦片不可避免的邊緣存在重疊。
邊緣必然重疊
我們定義地圖上的一個點為世界(World)座標,它是連續的,用浮點數表示。然後格子的索引叫地圖(Map)座標,它是離散的,用有符號整數表示。不過這裡地圖座標的取值未考慮負數,如要使用負數的地圖座標則需要對程式碼略微修改。
比如下圖的p點,我們假設格子寬10畫素。則其世界座標為(54,67),而地圖座標為(5,6)。
矩形瓦片範例
矩形瓦片的程式碼很簡單,如下:
//! 矩形瓦片地圖 template<Vector2 TILE_SIZE> class Rectangle { public: /** * @brief 地圖座標 -> 世界座標 */ constexpr Vector2 Map2World(const Point& xy) { return toVector2(xy) * TILE_SIZE; } /** * @brief 世界座標 -> 地圖座標 */ constexpr Point World2Map(const Vector2& pos) { return toPoint(pos / TILE_SIZE); } };
這裡的斜指的是,整個地圖拼出來是斜著的,也是一個菱形,如下圖所示(這是常用的演演算法):
斜菱形瓦片
我們令x'y'為地圖(格子)座標,xy為世界(畫素)座標,其中wh為瓦片寬高,則有如下關係:
上面這個式子通過簡單的變換,就可以得出:
轉換程式碼如下,這裡就體現出了將瓦片大小(TILE_SIZE)作為模板的好處了,其中除2的操作會自動合併為常數表示式,世界座標到地圖座標的轉換其中加了0.5,是為了四捨五入。
//! 斜45度瓦片地圖 template<Vector2 TILE_SIZE> class DiamondSlant { public: /** * @brief 地圖座標 -> 世界座標 */ constexpr Vector2 Map2World(const Point& xy) { return { (xy[1] + xy[0]) * TILE_SIZE[0] / 2.0, (xy[1] - xy[0]) * TILE_SIZE[1] / 2.0}; } /** * @brief 世界座標 -> 地圖座標 */ constexpr Point World2Map(const Vector2& pos) { Vector2 xy_div = pos / TILE_SIZE; return toPoint(Vector2{ xy_div[0] - xy_div[1] + 0.5, xy_div[0] + xy_div[1] - 0.5 }); } };
下面這種整體也是一個矩形,它的特點是x軸移動瓦片寬度,y軸只移動半個瓦片高度,當y為奇數時,x再往右移動半個瓦片寬度。(有些文章是y為偶數時x移動,原理相同)
正菱形瓦片
容易得到,從格子座標到世界座標,如下:
當y為偶數時:
當y為奇數時:
這裡出現和上面不一樣的事了,無法簡單的逆推公式來表示x'y'。因為通過世界(畫素)座標無法輕鬆得到它的地圖(格子)座標的y是奇數還是偶數。
從格子座標到世界座標的程式碼如下:
/** * @brief 地圖座標 -> 世界座標 */ constexpr Vector2 Map2World(const Point& xy) { Vector2 pos = { TILE_SIZE[0] * xy[0] , TILE_SIZE[1] / 2 * xy[1] }; if (xy[1] % 2 != 0) {//奇數行向右偏移 w / 2 pos[0] += TILE_SIZE[0] / 2; } return pos; }
而從世界座標到格子座標則比較麻煩了,如下,我們劃分網格:
劃分網格
明顯格子大小為(w,h),記世界座標pos所在的格子為p,則有:
來看單個劃分網格內,如下:
單個劃分格子
設瓦片格子座標為xy,則當 pos在菱形內時,有:
當 pos在菱形外時,四個角則分別判斷:右下角偏移(0,1);左下角偏移(-1,1);左上角偏移(-1,-1);右上角偏移(0,-1)。
所以最終實現程式碼如下:
//! 平菱形瓦片地圖 template<Vector2 TILE_SIZE> class DiamondFlat { public: /** * @brief 地圖座標 -> 世界座標 */ constexpr Vector2 Map2World(const Point& xy) { Vector2 pos = { TILE_SIZE[0] * xy[0] , TILE_SIZE[1] / 2 * xy[1] }; if (xy[1] % 2 != 0) {//奇數行向右偏移 w / 2 pos[0] += TILE_SIZE[0] / 2; } return pos; } /** * @brief 世界座標 -> 地圖座標 */ constexpr Point World2Map(const Vector2& pos) { constexpr Vector2 TILE_SIZE_HALF = TILE_SIZE / 2.0; //四分之一矩形面積 constexpr real s = Each::AccumulateMul(TILE_SIZE_HALF); //先計算矩形下標 Point p = toPoint(pos / TILE_SIZE); //在矩形內座標 Vector2 p1 = pos - toVector2(p) * TILE_SIZE - TILE_SIZE_HALF; //點圍成矩形面積 real sp = abs(p1[0] * TILE_SIZE_HALF[1]) + abs(p1[1] * TILE_SIZE_HALF[0]); p[1] *= 2; if (s < sp) { if (p1[0] > 0 && p1[1] > 0) return p + Point{ 0, 1 }; else if (p1[0] < 0 && p1[1] > 0) return p + Point{ -1, 1 }; else if (p1[0] < 0 && p1[1] < 0) return p + Point{ -1, -1 }; else if (p1[0] > 0 && p1[1] < 0) return p + Point{ 0, -1 }; else return p; } else { return p; } } };
如下圖所示,以菱形中心為原點建立座標系:
p在對角線上時
當p點在菱形上時,紅綠區域面積相等(對角線平分面積),所以:
(紅色區域加了兩次,將其中變成一個綠色區域)
則當p點在菱形外時,
;在菱形內時
原始碼位置:傳送門
到此這篇關於C++瓦片地圖座標轉換的實現詳解的文章就介紹到這了,更多相關C++座標轉換內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45