You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中基于Google API实现地图指定点缩放的技术问题求助

解决Unity中Google地图缩放时经纬度更新失效的问题

嘿,我看到你在Unity开发移动应用时,卡在了Google地图的缩放功能上——通过鼠标/触摸坐标计算新位置并更新经纬度的思路完全没问题,但落地时没成功对吧?结合我做类似功能的经验,咱们一步步拆解问题、修复代码:

常见的坑点分析

你的代码片段没写完,但这类问题通常出在三个地方:

  • 屏幕坐标到地图纹理的坐标转换错误(移动端是触摸而非鼠标,且要适配UI布局)
  • 缩放时经纬度计算逻辑偏差(没保证触摸点的经纬度在缩放后位置不变)
  • 地图纹理更新不及时(计算出新参数后没重新请求地图资源)

完整修正代码

我补全并优化了你的GoogleAPI类,兼顾移动端双指缩放和PC端鼠标滚轮调试,核心逻辑都加了注释:

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

public class GoogleAPI : MonoBehaviour
{
    // 替换成你的Google静态地图URL模板,记得加API Key
    public string urlTemplate = "https://maps.googleapis.com/maps/api/staticmap?center={0},{1}&zoom={2}&size={3}x{4}&key=YOUR_API_KEY";
    public RawImage mapImage;
    public float centerLon; // 地图中心经度
    public float centerLat; // 地图中心纬度
    public int currentZoom = 10; // 当前缩放级别(1-20为Google地图有效范围)
    public int mapWidth = 600; // 地图请求宽度
    public int mapHeight = 400; // 地图请求高度

    private RectTransform mapRect;

    void Start()
    {
        mapRect = mapImage.GetComponent<RectTransform>();
        LoadMap(); // 初始化加载地图
    }

    void Update()
    {
        // 处理移动端双指缩放
        if (Input.touchCount == 2)
        {
            Touch touch0 = Input.GetTouch(0);
            Touch touch1 = Input.GetTouch(1);

            // 计算两指距离的变化
            float prevDistance = Vector2.Distance(touch0.position - touch0.deltaPosition, touch1.position - touch1.deltaPosition);
            float currDistance = Vector2.Distance(touch0.position, touch1.position);

            if (prevDistance > 0)
            {
                float scaleFactor = currDistance / prevDistance;
                HandleZoom(scaleFactor, GetTouchMidpoint(touch0.position, touch1.position));
            }
        }
        // 处理PC端鼠标滚轮调试
        else if (Input.GetAxis("Mouse ScrollWheel") != 0)
        {
            float scrollFactor = Input.GetAxis("Mouse ScrollWheel") > 0 ? 2f : 0.5f;
            HandleZoom(scrollFactor, Input.mousePosition);
        }
    }

    // 获取双指触摸的中点坐标
    private Vector2 GetTouchMidpoint(Vector2 pos1, Vector2 pos2)
    {
        return new Vector2((pos1.x + pos2.x) / 2f, (pos1.y + pos2.y) / 2f);
    }

    // 核心缩放逻辑:保证触摸点经纬度在缩放后位置不变
    private void HandleZoom(float scaleFactor, Vector2 screenPos)
    {
        // 将屏幕坐标转换为地图UI的本地坐标
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(mapRect, screenPos, Camera.main, out Vector2 localPos))
        {
            // 计算触摸点在地图纹理上的相对比例(0-1范围)
            float xRatio = (localPos.x + mapRect.sizeDelta.x / 2f) / mapRect.sizeDelta.x;
            float yRatio = (localPos.y + mapRect.sizeDelta.y / 2f) / mapRect.sizeDelta.y;

            // 计算当前缩放级别下,地图的经纬度范围
            float currLonRange = 360f / Mathf.Pow(2, currentZoom);
            float currLatRange = 180f / Mathf.Pow(2, currentZoom);

            // 算出触摸点对应的实际经纬度
            float touchLon = centerLon - currLonRange / 2f + currLonRange * xRatio;
            float touchLat = centerLat + currLatRange / 2f - currLatRange * yRatio; // 纬度Y轴与屏幕方向相反

            // 更新缩放级别(限制在有效范围内)
            int newZoom = currentZoom + (scaleFactor > 1 ? 1 : -1);
            newZoom = Mathf.Clamp(newZoom, 1, 20);

            if (newZoom != currentZoom)
            {
                // 计算新缩放级别下的经纬度范围
                float newLonRange = 360f / Mathf.Pow(2, newZoom);
                float newLatRange = 180f / Mathf.Pow(2, newZoom);

                // 反推新的地图中心经纬度(保证触摸点位置不变)
                centerLon = touchLon - newLonRange / 2f + newLonRange * xRatio;
                centerLat = touchLat + newLatRange / 2f - newLatRange * yRatio;

                // 更新参数并重新加载地图
                currentZoom = newZoom;
                LoadMap();
            }
        }
    }

    // 向Google静态地图API请求并加载地图
    public void LoadMap()
    {
        string finalUrl = string.Format(urlTemplate, centerLat, centerLon, currentZoom, mapWidth, mapHeight);
        StartCoroutine(DownloadMap(finalUrl));
    }

    IEnumerator DownloadMap(string requestUrl)
    {
        using (WWW www = new WWW(requestUrl))
        {
            yield return www;
            if (string.IsNullOrEmpty(www.error))
            {
                mapImage.texture = www.texture;
            }
            else
            {
                Debug.LogError("地图加载失败: " + www.error);
            }
        }
    }
}

关键注意事项

  1. URL模板配置:一定要替换成你自己的Google地图API Key,否则无法请求资源
  2. 坐标转换:依赖RectTransformUtility确保屏幕坐标正确映射到地图UI区域,测试时要保证UI相机配置正确(比如用Screen Space - Overlay模式)
  3. 缩放节流:如果觉得缩放时请求太频繁,可以加一个延迟判断,比如等待0.3秒无缩放操作后再加载地图
  4. 范围限制:Google静态地图的缩放级别只能在1-20之间,代码里已经做了 clamp 处理

内容的提问来源于stack exchange,提问作者user7206653

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:56:16