方形瓦片地圖實現:滾動地圖
本文介紹瞭如何使用 Canvas API 實現滾動方形瓦片地圖。
注意:撰寫本文時,我們假設讀者已具備 Canvas 基礎知識,例如如何獲取 2D Canvas 上下文、載入影像等,這些內容已在 Canvas API 教程 中解釋,並且還包含了我們 瓦片地圖 入門文章中的基本資訊。本文也建立在 實現靜態方形瓦片地圖 的基礎上,如果您還沒有閱讀過,請務必先閱讀。
相機
相機是一個物件,它儲存有關當前顯示的遊戲世界或關卡部分的資訊。相機可以是自由形式的,由玩家控制(如策略遊戲中),也可以跟隨一個物件(如平臺遊戲中的主角)。
無論相機型別如何,我們總是需要關於其當前位置、視口大小等資訊。在本文提供的 演示 中,相機的引數如下:
x和y:相機的當前位置。在此實現中,我們假設(x,y)指向地圖可見部分的左上角。width和height:相機視口的大小。maxX和maxY:相機的移動限制 — 下限幾乎總是(0,0),在本例中,上限等於世界大小減去相機視口大小。
渲染地圖
渲染滾動地圖與渲染靜態地圖之間存在兩個主要區別:
-
可能會顯示部分瓦片。在靜態地圖中,渲染通常從視口左上角的瓦片開始。而在渲染滾動瓦片地圖時,第一個瓦片通常會被裁剪。
-
只會渲染地圖的一部分。如果地圖比視口大,我們一次只能顯示一部分,而不會滾動的地圖通常會完整渲染。
為了處理這些問題,我們需要稍微修改渲染演算法。我們假設相機指向 (5,10)。這意味著第一個瓦片將是 0x0。在演示程式碼中,起始點儲存在 startCol 和 startRow 中。方便的是,我們還可以預先計算要渲染的最後一個瓦片。
const startCol = Math.floor(this.camera.x / map.tsize);
const endCol = startCol + this.camera.width / map.tsize;
const startRow = Math.floor(this.camera.y / map.tsize);
const endRow = startRow + this.camera.height / map.tsize;
一旦我們確定了第一個瓦片,就需要計算它的渲染(以及其他瓦片的渲染)偏移量。由於相機指向 (5, 10),我們知道第一個瓦片應該向左上方偏移 (-5,-10) 畫素。在我們的演示中,偏移量儲存在 offsetX 和 offsetY 變數中。
const offsetX = -this.camera.x + startCol * map.tsize;
const offsetY = -this.camera.y + startRow * map.tsize;
有了這些值,渲染地圖的迴圈與用於渲染靜態瓦片地圖的迴圈非常相似。主要區別在於我們將 offsetX 和 offsetY 值加到了目標 x 和 y 座標上,並且這些值會被四捨五入,以避免相機指向浮點數位置時產生的偽影。
for (let c = startCol; c <= endCol; c++) {
for (let r = startRow; r <= endRow; r++) {
const tile = map.getTile(c, r);
const x = (c - startCol) * map.tsize + offsetX;
const y = (r - startRow) * map.tsize + offsetY;
if (tile !== 0) {
// 0 => empty tile
this.ctx.drawImage(
this.tileAtlas, // image
(tile - 1) * map.tsize, // source x
0, // source y
map.tsize, // source width
map.tsize, // source height
Math.round(x), // target x
Math.round(y), // target y
map.tsize, // target width
map.tsize, // target height
);
}
}
}
演示
我們的滾動瓦片地圖實現演示將上述程式碼整合在一起,展示了這種地圖的實現方式。您可以檢視 線上演示,並檢視 其原始碼。

還有一個 可用的演示,它展示瞭如何讓相機跟隨角色。