如何判断小对象顶点是否在大对象平面区域内?(约束移动边界)
简洁实现任意角度平面上的拖拽边界限制(适配偏移场景)
核心思路
不用复杂的平面投影、多点检测,而是通过局部坐标系转换把非轴对齐的空间问题简化为轴对齐的边界判断——这是Unity中处理空间适配最常用的技巧之一,完全适配任意角度的墙面平面,同时自动处理绘画与墙面的偏移问题。
具体实现步骤
1. 预处理墙面与绘画的空间参数
在初始化阶段,提取墙面和绘画的Box Collider信息,转换到墙面的局部空间:
- 墙面的forward方向面在自身局部空间中是一个轴对齐的矩形,直接用Box Collider的
extents就能得到这个矩形的X/Y范围(假设墙面的forward对应局部Z轴,该面的Z坐标固定)。 - 绘画的半尺寸也转换到墙面局部空间,用于后续计算包围盒。
2. 拖拽位置的空间转换与偏移处理
当拖拽得到世界空间的目标位置后:
- 用墙面的
InverseTransformPoint()把目标位置转到墙面局部空间,此时绘画与墙面的偏移会自动被纳入局部坐标中,不需要额外的投影计算。 - 固定局部空间的Z值,维持绘画相对于墙面的原始偏移距离,确保始终在正确的平面附近。
3. 轴对齐边界判断与位置修正
在墙面局部空间中,直接进行矩形边界的碰撞判断:
- 计算绘画在局部空间中的包围盒最小/最大X、Y值。
- 对比墙面矩形的X/Y范围,修正绘画的局部位置,确保包围盒完全落在墙面范围内。
- 最后用
TransformPoint()把修正后的局部位置转回世界空间,设置给绘画对象。
代码示例(Unity C#)
using UnityEngine; public class DragPainting : MonoBehaviour { [Header("拖拽目标")] public Transform wall; public Transform painting; private BoxCollider _wallCollider; private BoxCollider _paintingCollider; private Vector2 _wallLocalRectMin; private Vector2 _wallLocalRectMax; private Vector2 _paintingLocalHalfSize; private float _paintingLocalZOffset; void Start() { _wallCollider = wall.GetComponent<BoxCollider>(); _paintingCollider = painting.GetComponent<BoxCollider>(); // 获取墙面forward方向面的局部矩形范围 Vector3 wallExtents = _wallCollider.bounds.extents; _wallLocalRectMin = new Vector2(-wallExtents.x, -wallExtents.y); _wallLocalRectMax = new Vector2(wallExtents.x, wallExtents.y); // 转换绘画的半尺寸到墙面局部空间 Vector3 paintingExtents = _paintingCollider.bounds.extents; Vector3 localExtents = wall.InverseTransformVector(paintingExtents); _paintingLocalHalfSize = new Vector2(Mathf.Abs(localExtents.x), Mathf.Abs(localExtents.y)); // 记录绘画相对于墙面的局部Z偏移(维持固定距离) _paintingLocalZOffset = wall.InverseTransformPoint(painting.position).z; } void Update() { if (Input.GetMouseButton(0)) { Ray dragRay = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(dragRay, out RaycastHit hit) && hit.transform == wall) { // 转换目标位置到墙面局部空间 Vector3 targetLocalPos = wall.InverseTransformPoint(hit.point); // 维持绘画的固定偏移 targetLocalPos.z = _paintingLocalZOffset; // 计算绘画的局部包围盒范围 float paintMinX = targetLocalPos.x - _paintingLocalHalfSize.x; float paintMaxX = targetLocalPos.x + _paintingLocalHalfSize.x; float paintMinY = targetLocalPos.y - _paintingLocalHalfSize.y; float paintMaxY = targetLocalPos.y + _paintingLocalHalfSize.y; // 修正X方向边界 if (paintMinX < _wallLocalRectMin.x) targetLocalPos.x = _wallLocalRectMin.x + _paintingLocalHalfSize.x; else if (paintMaxX > _wallLocalRectMax.x) targetLocalPos.x = _wallLocalRectMax.x - _paintingLocalHalfSize.x; // 修正Y方向边界 if (paintMinY < _wallLocalRectMin.y) targetLocalPos.y = _wallLocalRectMin.y + _paintingLocalHalfSize.y; else if (paintMaxY > _wallLocalRectMax.y) targetLocalPos.y = _wallLocalRectMax.y - _paintingLocalHalfSize.y; // 应用修正后的位置 painting.position = wall.TransformPoint(targetLocalPos); } } } }
方案优势
- 完全适配任意旋转角度的墙面平面,不需要处理复杂的平面方程或投影计算。
- 自动处理绘画与墙面的偏移问题,局部坐标系转换直接包含了位置偏移信息。
- 代码简洁,计算量小,仅依赖Unity内置的空间转换方法,稳定性高。
内容的提问来源于stack exchange,提问作者pretender
相关产品推荐
相关产品推荐

