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

3D俯视角游戏中如何让球形子弹朝鼠标光标方向发射?

修复3D俯视角子弹朝向鼠标的问题

你的问题根源在于ScreenToWorldPoint(Input.mousePosition)的使用方式错误:Input.mousePosition只包含屏幕坐标的x/y值,z值为0,而ScreenToWorldPoint需要z值来确定相对于相机的深度,这导致你得到的是相机近平面上的点,而非鼠标在地面的投影位置。

下面是两种可靠的修复方案:

方案一:在Bullet中用射线检测获取地面投影点

修改Bullet脚本的Start方法,通过射线检测计算鼠标在目标平面(y=0.5)的交点:

public class Bullet : MonoBehaviour
{
    [SerializeField] private float speed = 5.0f;
    private Vector3 bulletDirection;

    void Start()
    {
        // 从相机向鼠标位置发射射线
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        // 定义子弹飞行的平面高度
        float targetY = 0.5f;
        Plane groundPlane = new Plane(Vector3.up, targetY);

        // 计算射线与平面的交点
        if (groundPlane.Raycast(ray, out float distance))
        {
            Vector3 targetPoint = ray.GetPoint(distance);
            // 计算方向并忽略y轴分量(保持水平飞行)
            bulletDirection = (targetPoint - transform.position).normalized;
            bulletDirection.y = 0;
        }
        else
        {
            //  fallback:如果射线未命中平面,使用相机到目标平面的距离作为深度
            Vector3 mousePosWithDepth = Input.mousePosition;
            mousePosWithDepth.z = Camera.main.transform.position.y - targetY;
            Vector3 targetPoint = Camera.main.ScreenToWorldPoint(mousePosWithDepth);
            targetPoint.y = targetY;
            bulletDirection = (targetPoint - transform.position).normalized;
            bulletDirection.y = 0;
        }

        Debug.Log("Target: " + ray.GetPoint(distance) + ", Direction: " + bulletDirection);
    }

    void Update()
    {
        transform.Translate(bulletDirection * speed * Time.deltaTime);
    }
}

方案二:在PlayerController中提前计算方向(推荐)

将发射逻辑集中在PlayerController中,提前计算好子弹方向再传递给Bullet,这样Bullet无需处理鼠标输入,职责更清晰:

1. 修改PlayerController的发射代码

public class PlayerController : MonoBehaviour
{
    public Bullet bulletPrefab;
    private float targetY = 0.5f;

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            FireBullet();
        }
    }

    void FireBullet()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        Plane groundPlane = new Plane(Vector3.up, targetY);
        Vector3 targetPoint;

        if (groundPlane.Raycast(ray, out float distance))
        {
            targetPoint = ray.GetPoint(distance);
        }
        else
        {
            Vector3 mousePosWithDepth = Input.mousePosition;
            mousePosWithDepth.z = Camera.main.transform.position.y - targetY;
            targetPoint = Camera.main.ScreenToWorldPoint(mousePosWithDepth);
            targetPoint.y = targetY;
        }

        // 计算水平方向
        Vector3 direction = (targetPoint - transform.position).normalized;
        direction.y = 0;

        // 实例化子弹并传递方向
        Bullet bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);
        bullet.SetDirection(direction);
    }
}

2. 修改Bullet脚本

public class Bullet : MonoBehaviour
{
    [SerializeField] private float speed = 5.0f;
    private Vector3 bulletDirection;

    public void SetDirection(Vector3 direction)
    {
        bulletDirection = direction;
    }

    void Update()
    {
        transform.Translate(bulletDirection * speed * Time.deltaTime);
    }
}

两种方案都能准确获取鼠标在地面的投影位置,确保子弹朝鼠标方向飞行。方案二更符合代码职责分离的原则,便于后续扩展。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 19:42:45