
背景
最近在 肝🤕 塞爾達曠野之息,希望 2022年 新作發布前可以救出公主 👸。 同時公司有地圖加載的需求,於是想以 曠野之息 地圖為例,學習實踐一下前端開發相關的地圖知識,本文內容主要介紹通過使用瓦片地圖加載原理,實現 塞爾達曠野之息 地圖加載並添加交互錨點。
基礎知識
瓦片地圖 🗺
在游戲開發過程中,經常會遇到超過屏幕大小的地圖,例如在即時戰略游戲中,它使得玩家可以在地圖中滾動游戲畫面。這類游戲通常會有豐富的背景元素,如果直接使用背景圖切換的方式,需要為每個不同的場景准備一張背景圖,但是每個背景圖都不小,這樣會造成資源浪費。
瓦片地圖就是為了解決此類問題產生的,一張大的世界地圖或者背景圖可以由幾種地形來表示,每種地形對應一張小的的圖片,我們稱這些小的地形圖片為瓦片。把這些瓦片拼接在一起,一個完整的地圖就組合出來了,這就是瓦片地圖的原理。

瓦片地圖金字塔模型是一種多分辨率層次模型,從瓦片金字塔的底層到頂層,分辨率越來越低,但表示的地理范圍不變。 首先確定地圖服務平台所要提供的縮放級別的數量 N,把縮放級別最高、地圖比例尺最大的地圖圖片作為金字塔的底層,即第 0 層,並對其進行分塊,從地圖圖片的左上角開始,從左至右、從上到下進行切割,分割成相同大小的正方形地圖瓦片,形成第 0 層瓦片矩陣;在第 0 層地圖圖片的基礎上,按每像素分割為 2×2 個像素的方法生成第 1 層地圖圖片,並對其進行分塊,分割成與下一層相同大小的正方形地圖瓦片,形成第1層瓦片矩陣;采用同樣的方法生成第 2 層瓦片矩陣;...... 如此下去,直到第 N-1 層,構成整個瓦片金字塔。

瓦片地圖一般采用
ZXY規范的地圖瓦片。(瓦片層級、瓦片x坐標、瓦片y坐標)
墨卡托投影
瓦片地圖采用的都是墨卡托投影,即正軸等角圓柱投影,又稱等角圓柱投影, 是圓柱投影的一種,由荷蘭地圖學家墨卡托(Gerhardus Mercator)擬定。基本原理是假設地球被圍在一中空的圓柱里,其基准緯線與圓柱相切(赤道)接觸,然后再假想地球中心有一盞燈,把球面上的圖形投影到圓柱體上,再把圓柱體展開,這就是一幅選定基准緯線上的 墨卡托投影 繪制出的地圖。百度地圖、高德地圖及 Google Maps 使用的投影方法都是墨卡托投影。

瓦片地圖不用自己生成,有很多工具可以用來制作瓦片地圖,
Tiled、Arcgis等都是非常流行的制作工具。

實現
在本例中,塞爾達曠野之息瓦片地圖來源網絡開源地圖,加載瓦片地圖使用 Leaflet web 地圖庫,開發之前簡要了解一下。
Leaflet.js
Leaflet 🌿 (https://leafletjs.com) 是一個為建設交互性好適用於移動設備地圖,而開發的現代的、開源的 JavaScript 庫。使用它我們可以部署簡單,交互式,輕量級的Web地圖。
- 代碼僅
33 KB,但它具有開發在線地圖的大部分功能。 - 允許使用圖層,
WMS,標記,彈出窗口,矢量圖層(折線,多邊形,圓形等),圖像疊加層和GeoJSON等圖層。 - 可以通過拖動地圖,縮放(通過雙擊或滾輪滾動),使用鍵盤,使用事件處理以及拖動標記來與
Leaflet地圖進行交互。 - 瀏覽器支持桌面端
Chrome、Firefox、Safari 5+、Opera 12+、IE 7-11以及Safari、Android、Chrome、Firefox等手機瀏覽器。
代碼實現
在頁面的 head 標簽中引入 Leaflet的 css 文件和 js 文件。在想要創建地圖的地方創建一個帶有 id 的 div,示例中用 #mapContainer 元素承載地圖。
<head>
<link href="assets/libs/leaflet/leaflet.css" rel="stylesheet"/>
<script src="assets/libs/leaflet/leaflet-src.js"></script>
</head>
<body>
<div id="mapContainer"></div>
</body>
需要確保地圖有一個明確的高度, 可以在 CSS 中添加如下全屏顯示的樣式。
#mapContainer {
width: 100%;
height: 100%;
}
現在地圖的初始化已經完成了,這一步進行瓦片地圖加載。
L.LatLngBounds(西南角點,東北角點):通過定義矩形西南角點和東北角點來創建經緯度的矩形框。setView:初始化地圖,並將其視圖設置為我們所選擇的地理坐標和縮放級別。L.tileLayer:加載瓦片圖層。addTo:顯示地圖。
var bounds = new L.LatLngBounds(
new L.LatLng(-49.875, 34.25), new L.LatLng(-206, 221)
);
var map = L.map('mapContainer', {
crs: L.CRS.Simple,
attributionControl: false,
maxBounds: bounds,
maxBoundsViscosity: 1.0,
}).setView([0, 0], 2);
var layer = L.tileLayer('assets/maps/{z}_{x}_{y}.png', {
attribution: '© David',
minZoom: 2,
maxZoom: 7,
noWrap: true,
bounds: bounds
}).addTo(map);

確保所有代碼都在用於顯示地圖的
div和leaflet.js包含之后調用。默認情況下(因為我們在創建地圖實例時沒有設置任何參數),地圖上的所有鼠標事件和觸摸交互功能都是開啟的,並且它具有縮放和屬性控件。
此時我們在頁面中對地圖進行拖動、縮放等操作,並打開瀏覽器控制台查看 network 中的 img 選項,隨着操作的觸發,不同的地圖瓦片被瀏覽器加載顯示。

塞爾達曠野之息 地圖非常大,據國外 油管阿婆主 測試,林克從最北走到地圖最南端需要 20 多分鍾。在如此宏大的地圖上進行游戲,探索的神廟、地圖塔、人馬等怪物點等位置需要花很大精力,如果使用已有數據進行標注,可以節省很多精力(但也失去了探索的樂趣 😂)。此時可以利用 Leaflet 的地圖標注功能,在地圖上進行標記。其中標注數據來源於網絡資料。以下內容以神廟 🛕 為例,實現在瓦片地圖上的標注和交互功能。
L.marker([x, y]):除了瓦片之外,可以輕松地在地圖中添加其他東西,包括標記、折線、多邊形、圓圈和彈出窗口。L.divIcon: 自定義圖標。bindPopup: 彈出窗口通常用於將某些信息附加到地圖上的特定對象上。
$.each(markerData, function () {
var key = this.markerCategoryId + "-" + this.id + "-" + this.name.replace(/[^A-Z]/gi, "-");
var popupHtml = '<div class="popupContainer">';
popupHtml += '<strong class="name">' + this.name + '</strong>';
popupHtml += '<div class="buttonContainer">';
popupHtml += '<span class="markButton" onclick="markPoint(this)" data-key="' + key + '">標記</span>';
popupHtml += '</div>';
var className = "mark-" + key;
className += " markIcon";
className += " icon-" + markerStyle[this.markerCategoryId];
var marker = L.marker([this.y, this.x], {
title: this.name,
icon: L.divIcon({
className: className,
iconSize: [20, 20],
iconAnchor: [10, 10],
popupAnchor: [0, -10],
})
}).addTo(map).bindPopup(popupHtml);
});
至此,通過遍歷,將數據中神廟的坐標點添加到了地圖上,同時在dom結構中添加了點擊事件,點擊神廟可以進行交互。

使用同樣的方法,可以將地圖塔、村庄、人馬、呀哈哈 😂、回憶點、子任務點等位置信息標注在地圖中方便查找。

實現效果


總結
使用瓦片地圖,可以做到地圖的整體和局部都能高清展示,並且能夠做到按需加載,需要注意的是,分層較多的地圖瓦片圖片也會指數增長,需要做好緩存處理,這樣就能提升地圖頁面加載速度,提升用戶體驗。leaflet.js 雖然很輕量,但是功能非常強大,本例中只用到它的一些基礎功能,其他高級用法還要在后續開發中繼續探索。
參考資料
- 塞爾達曠野之息地圖標注來源:https://github.com
- 瓦片地圖生成工具
Tiled項目:https://www.mapeditor.org - 瓦片地圖生成工具
arcgis:https://developers.arcgis.com - 開放地理空間實驗室
Leaflet.js: http://webgis.cn/leaflet-index.html - 墨卡托投影:https://baike.baidu.com/item/墨卡托投影
- https://www.cnblogs.com/fwc1994/p/6519229.html
- ZXY標准瓦片 http://support.supermap.com.cn/DataWarehouse/WebDocHelp/iServer/Subject_introduce/Cache/MapCache/TileFormat/ZXY_format.htm

作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/15265372.html
