Unity 获取手机地理位置信息

Unity 获取手机地理位置信息

引言

在游戏的开发过程中,有时候会遇到需要获取玩家位置信息的需求,比如显示玩家所在的国家城市等。

有一下方法可以参考:

  • 可以根据手机的地区和语言来做判断。

  • 根据IP来判断所处的位置,阿里云啥的都有对应的接口服务。

  • 根据GPS来判断。

以上方法都各有利弊吧,这里简单介绍下根据GPS来处理的方案。

实现

Unity中不提供直接获取玩家在哪个国家哪座城市的功能,只提供获取一些GPS信息的功能,这样我们就需要根据GPS信息来获取具体的国家城市,需要借助一些第三方插件来实现。

Unity获取用户的经纬度信息

官方文档:Unity - Scripting API: LocationService.Start (unity3d.com)

我根据官方文档做了一些修改,在请求权限的时候因为使用的Unity2019,Unity提供的接口还不支持回调返回,所以这里做了一些处理。

完整代码如下:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Android;
using UnityEngine.Events;

/// <summary>
/// GPS位置管理器
/// </summary>
public class LocationManager : MonoBehaviour
{
    
    
    #region 单例
    public static LocationManager _Instance;
    public static LocationManager Instance
    {
    
    
        get
        {
    
    
            if (_Instance == null)
            {
    
    
                GameObject obj = new GameObject("LocationManager");
                _Instance = obj.AddComponent<LocationManager>();
                DontDestroyOnLoad(obj);
            }
            return _Instance;
        }
    }

    #endregion

    /// <summary>
    /// 超时时间
    /// 20秒
    /// </summary>
    private const float Time_Out = 20;

    /// <summary>
    /// 启动成功回调
    /// </summary>
    public event UnityAction<LocationInfo> SuccessCallback;

    /// <summary>
    /// 失败回调
    /// </summary>
    public event UnityAction<string> FailureCallback;

    /// <summary>
    /// 刷新回调
    /// </summary>
    public event UnityAction<LocationInfo> UpdateCallback;

    /// <summary>
    /// 停止回调
    /// </summary>
    public event UnityAction StoppedCallback;

    /// <summary>
    /// 是否开始
    /// </summary>
    private bool _IsStarted = false;

    // Start is called before the first frame update
    void Start()
    {
    
    

    }

    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.location.status == LocationServiceStatus.Running)
        {
    
    
            OnUpdate(Input.location.lastData);
        }
#if UNITY_ANDROID && !UNITY_EDITOR
        if (UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.FineLocation))
        {
    
    
            StartGPS();
        }
#endif
    }

    /// <summary>
    /// 申请权限
    /// </summary>
    public static void RequestPermission()
    {
    
    
#if UNITY_ANDROID && !UNITY_EDITOR
        string permission = UnityEngine.Android.Permission.FineLocation;
        if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission))
        {
    
    
            UnityEngine.Android.Permission.RequestUserPermission(permission);
        }
#endif
    }

    /// <summary>
    /// 初始化
    /// </summary>
    public void Init()
    {
    
    
        RequestPermission();
        StartGPS();
    }

    /// <summary>
    /// 开始定位
    /// </summary>
    private void StartGPS()
    {
    
    
        if (!Input.location.isEnabledByUser)
        {
    
    
            OnError("用户没有权限");
            return;
        }
        if (_IsStarted)
        {
    
    
            return;
        }
        _IsStarted = true;
        Input.location.Start();
        StartCoroutine(GetGPS());
    }
    private IEnumerator GetGPS()
    {
    
    
        float time = Time_Out;
        while (Input.location.status == LocationServiceStatus.Initializing && time > 0)
        {
    
    
            yield return new WaitForSeconds(1);
            time--;
        }

        if (time < 1)
        {
    
    
            OnError("Timed out");
            yield break;
        }

        if (Input.location.status == LocationServiceStatus.Failed)
        {
    
    
            OnError("Unable to determine device location");
            yield break;
        }
        else
        {
    
    
            OnStartSuccess(Input.location.lastData);
        }
    }

    /// <summary>
    /// 停止定位
    /// </summary>
    public static void StopGPS()
    {
    
    
        if (!_Instance)
        {
    
    
            return;
        }
        if (!_Instance._IsStarted)
        {
    
    
            return;
        }
        try
        {
    
    
            Input.location.Stop();
            _Instance._IsStarted = false;
        }
        catch (System.Exception)
        {
    
    
            throw;
        }
        finally
        {
    
    
            _Instance.OnStopped();
        }
    }

    /// <summary>
    /// 启动成功
    /// </summary>
    /// <param name="locationInfo"></param>
    private void OnStartSuccess(LocationInfo locationInfo)
    {
    
    
        Debug.Log("OnStartSuccess:" + locationInfo.latitude + " " + locationInfo.longitude + " " + locationInfo.altitude + " " + locationInfo.horizontalAccuracy + " " + locationInfo.timestamp);
        SuccessCallback?.Invoke(locationInfo);
    }

    /// <summary>
    /// 发生错误
    /// </summary>
    private void OnError(string errorInfo)
    {
    
    
        Debug.Log("OnError:" + errorInfo);
        FailureCallback?.Invoke(errorInfo);
        StopGPS();
    }

    /// <summary>
    /// 更新位置
    /// </summary>
    /// <param name="locationInfo"></param>
    private void OnUpdate(LocationInfo locationInfo)
    {
    
    
        UpdateCallback?.Invoke(locationInfo);
    }

    /// <summary>
    /// 停止
    /// </summary>
    private void OnStopped()
    {
    
    
        Debug.Log("OnStopped:");
        StoppedCallback?.Invoke();

        if (gameObject)
        {
    
    
            Destroy(gameObject);
            _Instance = null;
        }
    }
}

根据GPS信息获取对应的国家城市

基本上所有的地图都有这个功能,例如百度地图,谷歌地图等。

百度地图:逆地理编码 rgc 反geo检索 | 百度地图API SDK (baidu.com)

谷歌地图:反向地理编码(地址查询)请求和响应 | Geocoding API | Google Developers

简答来说就是都是通过网络请求,将GPS信息和自己创建的密钥发送给后台,后台返回对应的国家城市信息,按照指定的格式进行解析就可以了,这里就不过多介绍了。

但是想用起来都不简单,毕竟人家统计这么多地图信息也不容易。

尾语

如果有写的不好的地方,欢迎各位大佬批评指正。

猜你喜欢

转载自blog.csdn.net/yr1102358773/article/details/128949452