Unity中如何阻止Cell indicator超出地板平面边界?
解决Cell Indicator超出地板边界的问题
问题分析
当前代码存在两个核心问题导致Cell Indicator超出地板:
- 鼠标移出地板后,
InputManager的GetSelectesdMapPosition仍返回最后一次命中地板的位置,Cell Indicator会继续基于该位置计算网格坐标 - 即使鼠标未命中地板,Cell Indicator始终保持显示,且
Grid.WorldToCell会返回地板外的无效网格坐标
解决方案
1. 修改InputManager,增加命中状态判断
新增是否命中地板的标记,方便后续控制Cell Indicator的显示状态:
using UnityEngine; public class InputManager : MonoBehaviour { [SerializeField] private Camera sceneCamera; private Vector3 lastPosition; [SerializeField] private LayerMask placementLayerMask; private bool isHitFloor; public Vector3 GetSelectedMapPosition() { Vector3 mousePos = Input.mousePosition; mousePos.z = sceneCamera.nearClipPlane; Ray ray = sceneCamera.ScreenPointToRay(mousePos); if (Physics.Raycast(ray, out RaycastHit hit, 100, placementLayerMask)) { lastPosition = hit.point; isHitFloor = true; } else { isHitFloor = false; } return lastPosition; } public bool IsHitFloor() { return isHitFloor; } }
2. 修改PlacementSystem,限制网格范围并控制显示
获取地板的碰撞边界,将网格坐标限制在有效范围内,同时在鼠标未命中地板时隐藏Cell Indicator:
using UnityEngine; public class PlacementSystem : MonoBehaviour { [SerializeField] private GameObject mouseIndicator, cellIndicator; [SerializeField] private InputManager inputManager; [SerializeField] private GridLayout grid; [SerializeField] private Collider floorCollider; // 拖入地板的BoxCollider private Vector3Int minGridPos; private Vector3Int maxGridPos; private void Start() { // 初始化地板对应的网格边界 Bounds floorBounds = floorCollider.bounds; minGridPos = grid.WorldToCell(floorBounds.min); maxGridPos = grid.WorldToCell(floorBounds.max); maxGridPos -= Vector3Int.one; // 修正单元格中心偏移导致的超出问题 } private void Update() { Vector3 mousePosition = inputManager.GetSelectedMapPosition(); mouseIndicator.transform.position = mousePosition; if (inputManager.IsHitFloor()) { cellIndicator.SetActive(true); Vector3Int gridPosition = grid.WorldToCell(mousePosition); // 将网格坐标限制在地板范围内 gridPosition.x = Mathf.Clamp(gridPosition.x, minGridPos.x, maxGridPos.x); gridPosition.y = Mathf.Clamp(gridPosition.y, minGridPos.y, maxGridPos.y); gridPosition.z = Mathf.Clamp(gridPosition.z, minGridPos.z, maxGridPos.z); cellIndicator.transform.position = grid.CellToWorld(gridPosition); cellIndicator.transform.position += new Vector3(0f, 0.1f, 0f); } else { cellIndicator.SetActive(false); } } }
注意事项
- 确保地板对象添加了
BoxCollider组件,并将其拖入PlacementSystem的floorCollider字段 - 如果地板是不规则形状,无法用BoxCollider获取边界,可以直接手动给
minGridPos和maxGridPos赋值固定的网格坐标(例如minGridPos = new Vector3Int(0,0,0); maxGridPos = new Vector3Int(10,0,10);) - 修正了原脚本中的拼写错误:
GetSelectesdMapPosition改为GetSelectedMapPosition,请确保函数定义和调用保持一致
内容的提问来源于stack exchange,提问作者user25298028
相关产品推荐
相关产品推荐

