前端瓦片地圖加載之塞爾達傳說曠野之息


zelda

背景

最近在 肝🤕 塞爾達曠野之息,希望 2022年 新作發布前可以救出公主 👸。 同時公司有地圖加載的需求,於是想以 曠野之息 地圖為例,學習實踐一下前端開發相關的地圖知識,本文內容主要介紹通過使用瓦片地圖加載原理,實現 塞爾達曠野之息 地圖加載並添加交互錨點。

基礎知識

瓦片地圖 🗺

在游戲開發過程中,經常會遇到超過屏幕大小的地圖,例如在即時戰略游戲中,它使得玩家可以在地圖中滾動游戲畫面。這類游戲通常會有豐富的背景元素,如果直接使用背景圖切換的方式,需要為每個不同的場景准備一張背景圖,但是每個背景圖都不小,這樣會造成資源浪費。

瓦片地圖就是為了解決此類問題產生的,一張大的世界地圖或者背景圖可以由幾種地形來表示,每種地形對應一張小的的圖片,我們稱這些小的地形圖片為瓦片。把這些瓦片拼接在一起,一個完整的地圖就組合出來了,這就是瓦片地圖的原理。

tile_1

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

tile_0

瓦片地圖一般采用ZXY規范的地圖瓦片。(瓦片層級、瓦片 x坐標、瓦片 y坐標

墨卡托投影

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

mercator

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

hr

實現

在本例中,塞爾達曠野之息瓦片地圖來源網絡開源地圖,加載瓦片地圖使用 Leaflet web 地圖庫,開發之前簡要了解一下。

Leaflet.js

Leaflet 🌿 (https://leafletjs.com) 是一個為建設交互性好適用於移動設備地圖,而開發的現代的、開源的 JavaScript 庫。使用它我們可以部署簡單,交互式,輕量級的Web地圖。

  • 代碼僅 33 KB,但它具有開發在線地圖的大部分功能。
  • 允許使用圖層,WMS,標記,彈出窗口,矢量圖層(折線,多邊形,圓形等),圖像疊加層和 GeoJSON 等圖層。
  • 可以通過拖動地圖,縮放(通過雙擊或滾輪滾動),使用鍵盤,使用事件處理以及拖動標記來與 Leaflet 地圖進行交互。
  • 瀏覽器支持桌面端 ChromeFirefoxSafari 5+Opera 12+IE 7-11 以及 SafariAndroidChromeFirefox等手機瀏覽器。

代碼實現

在頁面的 head 標簽中引入 Leafletcss 文件和 js 文件。在想要創建地圖的地方創建一個帶有 iddiv,示例中用 #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: '&copy; David',
  minZoom: 2,
  maxZoom: 7,
  noWrap: true,
  bounds: bounds
}).addTo(map);

map_0

確保所有代碼都在用於顯示地圖的 divleaflet.js 包含之后調用。默認情況下(因為我們在創建地圖實例時沒有設置任何參數),地圖上的所有鼠標事件和觸摸交互功能都是開啟的,並且它具有縮放和屬性控件。

此時我們在頁面中對地圖進行拖動、縮放等操作,並打開瀏覽器控制台查看 network 中的 img 選項,隨着操作的觸發,不同的地圖瓦片被瀏覽器加載顯示。

map_0.5

塞爾達曠野之息 地圖非常大,據國外 油管阿婆主 測試,林克從最北走到地圖最南端需要 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結構中添加了點擊事件,點擊神廟可以進行交互。

map_1

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

map_2

實現效果

map

在線預覽:https://dragonir.github.io/zelda-map

hr_light

總結

使用瓦片地圖,可以做到地圖的整體和局部都能高清展示,並且能夠做到按需加載,需要注意的是,分層較多的地圖瓦片圖片也會指數增長,需要做好緩存處理,這樣就能提升地圖頁面加載速度,提升用戶體驗。leaflet.js 雖然很輕量,但是功能非常強大,本例中只用到它的一些基礎功能,其他高級用法還要在后續開發中繼續探索。

參考資料

footer

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM