斜45度瓦片地圖(Staggered Tiled Map)裏的簡單數學

瓦片地圖(Tiled Map)系列文章:ui

前段時間在作遊戲的地圖編輯功能,咱們是在一個斜45度視角的場景上,對地圖上的建築或裝飾物進行添加、移動、移除等基本操做,並且位置的改變是以網格做爲最小操做單位的。本渣是用Staggered Tiled Map實現的,與垂直視角的Tiled Map不一樣,斜45度視角處理起來相對麻煩些,此次就聊聊其中一些跟數學相關的有趣問題。code

<!-- more -->blog

何爲Staggered Tiled Map?

不解釋,有圖有真相XD排序

'Orthogonal Tiled Map'
'Orthogonal Tiled Map'遊戲

'Isometric Tiled Map'
'Isometric Tiled Map'圖片

圖片描述
'Hexagonal Tiled Map'ip

‘Hexagonal Tiled Map’
‘Hexagonal Tiled Map’資源

判斷區域相交

地圖編輯的一個基礎功能即是判斷當前被編輯的建築或裝飾物的位置的合法性。這種合法性檢查主要有兩方面:一是不能放置在地圖上被禁止編輯的區域(例如地圖上的河流、山坡),這能夠經過在Tiled Map上在相應區域作上標記,判斷建築所在的區域是否有該標記就能夠了;二是不能與其餘建築或裝飾物重疊,這即是這裏主要要討論的問題了。

在實際作位置判斷時,咱們並不是按照每一個建築或裝飾物的圖片實際輪廓,而是把它們都對應到Tiled Map上一塊以網格線爲邊的區域上——在斜45度視角下,這樣的區域就是一個平行四邊形。所以,建築或裝飾物是否重疊的問題便轉化爲在Tiled Map上的兩個平行四邊形是否相交的問題。再作進一步簡化,咱們發現這其實只須要判斷任一平行四邊形的四個頂點的瓦片(tile)是否落在另外一個平行四邊形內部就能夠了。

看到這裏,你也許已經發現:這不就是中學裏簡單的代數問題嗎?判斷點是否在平行四邊形內,只須要知道平行四邊形四條邊所在直線的方程和點的座標,便迎刃而解。沒錯,Tiled Map裏每一塊瓦片區域有本身的座標,咱們只須要把一塊瓦片的座標當作點的座標,直線方程和點的座標就有了。但斜45度角Staggered Tiled Map的有趣之處在於,即使把瓦片當作點,獲得的並非一個常見的平面直角座標系。

下面咱們仍是經過圖片來看看Staggered Tiled Map的座標:

爲了方便起見,咱們把向下做爲y軸正方向,咱們能夠發現上面的座標(x, y)有着以下規律:

-- columnNum表示列數
-- columnNum = 1, 2, 3, ...
x = (columnNum - 1) % 2


-- rowNum表示行數
-- rowNum = 1, 2, 3, ...
y = rowNum - 1

看上去好像不復雜,但要列出直線方程呢?好比如下兩種可做爲平行四邊形瓦片區域的邊的直線:

一時半會懵逼了吧?使問題複雜的正是這些公式須要判斷奇偶性,能不能把奇偶性判斷拿掉呢?固然能夠,作座標轉換就能夠了,讓咱們先看一張直觀的座標轉換結果圖:

這至關於作了以下的座標轉換:

f[(x, y)] = (x * 2, y) if y mod 2 = 0

f[(x, y)] = (x * 2 + 1, y) if y mod 2 = 1

合併成一條公式也就是:

f[(x, y)] = (x * 2 + y mod 2, y)

如今是否是簡單得多了?上面兩條直線方程(由於這樣的直線斜率是肯定的,只須要知道直線上一點的座標就能夠肯定直線方程)分別是:

-- linear equation of the row line containing the point of tileCoord
local function rowEquation(tileCoord)
    return tileCoord.x * 2 + tileCoord.y % 2 + tileCoord.y
end
-- linear equation of the column line containing the point of tileCoord
local function columnEquation(tileCoord)
    return tileCoord.x * 2 + tileCoord.y % 2 - tileCoord.y
end

這個時候你應該已經發現,咱們能夠用以前簡單的代數問題解法來解決這一問題了:已知點的座標tileCoord和一個區域region四個頂點的座標(分別爲region.topregion.bottomregion.leftregion.right,事實上只須要知道其中兩個點就能夠了),判斷點是否在區域內,只須要作不等式判斷便可:

local function containsTile(region, tileCoord)
    return (rowEquation(tileCoord) >= rowEquation(region.top))
    and (rowEquation(tileCoord) <= rowEquation(region.bottom))
    and (columnEquation(tileCoord) <= columnEquation(region.top))
    and (columnEquation(tileCoord) >= columnEquation(region.bottom))

你也許會問,爲何不直接定義一套方便計算的座標系統?爲什麼要用Staggered Tiled Map原有的座標系統去作變換呢?這是由於前面所提到的作標記的非法編輯區域是採用原有的座標系統的,採用同一套座標系統加簡單的座標轉換處理比起採用兩套座標系統,在實現上和維護上的成本更低。

遮擋關係

地圖編輯的另外一個基礎需求是要處理好建築及裝飾物之間的遮擋關係。這個問題能夠轉化爲建築或裝飾物的顯示層級的排序。可是問題又來了,如何比較任意兩個建築或裝飾物的顯示前後順序呢?特別是它們還有可能隔得很遠,並無顯示上的重疊區域?

這個問題其實沒有固定答案,本渣也只是根據咱們系統的實際狀況定了一套排序規則。在本渣的規則中,建築或裝飾物的顯示層級只與它們對應的平行四邊形區域有關。本渣用每個的平行四邊形左側和右側瓦片的座標點獲得一條直線,並把平行四邊形對角線交點做爲基準點。當比較兩個建築或裝飾物的顯示前後時,先判斷兩者平行四邊形的寬度(兩條相鄰邊的tile數量),短的求基準點,長的求直線。若是點在直線下方,則點所對應的建築或裝飾物在前方;反之則在後方。

固然,本渣這套規則實際能顯示正確還有賴於美術大大們提供的建築或裝飾物圖片資源的狀況哈,若是建築或裝飾物的輪廓寬度超過它們的平行四邊形區域,仍是可能會出現顯示奇怪的地方的。

相關文章
相關標籤/搜索