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

Unity篮球射击游戏屏幕点转世界点触摸位置转换问题求助

Unity篮球投篮游戏屏幕坐标转世界坐标问题修复方案

问题核心

开发篮球投篮游戏时,通过Input.mousePosition获取触摸滑动数据转换为世界坐标后,仅中心约30度区域能正常投篮,两侧失效。最初的坐标转换逻辑错误,修改后仍存在平面不统一、透视偏差等问题。

问题根源分析

  1. 坐标平面不统一:修改后的代码中,按下时强制将touchDownWorldPos.z设为相机近裁剪面,导致按下点与抬起点不在同一目标平面,滑动方向计算出现偏差。
  2. 透视相机的坐标转换误差:若使用透视相机,直接用ScreenToWorldPoint时,边缘区域的z值设置不当会导致世界坐标偏移,引发投篮方向错误。
  3. 无滑动区域校验:未限制输入仅在“滑动区域”内,边缘无效输入被误处理。

具体修改方案

1. 统一目标平面,移除强制修改z值

确保按下和抬起时的坐标都转换到篮球所在的同一世界平面,不要手动修改转换后的世界点z值。

2. 改用射线检测获取平面交点(推荐透视相机使用)

ScreenPointToRay可以准确计算屏幕点到目标平面的交点,避免透视带来的坐标偏差:

public Camera cameraForShooter;
public float targetWorldZ = 5f; // 篮球初始位置的世界z坐标
private Vector3 touchDownWorldPos;
private Plane targetPlane;

void Start()
{
    // 初始化目标平面:法向量为相机的反前方向(确保平面朝向相机)
    targetPlane = new Plane(-cameraForShooter.transform.forward, new Vector3(0, 0, targetWorldZ));
}

void Update()
{
    // 触摸按下
    if (Input.GetMouseButtonDown(0))
    {
        Ray ray = cameraForShooter.ScreenPointToRay(Input.mousePosition);
        if (targetPlane.Raycast(ray, out float distance))
        {
            touchDownWorldPos = ray.GetPoint(distance);
            Debug.Log($"touch down world pos: {touchDownWorldPos}");
        }
    }

    // 触摸抬起
    if (Input.GetMouseButtonUp(0))
    {
        Ray ray = cameraForShooter.ScreenPointToRay(Input.mousePosition);
        if (targetPlane.Raycast(ray, out float distance))
        {
            Vector3 worldPoint = ray.GetPoint(distance);
            // 计算投篮方向与力度
            Vector3 shootDirection = worldPoint - touchDownWorldPos;
            // 执行投篮逻辑(示例:给篮球施加力)
            // basketballRigidbody.AddForce(shootDirection * forceMultiplier, ForceMode.Impulse);
            Debug.Log($"shoot direction: {shootDirection}");
        }
    }
}

3. 添加滑动区域校验

如果“滑动区域”是UI元素,通过RectTransformUtility判断输入是否在区域内:

public RectTransform slideArea;

// 判断输入是否在滑动区域内
bool IsInSlideArea(Vector2 screenPos)
{
    Rect rect = slideArea.rect;
    Vector2 localPos;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(slideArea, screenPos, cameraForShooter, out localPos);
    return rect.Contains(localPos);
}

// 修改触摸按下逻辑
if (Input.GetMouseButtonDown(0) && IsInSlideArea(Input.mousePosition))
{
    // 原有转换逻辑
}

4. 正交相机适配

如果使用正交相机,可直接用ScreenToWorldPoint,但需确保z值为相机到目标平面的世界空间距离:

// 按下时
Vector3 touchPos = Input.mousePosition;
// z值为相机到目标平面的距离(世界空间)
touchPos.z = Mathf.Abs(cameraForShooter.transform.position.z - targetWorldZ);
touchDownWorldPos = cameraForShooter.ScreenToWorldPoint(touchPos);

// 抬起时同理
Vector3 screenPoint = Input.mousePosition;
screenPoint.z = Mathf.Abs(cameraForShooter.transform.position.z - targetWorldZ);
Vector3 worldPoint = cameraForShooter.ScreenToWorldPoint(screenPoint);

额外排查点

  • 确认targetWorldZ是篮球所在平面的真实世界z坐标,而非相机的nearClipPlane。
  • 检查相机的fieldOfView(透视相机)或orthographicSize(正交相机),确保视野覆盖整个滑动区域。
  • 调试时绘制Gizmos,可视化按下/抬起的世界点,确认坐标是否正确:
void OnDrawGizmos()
{
    Gizmos.color = Color.red;
    Gizmos.DrawSphere(touchDownWorldPos, 0.1f);
}

内容的提问来源于stack exchange,提问作者Siddharth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:31:39