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

Emi*_*mil 5 c# unity-game-engine

我正在开发一款基于位置的游戏,有点像口袋妖怪游戏。我正在阅读Android手机上的位置,没有任何问题,但是在统一编辑器中进行开发时,我无法获取任何位置数据,因为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
}
Run Code Online (Sandbox Code Playgroud)

但是该位置的所有属性都是只读的,因此出现编译错误。是否可以在编辑器中启用位置服务或对位置进行硬编码?

Pro*_*mer 5

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

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

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

如果你真的想开发一种模拟位置的方法,你就必须放弃Unity的LocationInfo结构。进行您自己的定制LocationInfo并命名LocationInfoExt。Ext = 扩展。

也做同样的事情LocationService,然后将官方包装LocationService到您的自定义LocationServiceExt类中。您可以用来LocationServiceExt决定是否应该通过使用模拟位置来模拟位置LocationInfoExt,或者不通过内部使用来模拟位置LocationInfo来提供结果。

在下面的示例中,官方的LocationService, LocationInfoLocationServiceStatusclass/struct/enum 被替换为LocationServiceExt,LocationInfoExtLocationServiceStatusExt。它们还实现了相同的功能和属性。唯一的区别是您可以将 true/false 传递给 的构造函数 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,
}
Run Code Online (Sandbox Code Playgroud)

用法

创建模拟位置

LocationServiceExt locationServiceExt = new LocationServiceExt(true);
Run Code Online (Sandbox Code Playgroud)

创建真实位置

LocationServiceExt locationServiceExt = new LocationServiceExt(false);
Run Code Online (Sandbox Code Playgroud)

稍后修改位置

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
Run Code Online (Sandbox Code Playgroud)

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

public Text text;
IEnumerator StartGPS()
{
    text.text = "Starting";
    //Pass true to use mocked Location. Pass false or don't pass anything to use real location
    LocationServiceExt locationServiceExt = new LocationServiceExt(true);

    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;

    // First, check if user has location service enabled
    if (!locationServiceExt.isEnabledByUser)
    {
        text.text = "Not Enabled";
        yield break;
    }
    else
    {
        text.text = "Enabled!";
    }

    // Start service before querying location
    locationServiceExt.Start();


    // Wait until service initializes
    int maxWait = 20;
    while (locationServiceExt.status == LocationServiceStatusExt.Initializing && maxWait > 0)
    {
        text.text = "Timer: " + maxWait;
        yield return new WaitForSeconds(1);
        maxWait--;
    }

    // Service didn't initialize in 20 seconds
    if (maxWait < 1)
    {
        print("Timed out");
        text.text = "Timed out";
        yield break;
    }

    // Connection has failed
    if (locationServiceExt.status == LocationServiceStatusExt.Failed)
    {
        print("Unable to determine device location");
        text.text = "Unable to determine device location";
        yield break;
    }
    else
    {
        // Access granted and location value could be retrieved
        string location = "Location: " + locationServiceExt.lastData.latitude + " "
            + locationServiceExt.lastData.longitude + " " + locationServiceExt.lastData.altitude
            + " " + locationServiceExt.lastData.horizontalAccuracy + " " + locationServiceExt.lastData.timestamp;
        Debug.Log(location);
        text.text = location;
    }

    // Stop service if there is no need to query location updates continuously
    locationServiceExt.Stop();
}
Run Code Online (Sandbox Code Playgroud)