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

Unity中如何阻止Cell indicator超出地板平面边界?

解决Cell Indicator超出地板边界的问题

问题分析

当前代码存在两个核心问题导致Cell Indicator超出地板:

  1. 鼠标移出地板后,InputManager的GetSelectesdMapPosition仍返回最后一次命中地板的位置,Cell Indicator会继续基于该位置计算网格坐标
  2. 即使鼠标未命中地板,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:34:55