using packt.FoodyGo.Utils; using packt.FoodyGO.Managers; using packt.FoodyGO.Mapping; using System.Collections; using UnityEngine; namespace packt.FoodyGO.Services { [AddComponentMenu("Services/GPSLocationService")] public class GPSLocationService : Singleton { //Redraw Event public delegate void OnRedrawEvent(GameObject g); public event OnRedrawEvent OnMapRedraw; [Header("GPS Accuracy")] public float DesiredAccuracyInMeters = 10f; public float UpdateAccuracyInMeters = 10f; [Header("Map Tile Parameters")] public int MapTileScale; public int MapTileSizePixels; public int MapTileZoomLevel; [Header("GPS Simulation Settings")] public bool Simulating; public MapLocation StartCoordinates; public float Rate = 1f; public Vector2[] SimulationOffsets; private int simulationIndex; [Header("Exposed for GPS Debugging Purposes Only")] public bool IsServiceStarted; public float Latitude; public float Longitude; public float Altitude; public float Accuracy; public double Timestamp; public double PlayerTimestamp; public MapLocation mapCenter; public MapEnvelope mapEnvelope; public Vector3 mapWorldCenter; public Vector2 mapScale; public MapEnvelope mapBounds; //initialize the object void Awake() { print("Starting GPSLocationService"); #if !UNITY_EDITOR StartCoroutine(StartService()); Simulating = false; #else StartCoroutine(StartSimulationService()); Latitude = StartCoordinates.Latitude; Longitude = StartCoordinates.Longitude; Accuracy = 10; Timestamp = Epoch.Now; CenterMap(); #endif } IEnumerator StartSimulationService() { while (Simulating) { IsServiceStarted = true; if (simulationIndex++ >= SimulationOffsets.Length-1) { simulationIndex = 0; } Longitude += SimulationOffsets[simulationIndex].x; Latitude += SimulationOffsets[simulationIndex].y; PlayerTimestamp = Epoch.Now; yield return new WaitForSeconds(Rate); } IsServiceStarted = false; } //StartService is a coroutine, to avoid blocking as the location service is started IEnumerator StartService() { // First, check if user has location service enabled if (!Input.location.isEnabledByUser) { print("location not enabled by user, exiting"); yield break; } // Start service before querying location Input.location.Start(DesiredAccuracyInMeters, UpdateAccuracyInMeters); // 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 < 1) { print("Timed out"); yield break; } // Connection has failed if (Input.location.status == LocationServiceStatus.Failed) { print("Unable to determine device location."); yield break; } else { //make sure simulation is disbaled Simulating = false; print("GSPLocationService started"); // Access granted and location value could be retrieved print("Location initialized at: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp); CenterMap(); IsServiceStarted = true; } } //called once per frame void Update() { if(Input.location.status == LocationServiceStatus.Running && IsServiceStarted) { //updates the public values that can be consumed by other game objects Latitude = Input.location.lastData.latitude; Longitude = Input.location.lastData.longitude; Altitude = Input.location.lastData.altitude; Accuracy = Input.location.lastData.horizontalAccuracy; PlayerTimestamp = Input.location.lastData.timestamp; MapLocation loc = new MapLocation(Input.location.lastData.longitude, Input.location.lastData.latitude); if (mapEnvelope.Contains(loc) == false) { Timestamp = Input.location.lastData.timestamp; CenterMap(); } } else if (Simulating && IsServiceStarted) { MapLocation loc = new MapLocation(Longitude, Latitude); if (mapEnvelope.Contains(loc) == false) { Timestamp = PlayerTimestamp; CenterMap(); } } } public void MapRedrawn() { if(OnMapRedraw != null) { OnMapRedraw(this.gameObject); } } private void CenterMap() { mapCenter.Latitude = Latitude; mapCenter.Longitude = Longitude; mapWorldCenter.x = GoogleMapUtils.LonToX(mapCenter.Longitude); mapWorldCenter.y = GoogleMapUtils.LatToY(mapCenter.Latitude); mapScale.x = GoogleMapUtils.CalculateScaleX(Latitude, MapTileSizePixels, MapTileScale, MapTileZoomLevel); mapScale.y = GoogleMapUtils.CalculateScaleY(Longitude, MapTileSizePixels, MapTileScale, MapTileZoomLevel); var lon1 = GoogleMapUtils.adjustLonByPixels(Longitude, -MapTileSizePixels/2, MapTileZoomLevel); var lat1 = GoogleMapUtils.adjustLatByPixels(Latitude, MapTileSizePixels/2, MapTileZoomLevel); var lon2 = GoogleMapUtils.adjustLonByPixels(Longitude, MapTileSizePixels/2, MapTileZoomLevel); var lat2 = GoogleMapUtils.adjustLatByPixels(Latitude, -MapTileSizePixels/2, MapTileZoomLevel); mapEnvelope = new MapEnvelope(lon1, lat1, lon2, lat2); lon1 = GoogleMapUtils.adjustLonByPixels(Longitude, -MapTileSizePixels*3/2 , MapTileZoomLevel); lat1 = GoogleMapUtils.adjustLatByPixels(Latitude, MapTileSizePixels*3/2 , MapTileZoomLevel); lon2 = GoogleMapUtils.adjustLonByPixels(Longitude, MapTileSizePixels*3/2 , MapTileZoomLevel); lat2 = GoogleMapUtils.adjustLatByPixels(Latitude, -MapTileSizePixels*3/2 , MapTileZoomLevel); mapBounds = new MapEnvelope(lon1, lat1, lon2, lat2); } //called when the object is destroyed void OnDestroy() { if (IsServiceStarted) Input.location.Stop(); } public MapLocation Location { get { return new MapLocation(Longitude, Latitude); } } } }