如何在统一编辑器中使用Input.Location和mock位置

时间:2016-08-08 12:04:41

标签: c# unity3d

我正在建立一个基于位置的游戏,有点像口袋妖怪去。 我正在Android手机上阅读该位置没有任何问题,但是当我在Unity编辑器中进行开发时我无法获取任何位置数据,因为在编辑器中Input.location.isEnabledByUser为false

可以模拟/硬编码一个位置,这样我就可以在不部署到手机的情况下进行尝试。

我试着像这样硬编码:

LocationInfo ReadLocation(){
    #if UNITY_EDITOR

    var location = new LocationInfo();
    location.latitude = 59.000f;
    location.longitude = 18.000f;
    location.altitude= 0.0f;
    location.horizontalAccuracy = 5.0f;
    location.verticalAccuracy = 5.0f;

    return location;
    #elif
    return Input.location.lastData;
    #endif
}

但该位置的所有属性都是只读的,因此我收到了编译错误。 有没有办法在编辑器中启用位置服务,或硬编码位置?

2 个答案:

答案 0 :(得分:3)

  

有没有办法在编辑器中启用位置服务,或者硬编码   位置?

这是Unity Remote成立的原因之一。设置Unity Remote,然后将移动设备连接到编辑器。您现在可以从编辑器中获得真实的位置。

  

但该位置的所有属性都是只读的

如果你真的想开发一种模拟位置的方法,你必须放弃Unity的LocationInfo结构。制作您自己的自定义LocationInfo并将其命名为LocationInfoExt。 Ext is = Extended。

LocationService执行同样的操作,然后将官方LocationService包装到自定义LocationServiceExt类中。您可以使用LocationServiceExt来决定是否应该使用LocationInfoExt来模拟位置,或者在内部使用LocationInfo来模拟位置来提供结果。

在下面的示例中,官方LocationServiceLocationInfoLocationServiceStatus类/结构/枚举已替换为LocationServiceExtLocationInfoExt和{{1 }}。它们还具有相同的功能和属性。唯一的区别是你可以将true / false传递给LocationServiceStatusExt的构造函数,以便在编辑器中使用它。

LocationServiceExt包装类

创建一个名为LocationServiceExt的类,然后将下面的代码复制到其中: 它具有原始LocationServiceExt类的所有功能和属性。

LocationService

<强>用法

创建模拟位置

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class LocationServiceExt
{
    private LocationService realLocation;

    private bool useMockLocation = false;
    private LocationInfoExt mockedLastData;
    private LocationServiceStatusExt mockedStatus;
    private bool mIsEnabledByUser = false;

    public LocationServiceExt(bool mockLocation = false)
    {
        this.useMockLocation = mockLocation;

        if (mockLocation)
        {
            mIsEnabledByUser = true;
            mockedLastData = getMockLocation();
        }
        else
        {
            realLocation = new LocationService();
        }
    }

    public bool isEnabledByUser
    {
        //realLocation.isEnabledByUser seems to be failing on Android. Input.location.isEnabledByUser is the fix
        get { return useMockLocation ? mIsEnabledByUser : Input.location.isEnabledByUser; }
        set { mIsEnabledByUser = value; }
    }


    public LocationInfoExt lastData
    {
        get { return useMockLocation ? mockedLastData : getRealLocation(); }
        set { mockedLastData = value; }
    }

    public LocationServiceStatusExt status
    {
        get { return useMockLocation ? mockedStatus : getRealStatus(); }
        set { mockedStatus = value; }
    }

    public void Start()
    {
        if (useMockLocation)
        {
            mockedStatus = LocationServiceStatusExt.Running;
        }
        else
        {
            realLocation.Start();
        }
    }

    public void Start(float desiredAccuracyInMeters)
    {
        if (useMockLocation)
        {
            mockedStatus = LocationServiceStatusExt.Running;
        }
        else
        {
            realLocation.Start(desiredAccuracyInMeters);
        }
    }

    public void Start(float desiredAccuracyInMeters, float updateDistanceInMeters)
    {
        if (useMockLocation)
        {
            mockedStatus = LocationServiceStatusExt.Running;
        }
        else
        {
            realLocation.Start(desiredAccuracyInMeters, updateDistanceInMeters);
        }
    }

    public void Stop()
    {
        if (useMockLocation)
        {
            mockedStatus = LocationServiceStatusExt.Stopped;
        }
        else
        {
            realLocation.Stop();
        }
    }

    //Predefined Location. You always override this by overriding lastData from another class 
    private LocationInfoExt getMockLocation()
    {
        LocationInfoExt location = new LocationInfoExt();
        location.latitude = 59.000f;
        location.longitude = 18.000f;
        location.altitude = 0.0f;
        location.horizontalAccuracy = 5.0f;
        location.verticalAccuracy = 5.0f;
        location.timestamp = 0f;
        return location;
    }

    private LocationInfoExt getRealLocation()
    {
        if (realLocation == null)
            return new LocationInfoExt();

        LocationInfo realLoc = realLocation.lastData;
        LocationInfoExt location = new LocationInfoExt();
        location.latitude = realLoc.latitude;
        location.longitude = realLoc.longitude;
        location.altitude = realLoc.altitude;
        location.horizontalAccuracy = realLoc.horizontalAccuracy;
        location.verticalAccuracy = realLoc.verticalAccuracy;
        location.timestamp = realLoc.timestamp;
        return location;
    }

    private LocationServiceStatusExt getRealStatus()
    {
        LocationServiceStatus realStatus = realLocation.status;
        LocationServiceStatusExt stats = LocationServiceStatusExt.Stopped;

        if (realStatus == LocationServiceStatus.Stopped)
            stats = LocationServiceStatusExt.Stopped;

        if (realStatus == LocationServiceStatus.Initializing)
            stats = LocationServiceStatusExt.Initializing;

        if (realStatus == LocationServiceStatus.Running)
            stats = LocationServiceStatusExt.Running;

        if (realStatus == LocationServiceStatus.Failed)
            stats = LocationServiceStatusExt.Failed;

        return stats;
    }
}

public struct LocationInfoExt
{
    public float altitude { get; set; }
    public float horizontalAccuracy { get; set; }
    public float latitude { get; set; }
    public float longitude { get; set; }
    public double timestamp { get; set; }
    public float verticalAccuracy { get; set; }
}

public enum LocationServiceStatusExt
{
    Stopped = 0,
    Initializing = 1,
    Running = 2,
    Failed = 3,
}

创建一个真实的位置

LocationServiceExt locationServiceExt = new LocationServiceExt(true);

稍后在

修改位置
LocationServiceExt locationServiceExt = new LocationServiceExt(false);

来自Unity Doc的完整移植工作示例。

LocationInfoExt locInfo = new LocationInfoExt();
locInfo.latitude = 59.000f;
locInfo.longitude = 18.000f;
locInfo.altitude = -3.0f; //0.0f;
locInfo.horizontalAccuracy = 5.0f;
locInfo.verticalAccuracy = 5.0f;

locationServiceExt.lastData = locInfo; //Apply the location change

答案 1 :(得分:1)

要遵循的步骤:

首先,你需要开始GPS呼叫:

Input.location.Start();

“start”需要一些时间来初始化所有需要的进程,因此您可以这样做:

IEnumerator InitLocationTracker()
    {
        // Start service before querying location
        Input.location.Start();

        // Wait until service initializes

        if (true == disableGPSMode)
        {
            //delegate to call again "InitLocationTracker"
            if (null != OnRetryLocation)
            {
                OnRetryLocation ();
            }
            //variable to check the location available
            isLocationAvailable = false;

            yield return null;
        }
        // I chose 20s to retry the call
        int maxWait = 20;
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            // Service didn't initialize in 20 seconds
            if (maxWait < 1)
            {
                Debug.Log("LocationTracker: Timed out");

                //GameObject to show error text
                errorText.text = "LocationTracker: Timed out";
                errorPanel.SetActive(true);

                //delegate to call again "InitLocationTracker"
                if (null != OnRetryLocation)
                {
                    isLocationAvailable = false;
                    OnRetryLocation ();

                    yield break;
                }


            }

            yield return new WaitForSeconds(1f);
            maxWait--;
        }

        // Connection has failed
        if (Input.location.status == LocationServiceStatus.Failed)
        {
            Debug.Log("LocationTracker: Unable to determine device location");

            errorText.text = "LocationTracker: Unable to determine device location";
            errorPanel.SetActive(true);


            if (null != OnRetryLocation)
            {
                OnRetryLocation ();
            }

            isLocationAvailable = false;
        }
        else
        {
            Debug.Log("LocationTracker Location: " + current_lat + " " + current_lon + " " + Input.location.lastData.timestamp);
            isLocationAvailable = true;


            StartCoroutine(TrackLocation());
        }
    }

然后您可以调用并使用位置数据调用:

private float current_lat;
private float current_lon;

current_lat = Input.location.lastData.latitude;
current_lon = Input.location.lastData.longitude;

但是我会建议你调用一个协程并进行无限循环来检查你是否随时都有GPS信号。伪代码可能是这样的:

 IEnumerator TrackLocation()
{
    while (true) 
    {
        //5 seconds for example
        yield return new WaitForSeconds (5f);

        if (Input.location.status == LocationServiceStatus.Running)
        {
            //Get the location data here
        }
    }
}

最后一点,如果您需要某些点的GPS数据,您可以将协程移动到您需要的区域。由您决定如何编程GPS检查和数据使用。

资源链接(来自Unity文档)

LocationInfo

LocationService