【问题标题】:Is there any way to stop raycasts from going through objects?有什么办法可以阻止光线投射穿过物体?
【发布时间】:2022-01-20 09:06:25
【问题描述】:

我正在制作一把抓枪,如果图层为LightWeight,则将对象拉向玩家,如果图层为Ground,则将玩家拉向对象

            int groundLayer_mask = LayerMask.GetMask("Ground");
            int lightWeightLayer_mask = LayerMask.GetMask("LightWeight");

            //Shoots a raycast, and only works if layer is Ground
            if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, groundLayer_mask))
            {
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 0;

                state = State.HookShotThrown;
            }
            //Shoots a raycast, and only works if layer is LightWeight
            else if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, lightWeightLayer_mask))
            {
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 1;

                state = State.HookShotThrown;
            }

但是,如果我朝具有Ground 层的对象的方向看,即使有一个具有LightWeight 层的对象比具有Ground 的对象更接近,它也适用于具有Ground 的对象,因为我先有它的if语句。有什么方法可以让它不通过前面的对象只是因为第一个如果正在寻找后面的对象,或者让它优先考虑前面的对象?

【问题讨论】:

    标签: c# unity3d if-statement raycasting


    【解决方案1】:

    除了layerHit 的值之外,您的两个 raycast 案例基本上都做同样的事情。所以无论哪种方式都是浪费资源;)

    因此,为了提高效率并实现您想要的效果,只需在图层蒙版中包含两个图层,并对两个图层只进行一次光线投射 -> 它将使用从给定图层中首先命中的任何内容。

    然后您仍然可以检查您在if 块中实际击中的层。

    所以我会公开该字段以在 Inspector 中进行配置

    // Configure this via the Inspector
    // it will be a drop-down from which you can select multiple entries
    public LayerMask layers;
    
    private void Awake ()
    {
        // if you really want to keep getting these by code
        layers = LayerMask.GetMask("Ground", "LightWeight");
    }
    

    而且通常我也会使用enum 来获得一些有意义的名称,例如

    public enum HitType
    {
        None = -1,
        Ground,
        Lightweight
    }
    

    然后像这样使用单个射线投射

    int groundLayer_mask = LayerMask.NameToLayer("Ground");
    int lightWeightLayer_mask = LayerMask.NameToLayer("LightWeight");
    
    var hitType = HitType.None;
    
    if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, layers))
    {
        //Hit Something
        debugHitpointTransform.position = raycastHit.point;
        hookshotPosition = raycastHit.point;
        hookShotSize = 0f;
        HookShotTransform.gameObject.SetActive(true);
        HookShotTransform.localScale = Vector3.zero;
    
        if(raycastHit.collider.gameObject.layer == groundLayer_mask) hitType = HitType.Ground;
        else if(raycastHit.collider.gameObject.layer == lightWeightLayer_mask) hitType = HitType.Lightweight;
    
        state = State.HookShotThrown;
    }
    

    【讨论】:

    • @Brain_Grunt 是的,完全一样。基本上enum 仍然是int 底层(默认情况下.. 您甚至可以将底层类型更改为例如byteuint 等).. 但是这样您就可以为您的值指定一个特定的名称并且不要不必一直记住01 究竟代表什么。由于这些是编译时间常数,尽管您可以再次使用 switch 这会更有效
    • @Brain_Grunt 在哪里,您究竟想如何使用它?目前它只存在于进行光线投射的方法中......除非你为它创建一个类字段而不是使用var
    • @Brain_Grunt 是的,在这种情况下,要么将其作为参数传递给您的方法,要么将其存储在某个类字段中
    • 一般来说,在 Unity 中你想使用 Debug.Log 而不是 Console.WriteLine ;)
    • 在带有 3 个立方体的新场景中使用 void Update(){Vector3 dir;if (Input.GetMouseButtonDown(0)) dir = Vector3.forward;else if (Input.GetMouseButtonDown(1)) dir = Vector3.right;else return;int gm = LayerMask.NameToLayer("Default");int lwm = LayerMask.NameToLayer("Water");int layers = 1 << gm | 1 << lwm;if (Physics.Raycast(transform.position, dir, out RaycastHit raycastHit, float.PositiveInfinity, layers)){if (raycastHit.collider.gameObject.layer == gm) Debug.Log("ground"); else if (raycastHit.collider.gameObject.layer == lwm) Debug.Log("lightweight");}} 为我工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 2020-01-21
    • 2016-03-17
    • 1970-01-01
    • 2022-06-15
    相关资源
    最近更新 更多