【问题标题】:Unity3D - Using Raycasting to detect Game Objects. Top-down viewUnity3D - 使用 Raycasting 检测游戏对象。自上而下的视图
【发布时间】:2020-12-31 11:30:14
【问题描述】:

我正在制作一个自上而下的空间资源收集游戏,带有 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);
    }
}
}

提前致谢

【问题讨论】:

    标签: c# unity3d vector raycasting


    【解决方案1】:

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

    此解决方案允许您单击一个游戏对象(前提是它附加了一个碰撞器),将当前游戏对象移向被单击的对象,以及收集一个可能的游戏对象数组 (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;
    }
    

    【讨论】:

    • 谢谢,这在小行星上使用时有效。但是,如果我想让射线沿着鼠标指针的方向继续,以定位屏幕上不可见的小行星,该怎么办?顺便说一句,我的目的不是让这成为一个动作脚本,而只是一种寻找资源的能力。仍然有效 :) 很抱歉在主帖中措辞不佳。
    • @JeyesElite 没问题,我已经更新了我的原始答案,包括对小行星的定向检查,您可能需要调整 searchDistance 值。运动只是一点点补充,祝你好运!
    【解决方案2】:

    您使用了 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      相关资源
      最近更新 更多