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

标签 c# unity3d

我正在构建一个基于位置的游戏,有点像 pokemon go。 我在我的 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
}

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

最佳答案

Is there a way to enable location service in the editor, or hardcode a location?

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

But all of the properties of the location are read only

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

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

在下面的示例中,官方的 LocationServiceLocationInfoLocationServiceStatus 类/结构/枚举被替换为 LocationServiceExtLocationInfoExtLocationServiceStatusExt。它们还实现了相同的功能和属性。唯一的区别是您可以将 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,
}

用法:

创建模拟位置

LocationServiceExt locationServiceExt = new LocationServiceExt(true);

创建真实位置

LocationServiceExt locationServiceExt = new LocationServiceExt(false);

稍后修改位置

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

来自 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();
}

关于c# - 如何在统一编辑器中使用 Input.Location 和模拟位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38828748/

相关文章:

c# - LINQ XML 子查询 - 需要帮助

c# - 如何正确关联启动另一个 Controller 传奇的多个实例的 Controller 传奇?

c# - 如何在 unity 5 中限制鼠标输入的旋转?

c# - 不使用 C# unsafe nor fixed 关键字将值写入字节数组

c# - 在 Unity 中使用 Getters 和 Setters

c# - 如何从矢量或 ImageTargets 列表生成随机目标

c# - 如何从其基类的实例创建新对象?

c# - AForge.NET 中的 "Source pixel format is not supported by the filter"错误

c# - 将数据从 C# 传递到 jQuery

c# - 从 Unity3D 发出测试请求