Unity3D-使用光线投射检测游戏对象俯视图

问题描述

我正在使用3D模型制作自上而下的空间资源收集游戏。

我正尝试向鼠标位置投射光线,以检测与游戏中物体的碰撞, 让我的小太空船知道去寻找资源的方向。 资源是玩家必须打破才能收集的小行星形式。

代码中,我使用“中心”向量来找到屏幕/播放器位置的中间位置,因为摄像机会跟随播放器。所有运动均沿X,Y轴发生。将center.Z设置为15只是为了抵消世界空间中主摄像机的-15Z位置。 到目前为止,该代码在可以检测到命中的程度“起作用”,但是射线没有沿鼠标方向传播。我必须暂缓它才能使其击中,并且很难复制到几乎随机的程度。光线可能无法理解鼠标的位置吗?

以防我措辞不佳,这种搜寻能力并不意味着要破坏小行星,只需找到它即可。破坏能力是一个单独的脚本。

代码

public class AbilitySearch : MonoBehavIoUr
{
Vector3 center;
Vector3 mousePos;
Vector3 direction;
private float range = 100f;

void Update()
{
    center = Camera.main.ViewportToWorldPoint(new Vector3(0.5f,0.5f,15.0f));
    mousePos = Input.mousePosition;
    direction = mousePos - transform.position;

    if (Input.GetMouseButton(1))
    {
        Search();
    }
}

void Search()
{
    RaycastHit hit;
    if (Physics.Raycast(center,direction,out hit,range))
    {
        Debug.Log("You hit " + hit.transform.name);
    }
}
}

预先感谢

解决方法

使用Input.mousePosition时,该位置是屏幕上的像素坐标,因此,如果鼠标位于屏幕的左下角,它将为0,0。这导致direction不正确。当您需要使用游戏空间坐标时,以Camera.ScreenToWorldPoint(Input.mousePosition)为例。

此解决方案允许您单击gameObject(前提是它已附加了对撞器),将当前gameObject移向所单击的对象,并沿方向收集可能的gameObject(RaycastHit [s])数组。点击一个。

Vector3 destination;
RaycastHit[] possibleTargets;
bool isTravelling;
float searchDistance = 5f;

private void Update()
{
    //If right mouse button has been pressed down
    if (Input.GetMouseButtonDown(1))
    {
        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray,out hit)) //If ray collides with something
        {
            Search(hit);
        }
    }
    //If going to destination
    if (isTravelling)
    {
        float step = 2f * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position,destination,step);
        //If approx arrived
        if (Vector3.Distance(transform.position,destination) < 0.1f)
        {
            isTravelling = false; //Stop moving to destination
            Debug.Log("You've arrived");
        }
    }
}

private void Search(RaycastHit _hit)
{
    //Normalise directional vectors,so (if needed) they can be multipled as expected
    Vector3 direction = (_hit.point - transform.position).Normalized();
    RaycastHit secondHit;
    //Grab objects in direction of clicked object (including the one clicked)
    possibleTargets = Physics.RaycastAll(transform.position,direction,searchDistance);
    Debug.Log($"There are {possibleTargets.Length} possible targets ahead");
    Debug.Log($"You hit {_hit.transform.name}");
    //Set destination,and set to move
    destination = _hit.point;
    isTravelling = true;
}
,

您使用了ViewportToWorldPoint方法,该方法期望归一化的视口坐标在0到1的范围内,但是您提供了在我看来是相机世界坐标的参数。

您只需要将光线从相机投射到鼠标指针的世界位置(请参阅方法FindAsteroid中的第一行代码)即可检查与小行星的碰撞。返回的RaycastHit为您提供有关碰撞的信息-击中位置,游戏对象,对撞机-您可以将其用于其他游戏逻辑,例如从宇宙飞船向小行星命中点发射子弹。

我编辑了您的课程,并在下面的简单场景中添加了屏幕截图,其中显示了两种不同的“光线”:

  1. 黄射线从照相机到小行星命中点
  2. 洋红色射线从飞船的位置到小行星的命中点。

我还建议过滤射线广播以仅影响特定的对撞机- 参见LayerMask选择性投射光线部分)

public class AbilitySearch : MonoBehaviour
{
    private float  range = 100f;
    private Camera mainCam;

    private void Awake()
    {
        // TIP: Save reference to main camera - avoid internal FindGameObjectWithTag call
        mainCam = Camera.main;
    }

    private void Update()
    {
        if (Input.GetMouseButton(1))
        {
            if (FindAsteroid(out var asteroidHit))
            {
                // Draw a line from spaceship to asteroid hit position
                Debug.DrawLine(transform.position,asteroidHit.point,Color.magenta,Time.deltaTime);

                Debug.Log($"You hit {asteroidHit.transform.name}");
            }
        }
    }

    private bool FindAsteroid(out RaycastHit hit)
    {
        // Create a ray going from camera position to mouse position in world space
        var ray = mainCam.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray,out hit,range))
        {
            // Draw a line from camera to world mouse position
            Debug.DrawLine(ray.origin,hit.point,Color.yellow,Time.deltaTime);

            // An asteroid was found
            return true;
        }

        // An asteroid was NOT found
        return false;
    }
}

Sample spaceship scene