1. 程式人生 > >Unity LBS地圖(瓦片地圖,不接入任何SDK)

Unity LBS地圖(瓦片地圖,不接入任何SDK)

隨著現象級手遊“精靈寶可夢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