Getting GPS Location (Latitude, Longitude, Altitude) in Unity

This article summarizes how to obtain GPS location data (latitude, longitude, altitude) in Unity.

Introduction

I wanted to create an app that utilizes location data.

As the first step, I will organize the method to obtain location data using Unity.

# Unity Version  
2019.4.13.f1 LTS

Note: This article was translated from my original post.

Getting Location Data in Unity

Final Application

The final Unity project source code is available here:

github.com

This is a simple application that retrieves latitude, longitude, and altitude from a smartphone (Android / iOS) every 10 seconds and displays it on the screen.

Retrieve latitude(緯度), longitude(経度), altitude(高度) from a smartphone and display it as text

Below are the key points.

Script for Obtaining Location Data

The following is the C# script for obtaining location data. Unity's LocationService feature is used.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Location : MonoBehaviour
{
    public static Location Instance { set; get; }

    public float latitude;
    public float longitude;
    public float altitude;

    private void Start()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
        StartCoroutine(StartLocationService());
    }

    private IEnumerator StartLocationService()
    {
        // First, check if user has location service enabled
        if (!Input.location.isEnabledByUser)
        {
            Debug.Log("GPS not enabled");
            yield break;
        }

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

        // Wait until service initializes
        int maxWait = 20;
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            yield return new WaitForSeconds(1);
            maxWait--;
        }

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

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

        // Set locational infomations
        while (true) {
            latitude = Input.location.lastData.latitude;
            longitude = Input.location.lastData.longitude;
            altitude = Input.location.lastData.altitude;
            yield return new WaitForSeconds(10);
        }
    }
}

The code is adapted from the sample code in the Unity documentation.

The flow of the process in the coroutine is as follows:

  • Checking GPS permission
  • Starting the LocationService
  • Handling failures in LocationService startup
  • Retrieving location data from LocationService


        // First, check if user has location service enabled
        if (!Input.location.isEnabledByUser)
        {
            Debug.Log("GPS not enabled");
            yield break;
        }

First, Input.location.isEnabledByUser is checked to determine whether access to location data is allowed on the smartphone. If access is not granted, the coroutine is terminated with yield break;.


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

        // Wait until service initializes
        int maxWait = 20;
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            yield return new WaitForSeconds(1);
            maxWait--;
        }

Next, Input.location.Start(); starts the LocationService. A maximum startup time of 20 seconds is set, and it waits for the LocationService to initialize.

The implementation for waiting uses yield return new WaitForSeconds(1);, which resumes the coroutine after 1 second and keeps monitoring the status of LocationService.


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

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

Next, handling for LocationService startup failures is included. If 20 seconds pass without initialization (maxWait <= 0) or the LocationService status is Failed (Input.location.status == LocationServiceStatus.Failed), the coroutine is terminated.


        // Set locational infomations
        while (true) {
            latitude = Input.location.lastData.latitude;
            longitude = Input.location.lastData.longitude;
            altitude = Input.location.lastData.altitude;
            yield return new WaitForSeconds(10);
        }

Finally, latitude, longitude, and altitude are retrieved. Each value is obtained from Input.location.lastData.

Since I wanted to retrieve data periodically, I added a while loop with a 10-second wait between each retrieval.


Now, the location data is successfully obtained.

To access this location data from other scripts, use the Instance variable in the Location class.

For example, to display the location data in a Text UI element, use the following separate script that accesses Location.Instance:

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

public class UpdateLocationText : MonoBehaviour
{
    public Text location;

    private void Update()
    {
        location.text = $"緯度: {Location.Instance.latitude}\n経度: {Location.Instance.longitude}\n高度: {Location.Instance.altitude}\n\nCount: {Location.Instance.gps_count}\nMessage:\n{Location.Instance.message}";
    }
}

For more details, check the source project:

github.com

Conclusion

This article documented the method to obtain location data in Unity.

It is impressive how easily Unity allows access to GPS location data on a smartphone. (Godot Engine does not seem to provide location access functionality yet.)

I hope this helps someone!

[Related Articles]

en.bioerrorlog.work

References