Unity中2D地图缩放时玩家图标位置偏移问题排查与解决
3D游戏2D地图玩家图标缩放偏移问题解决
问题描述
我正在为3D游戏制作一款非迷你型2D地图,希望该地图可独立于游戏环境尺寸进行缩放,同时能在2D地图上以图标形式精准显示玩家位置。当前使用脚本时,玩家图标位置大致正确,但缩放地图时图标位置会发生偏移,期望调整2D地图大小(放大或缩小)时,玩家图标能保持与缩放前一致的对应位置。
原始脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Finalmap : MonoBehaviour { public Transform mapIcon; private Vector2 mapOffsetInUnits; private float mapScaleFactor; public GameObject mapPlane1; public GameObject mapPlane2; public GameObject player; void Start() { Renderer mapRenderer1 = mapPlane1.GetComponent<Renderer>(); Vector3 mapSize1 = mapRenderer1.bounds.size; float mapWidth1 = mapSize1.x; float mapHeight1 = mapSize1.z; Renderer mapRenderer2 = mapPlane2.GetComponent<Renderer>(); Vector3 mapSize2 = mapRenderer2.bounds.size; float mapWidth2 = mapSize2.x; float mapHeight2 = mapSize2.z; mapScaleFactor = Mathf.Min(mapWidth2 / mapWidth1, mapHeight2 / mapHeight1); float offsetX = (mapWidth2 - mapWidth1 * mapScaleFactor) / 2f; float offsetY = (mapHeight2 - mapHeight1 * mapScaleFactor) / 2f; mapOffsetInUnits = new Vector2(offsetX, offsetY); Debug.Log("Map offset in units: " + mapOffsetInUnits); Debug.Log("Map 1 width: " + mapWidth1 + ", height: " + mapHeight1); Debug.Log("Map 2 width: " + mapWidth2 + ", height: " + mapHeight2); player = GameObject.FindGameObjectWithTag("Player"); } void Update() { Vector3 playerPos = player.transform.position; Vector3 mapPlane1Pos = mapPlane1.transform.position; Quaternion mapPlane1Rot = mapPlane1.transform.rotation; Vector3 mapPlane2Pos = mapPlane2.transform.position; Quaternion mapPlane2Rot = mapPlane2.transform.rotation; float x = ((playerPos.x - mapPlane1Pos.x) * Mathf.Cos(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) + (playerPos.z - mapPlane1Pos.z) * Mathf.Sin(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) - mapOffsetInUnits.x) * mapScaleFactor; float y = ((playerPos.z - mapPlane1Pos.z) * Mathf.Cos(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) - (playerPos.x - mapPlane1Pos.x) * Mathf.Sin(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) - mapOffsetInUnits.y) * mapScaleFactor; Vector3 iconPos = new Vector3(y, 0f,-x); iconPos = Quaternion.Euler(0f, -mapPlane2Rot.eulerAngles.y, 0f) * iconPos + mapPlane2Pos; mapIcon.position = iconPos ; } }
问题原因
原始脚本仅在Start()方法中计算一次mapScaleFactor和mapOffsetInUnits,当缩放mapPlane2时,它的实时尺寸会变化,但这两个关键值不会更新,导致后续计算的图标位置出现偏移。此外,直接使用Renderer.bounds.size获取mapPlane1的尺寸会受其自身缩放影响,可能导致基准尺寸计算错误。
修改后的脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Finalmap : MonoBehaviour { public Transform mapIcon; public GameObject mapPlane1; public GameObject mapPlane2; public GameObject player; // 缓存mapPlane1的原始尺寸(不受缩放影响) private Vector3 originalMapSize1; void Start() { if (mapPlane1 != null) { Renderer mapRenderer1 = mapPlane1.GetComponent<Renderer>(); // 计算原始尺寸:当前bounds尺寸除以物体缩放比例 originalMapSize1 = mapRenderer1.bounds.size / mapPlane1.transform.localScale.x; } player = GameObject.FindGameObjectWithTag("Player"); } void Update() { // 空值检查,避免运行时报错 if (player == null || mapPlane1 == null || mapPlane2 == null) return; // 实时计算mapPlane1的当前尺寸(原始尺寸 * 缩放比例) Vector3 mapSize1 = originalMapSize1 * mapPlane1.transform.localScale.x; float mapWidth1 = mapSize1.x; float mapHeight1 = mapSize1.z; // 实时获取mapPlane2的当前尺寸 Renderer mapRenderer2 = mapPlane2.GetComponent<Renderer>(); Vector3 mapSize2 = mapRenderer2.bounds.size; float mapWidth2 = mapSize2.x; float mapHeight2 = mapSize2.z; // 实时更新缩放因子和偏移量 float mapScaleFactor = Mathf.Min(mapWidth2 / mapWidth1, mapHeight2 / mapHeight1); float offsetX = (mapWidth2 - mapWidth1 * mapScaleFactor) / 2f; float offsetY = (mapHeight2 - mapHeight1 * mapScaleFactor) / 2f; Vector2 mapOffsetInUnits = new Vector2(offsetX, offsetY); Vector3 playerPos = player.transform.position; Vector3 mapPlane1Pos = mapPlane1.transform.position; Quaternion mapPlane1Rot = mapPlane1.transform.rotation; Vector3 mapPlane2Pos = mapPlane2.transform.position; Quaternion mapPlane2Rot = mapPlane2.transform.rotation; // 拆分玩家相对位置计算,提升可读性 float playerLocalX = (playerPos.x - mapPlane1Pos.x) * Mathf.Cos(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) + (playerPos.z - mapPlane1Pos.z) * Mathf.Sin(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad); float playerLocalZ = (playerPos.z - mapPlane1Pos.z) * Mathf.Cos(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad) - (playerPos.x - mapPlane1Pos.x) * Mathf.Sin(mapPlane1Rot.eulerAngles.y * Mathf.Deg2Rad); // 转换到mapPlane2坐标系,应用实时缩放和偏移 float x = (playerLocalX - mapOffsetInUnits.x) * mapScaleFactor; float y = (playerLocalZ - mapOffsetInUnits.y) * mapScaleFactor; Vector3 iconPos = new Vector3(y, 0f, -x); iconPos = Quaternion.Euler(0f, -mapPlane2Rot.eulerAngles.y, 0f) * iconPos + mapPlane2Pos; mapIcon.position = iconPos; } }
关键修改点
- 缓存原始尺寸:在
Start()中缓存mapPlane1的原始尺寸,避免其自身缩放影响基准尺寸计算 - 实时更新参数:将缩放因子和偏移量的计算移到
Update()中,确保每次地图缩放时都能获取最新的尺寸值 - 空值安全检查:增加空值判断,防止运行时出现空引用异常
- 代码可读性优化:拆分玩家位置计算逻辑,便于后续维护
内容的提问来源于stack exchange,提问作者Shyama prasad Tripathy
相关产品推荐
相关产品推荐

