随着现象级手游“精灵宝可梦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