Unity 3D足球游戏路径绘制问题:无法识别深度轴
解决3D足球游戏路径绘制无法识别深度轴的问题
问题根源
你当前的实现直接使用Raycast命中Box Collider的hit.point,但如果Collider是薄平面(比如仅覆盖地面Y轴高度),命中点的Z轴(深度)值会被固定在Collider的Z位置,无法反映玩家想要的3D深度方向输入,导致路径只能在X/Y平面延伸。
修复方案
以下两种方案都能让路径支持3D空间的X/Y/Z三轴,根据你的游戏需求选择:
方案1:基于目标深度平面的坐标映射
直接将屏幕输入映射到3D空间中指定深度的平面,替代Raycast的命中点,适合固定深度范围的场景(比如预设球门区域的深度):
private List<Vector3> points = new List<Vector3>(); public Transform ball; public LineRenderer lineRenderer; // 可根据场景调整的目标深度(比如球门所在的Z坐标) public float targetDepth = 10f; // 绘制区域的X/Y范围限制 public float minX = -5f; public float maxX = 5f; public float minY = 0f; public float maxY = 3f; private void Update() { if (Input.GetMouseButton(0)) { Camera mainCam = Camera.main; // 将屏幕点转换为目标深度平面上的世界坐标 Vector3 screenPos = Input.mousePosition; screenPos.z = mainCam.WorldToScreenPoint(new Vector3(0, 0, targetDepth)).z; Vector3 worldPoint = mainCam.ScreenToWorldPoint(screenPos); // 限制在设定的绘制区域内 if (worldPoint.x >= minX && worldPoint.x <= maxX && worldPoint.y >= minY && worldPoint.y <= maxY) { if (points.Count == 0 || Vector3.Distance(points[points.Count - 1], worldPoint) > 0.1f) { points.Add(worldPoint); lineRenderer.positionCount = points.Count; lineRenderer.SetPositions(points.ToArray()); } } } if (Input.GetMouseButtonUp(0)) { if (points.Count == 0) return; ball.position = points[0]; StartCoroutine(MoveBallAlongPath()); points.Clear(); lineRenderer.positionCount = 0; } } private IEnumerator MoveBallAlongPath() { int resolution = 100; // 改用基于时间的移动,避免帧率影响速度 float moveSpeed = 8f; for (int i = 0; i < points.Count - 1; i++) { Vector3 pointA = points[i]; Vector3 pointB = points[i + 1]; Vector3 controlPoint = (pointA + pointB) / 2; for (int j = 0; j < resolution; j++) { float t = j / (float)resolution; Vector3 targetPoint = CalculateBezierPoint(t, pointA, controlPoint, pointB); float distance = Vector3.Distance(ball.position, targetPoint); float moveTime = distance / moveSpeed; float startTime = Time.time; while (Time.time - startTime < moveTime) { float progress = (Time.time - startTime) / moveTime; ball.position = Vector3.Lerp(ball.position, targetPoint, progress); yield return null; } } } } private Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) { float u = 1 - t; float tt = t * t; float uu = u * u; Vector3 p = uu * p0; p += 2 * u * t * p1; p += tt * p2; return p; }
方案2:支持动态调整深度的Raycast方案
保留Box Collider作为绘制区域,但让玩家可以通过鼠标滚轮/触摸滑动调整深度,适合需要自由控制3D路径的场景:
private List<Vector3> points = new List<Vector3>(); public Transform ball; public LineRenderer lineRenderer; public Collider drawArea; // 初始深度及范围限制 private float currentDepth = 5f; private float minDepth = 2f; private float maxDepth = 15f; private void Update() { // 鼠标滚轮调整深度 if (Input.mouseScrollDelta.y != 0) { currentDepth += Input.mouseScrollDelta.y * 0.5f; currentDepth = Mathf.Clamp(currentDepth, minDepth, maxDepth); } if (Input.GetMouseButton(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // 获取射线在当前深度的点 Vector3 targetPoint = ray.GetPoint(currentDepth); // 检查是否在绘制区域内 if (drawArea.bounds.Contains(targetPoint)) { if (points.Count == 0 || Vector3.Distance(points[points.Count - 1], targetPoint) > 0.1f) { points.Add(targetPoint); lineRenderer.positionCount = points.Count; lineRenderer.SetPositions(points.ToArray()); } } } if (Input.GetMouseButtonUp(0)) { if (points.Count == 0) return; ball.position = points[0]; StartCoroutine(MoveBallAlongPath()); points.Clear(); lineRenderer.positionCount = 0; } } // MoveBallAlongPath和CalculateBezierPoint方法同方案1
额外优化点
- 路径平滑度:当前二阶贝塞尔曲线可以改为三阶(添加两个控制点),让转弯更自然。
- 触摸适配:针对移动端,可添加双指滑动调整深度的逻辑,替代鼠标滚轮。
- 路径预览:绘制时可以实时预览球的移动轨迹,提升玩家体验。
内容的提问来源于stack exchange,提问作者AND4011002849
相关产品推荐
相关产品推荐

