using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; using TMPro; // 添加场景管理命名空间 /// /// GPS坐标转换测试器(实时设备GPS版) /// 功能: /// 1. 实时获取设备GPS作为摄像机原点 /// 2. 将模型放置在指定GPS坐标 /// 3. 可视化相对位置 /// public class GPSTestRunner : MonoBehaviour { [Header("AR设置")] public Transform targetObject; // 目标物体 public Camera arCamera; // AR主摄像机 public Transform otherObject; [Header("GPS配置")] [SerializeField] [Range(1, 60)] private int gpsUpdateInterval = 1; // 秒 [SerializeField] [Range(1, 50)] private float desiredAccuracy = 5; // 米 [SerializeField] private float initializationTimeout = 20; // 秒 [Header("目标坐标")] public Vector2 targetGPS = new Vector2(36.123456f, 117.654321f); private Quaternion initialRotation; // 新增:保存初始旋转 private Vector2 currentDeviceGPS; private bool isTracking = false; private float lastUpdateTime; private bool isRefreshing = false; [Header("区域检测设置")] public Vector2 cornerPoint1 = new Vector2(36.66174f, 117.01920f); public Vector2 cornerPoint2 = new Vector2(36.66045f, 117.01930f); public Vector2 cornerPoint3 = new Vector2(36.66104f, 117.01280f); public Vector2 cornerPoint4 = new Vector2(36.66084f, 117.01290f); public string targetSceneName = "SampleScene"; public string otherSceneName = "OtherScene"; private bool hasCheckedLocation = false; [SerializeField][Header("是否测试")] private bool isTest = false; #region 测试 [SerializeField]private TMP_Text text; #endregion IEnumerator StartGPSTracking() { // 显式请求定位权限(Android需要) if (Application.platform == RuntimePlatform.Android) { if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.FineLocation)) { UnityEngine.Android.Permission.RequestUserPermission(UnityEngine.Android.Permission.FineLocation); yield return new WaitForSeconds(1); } } // 检查定位服务是否可用 if (!Input.location.isEnabledByUser) { Debug.LogError("定位服务未启用"); yield break; } // 修改启动参数为单次定位 Input.location.Start(desiredAccuracy, 0.1f); // 第二个参数0.1表示最小距离变化 float timer = 0; while (Input.location.status == LocationServiceStatus.Initializing && timer < initializationTimeout) { yield return new WaitForSeconds(1); timer++; } if (Input.location.status == LocationServiceStatus.Running) { // 仅获取一次数据后立即停止 UpdateDevicePosition(); CheckLocationAndLoadScene(); // 添加检查位置并加载场景 Input.location.Stop(); isTracking = true; // 标记为已获取 } else { Debug.LogError($"定位初始化失败: {Input.location.status}"); } } void Awake() { initialRotation = targetObject.rotation; // 保存初始旋转 } void Start() { // initialRotation = targetObject.rotation; // 保存初始旋转 StartCoroutine(StartGPSTracking()); } void Update() { if (!isTracking) return; // 每5秒检测一次区域 if (Time.time % 5f < Time.deltaTime) { CheckLocationAndLoadScene(); } // 根据设定间隔更新位置 if (Time.time - lastUpdateTime >= gpsUpdateInterval) { UpdateDevicePosition(); lastUpdateTime = Time.time; } UpdateTargetPosition(); } void UpdateDevicePosition() { currentDeviceGPS = new Vector2( Input.location.lastData.latitude, Input.location.lastData.longitude ); Debug.Log($"GPS坐标更新: {currentDeviceGPS}"); } Vector3 ConvertToLocalSpace(Vector2 target) { const float metersPerDegree = 111319.488f; float latDelta = (target.x - currentDeviceGPS.x) * metersPerDegree; float lonDelta = (target.y - currentDeviceGPS.y) * metersPerDegree * Mathf.Cos(currentDeviceGPS.x * Mathf.Deg2Rad); return new Vector3(lonDelta, 0, latDelta); } void UpdateTargetPosition() { Vector3 newPosition = ConvertToLocalSpace(targetGPS); newPosition.y = targetObject.position.y; // 保持原有Y轴 // 仅修改位置,保持初始旋转 targetObject.position = newPosition; targetObject.rotation = initialRotation; // 保持初始旋转 Debug.Log($"目标位置更新 - 位置: {newPosition}, 旋转: {initialRotation.eulerAngles}"); } void OnApplicationQuit() { if (Input.location.isEnabledByUser) Input.location.Stop(); } // void OnGUI() // { // GUIStyle labelStyle = new GUIStyle(GUI.skin.label) // { // fontSize = 24, // alignment = TextAnchor.MiddleCenter // }; // // if (!isTracking) // { // GUI.Label(new Rect(Screen.width/2 - 150, Screen.height/2 - 20, 300, 40), // "正在初始化定位服务...", // labelStyle); // } // else // { // string currentGPS = $"纬度: {currentDeviceGPS.x:F7}\n经度: {currentDeviceGPS.y:F7}"; // string targetPos = $"X: {targetObject.position.x:F7}m\nZ: {targetObject.position.z:F7}m"; // GUI.Label(new Rect(Screen.width/2 - 200, Screen.height/2 - 60, 400, 80), // $"当前坐标:\n{currentGPS}", // labelStyle); // // GUI.Label(new Rect(Screen.width/2 - 200, Screen.height/2 + 20, 400, 80), // $"目标位置:\n{targetPos}", // labelStyle); // } // } void OnDrawGizmos() { if (!isTracking) return; Gizmos.color = Color.green; Gizmos.DrawWireCube(targetObject.position, Vector3.one * 2f); Gizmos.color = Color.blue; Gizmos.DrawSphere(arCamera.transform.position, 0.5f); } public void RequestGPSUpdate() { if (!isRefreshing) { StartCoroutine(RefreshGPS()); } else { Debug.LogWarning("GPS刷新正在进行中"); } } private IEnumerator RefreshGPS() { isRefreshing = true; // 停止现有服务 if (Input.location.isEnabledByUser) { Input.location.Stop(); yield return new WaitForSeconds(0.5f); } // 启动新请求 Input.location.Start(desiredAccuracy, 0.1f); float timer = 0; while (Input.location.status == LocationServiceStatus.Initializing && timer < initializationTimeout) { timer += Time.deltaTime; yield return null; } if (Input.location.status == LocationServiceStatus.Running) { UpdateDevicePosition(); isTracking = true; Debug.Log("GPS手动更新成功"); } else { Debug.LogError($"GPS更新失败: {Input.location.status}"); } Input.location.Stop(); isRefreshing = false; } // 添加检查位置并加载场景的方法 void CheckLocationAndLoadScene() { if (hasCheckedLocation) return; // 避免重复检查 if (IsPointInRegion(currentDeviceGPS)) { Debug.Log("GPS位置在指定区域内,加载场景:" + targetSceneName); //SceneManager.LoadScene(targetSceneName); otherObject.gameObject.SetActive(false); targetObject.gameObject.SetActive(true); text.text = "GPS:" + targetSceneName; } else { Debug.Log("GPS位置不在指定区域内,加载场景:" + otherSceneName); //SceneManager.LoadScene(otherSceneName); if(isTest){ otherObject.gameObject.SetActive(false); targetObject.gameObject.SetActive(true); }else{ otherObject.gameObject.SetActive(true); targetObject.gameObject.SetActive(false); } text.text = "GPS:" + otherSceneName; } hasCheckedLocation = true; } // 判断点是否在多边形区域内 bool IsPointInRegion(Vector2 point) { Vector2[] vertices = new Vector2[] { cornerPoint1, cornerPoint2, cornerPoint4, cornerPoint3 }; return IsPointInPolygon(point, vertices); } // 使用射线法判断点是否在多边形内 bool IsPointInPolygon(Vector2 point, Vector2[] polygon) { int polygonLength = polygon.Length, i = 0; bool inside = false; // 射线法: 从点向右发射一条射线,计算与多边形边的交点数量 float pointX = point.x, pointY = point.y; float startX, startY, endX, endY; for (i = 0; i < polygonLength; i++) { startX = polygon[i].x; startY = polygon[i].y; endX = polygon[(i + 1) % polygonLength].x; endY = polygon[(i + 1) % polygonLength].y; // 检查射线与边的交点 if (((startY <= pointY && pointY < endY) || (endY <= pointY && pointY < startY)) && (pointX < (endX - startX) * (pointY - startY) / (endY - startY) + startX)) { inside = !inside; } } return inside; } // 添加公共方法,允许从外部触发位置检查 public void TriggerLocationCheck() { if (!isTracking) return; CheckLocationAndLoadScene(); } }