Unity LBS地圖(瓦片地圖,不接入任何SDK)
阿新 • • 發佈:2019-02-01
隨著現象級手遊“精靈寶可夢GO”的走紅,許多手遊都想接入LBS社交,基於地理位置互動的LBS功能。那麼在Unity中怎麼實現LBS地圖呢,最簡單的接入地圖SDK,像百度地圖、高德地圖,一些常用到的功能都有了,像“陰陽師”的LBS就是接入的高德地圖。但接入SDK的方式,有個麻煩的問題,須要針對Android各IOS分別接入,主要是接入後的功能玩法都要用Android的java和IOS的OC去實現,這樣就要同時維護兩份程式碼了,而且測試還得在手機上測,甚是麻煩,還可能有裝置相容問題。經過一番研究,發現了一種實現方法,瓦片地圖,可直接在Unity中用C#實現,不限平臺。
網際網路地圖服務商的線上地圖都通過瓦片的方式提供,稱為瓦片地圖服務。最常見的地圖瓦片是圖片格式的,一般大小為256*256。瓦片地圖就是把地圖當作一張大圖,在幾個不同的縮放比例下,按大小固定切分為許多瓦片,這樣每張瓦片圖的經緯度就可以定位到了。如此,可根據給定的經緯度求得對應縮放比例下的瓦片,然後根據瓦片地圖座標x、y增減可求得周邊的瓦片。那麼一張瓦片圖就可以用瓦片座標x、y和縮放比例z確定了。例如百度地圖http://online1.map.bdimg.com/onlinelabel/?qt=tile&x=49310&y=10242&z=18,就是瓦片座標x=49310,y=10242,在縮放比例為18的一張瓦片圖了。
//將tile(瓦片)座標系轉換為LatLngt(地理)座標系,pixelX,pixelY為圖片偏移畫素座標 public static LatLng TileXYToLatLng(int tileX, int tileY, int zoom, int pixelX = 0, int pixelY = 0) { double size = Math.Pow(2, zoom); double pixelXToTileAddition = pixelX / 256.0; double lng = (tileX + pixelXToTileAddition) / size * 360.0 - 180.0; double pixelYToTileAddition = pixelY / 256.0; double lat = Math.Atan(Math.Sinh(Math.PI * (1 - 2 * (tileY + pixelYToTileAddition) / size))) * 180.0 / Math.PI; return new LatLng(lng, lat); }
也可以根據瓦片座標計算對應的經緯度
//將LatLngt地理座標系轉換為tile瓦片座標系,pixelX,pixelY為圖片偏移畫素座標 public static void LatLngToTileXY(LatLng latlng, int zoom, out int tileX, out int tileY, out int pixelX, out int pixelY) { double size = Math.Pow(2, zoom); double x = ((latlng.Longitude + 180) / 360) * size; double lat_rad = latlng.Latitude * Math.PI / 180; double y = (1 - Math.Log(Math.Tan(lat_rad) + 1 / Math.Cos(lat_rad)) / Math.PI) / 2; y = y * size; tileX = (int)x; tileY = (int)y; pixelX = (int)((x - tileX) * 256); pixelY = (int)((y - tileY) * 256); }
如此這樣,就可以把一張張瓦片圖拼成地圖了,仔細看下百度地圖或高德地圖,好像也是這樣一張張小圖載入來實現的。最簡單的實現:先定位到自己的經緯度,求得對應縮放比例z下的瓦片座標,載入對應的瓦片地圖和周邊的瓦片地圖,拖動時再載入相鄰的瓦片,縮放時,清除當前所有的圖片,再求得中心點的瓦片座標,這樣就可以實現一個基本地圖了。那麼在unity中按這樣實現就非常方便了,想在地圖上加什麼功能都非常方便,也不用考慮平臺的問題。例如可以隨意加上任何Marker。甚至用3D實現也不成問題。 另上Unity中定位程式碼
using UnityEngine;
using System.Collections;
public class Location : MonoBehaviour
{
IEnumerator Start()
{
if (!Input.location.isEnabledByUser)
{
Debug.LogError("Location is not enabled");
yield break;
}
Input.location.Start();
int maxWait = 30;
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
{
yield return new WaitForSeconds(1);
maxWait--;
}
if (maxWait < 1)
{
Debug.LogError("Location time out");
yield break;
}
if (Input.location.status == LocationServiceStatus.Failed)
{
Debug.LogError("Unable to determine device location");
yield break;
}
else
{
LatLng latlng = new LatLng(Input.location.lastData.longitude, Input.location.lastData.latitude);
Debug.Log(latlng);
}
Input.location.Stop();
}
}
參考文章:
http://www.jianshu.com/p/0b292688b6af