方形瓦片地图实现:滚动地图
本文介绍了如何使用 Canvas API 实现滚动方形瓦片地图。
注意: 编写本文时,我们假设读者已了解 Canvas 的基础知识,例如如何获取 2D Canvas 上下文、加载图像等,这些内容在 Canvas API 教程 中都有解释,我们的 瓦片地图 简介文章中也包含基本信息。本文还基于 实现静态方形瓦片地图 - 如果您还没有阅读,请先阅读。
相机
相机是一个对象,它保存有关当前显示的游戏世界或关卡的哪一部分的信息。相机可以是自由形式的,由玩家控制(例如在策略游戏中),也可以跟随某个对象(例如在平台游戏中跟随主角)。
无论相机类型如何,我们始终需要有关其当前位置、视口大小等的信息。在本文提供的 演示中,相机具有以下参数
x
和y
:相机的当前位置。在此实现中,我们假设(x,y)
指向地图可见部分的左上角。width
和height
:相机的视口大小。maxX
和maxY
:相机的定位限制 - 下限几乎始终为 (0,0),在本例中,上限等于世界大小减去相机视口大小。
渲染地图
渲染滚动地图与渲染静态地图之间有两个主要区别
- 可能会显示部分瓦片。在静态地图中,通常渲染从视口左上角的瓦片的左上角开始。而渲染滚动瓦片地图时,第一个瓦片通常会被裁剪。
- 只会渲染地图的一部分。如果地图比视口大,我们显然只能一次显示地图的一部分,而非滚动地图通常会完全渲染。
为了解决这些问题,我们需要稍微修改渲染算法。假设相机指向 (5,10)
。这意味着第一个瓦片将是 0x0
。在演示代码中,起点存储在 startCol
和 startRow
中。预先计算要渲染的最后一个瓦片也很方便。
js
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
变量中。
js
const offsetX = -this.camera.x + startCol * map.tsize;
const offsetY = -this.camera.y + startRow * map.tsize;
有了这些值,渲染地图的循环与用于渲染静态瓦片地图的循环非常相似。主要区别在于我们将 offsetX
和 offsetY
值添加到目标 x
和 y
坐标,并将这些值四舍五入,以避免相机指向浮点数位置时出现的伪像。
js
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
);
}
}
}