一旦CircleCast在Unity中碰到某些东西就停止它?

Posted

技术标签:

【中文标题】一旦CircleCast在Unity中碰到某些东西就停止它?【英文标题】:Make CircleCast stop once it hits something in Unity? 【发布时间】:2020-11-14 22:16:51 【问题描述】:

我正在开发一款可以让 2D 弹丸从墙壁上弹开的游戏。我目前让物体本身弹跳得很好,但是我想要一个Angry Birds Style HUD(减去重力)来显示物体将要撞到墙上的位置,并显示它将以什么角度弹跳:(请原谅我的绘画技巧)

我有这个系统在技术方面工作正常,除了这个事实,因为光线投射是无穷无尽的,所以实际结果看起来像这样:

所以要明确一点,最后,我希望第一次 raycast 无限发出,直到它击中某物,然后当它生成第一个击中某物的第二次 raycast 时,让第二次 raycast 只发出一个预先指定的距离(可能是 3f 或类似的距离),或者直到它撞到某物,在这种情况下它应该停止。

我的脚本:

Transform firePoint;

void Update

     DrawPredictionDisplay();


private void DrawPredictionDisplay()
    
        Vector2 origin = firePoint.transform.position; //unity has a built in type converter that converts vector3 to vector2 by dropping the z component
        direction = firePoint.transform.up;
        float radius = 0.4f;
        RaycastHit2D hit = Physics2D.CircleCast(origin, radius, direction);

        // Draw black line from firepoint to hit point 1
        Debug.DrawLine(origin, direction * 10000, UnityEngine.Color.black);

        if (hit)
                  
            origin = hit.point + (hit.normal * radius);
            Vector2 secondDirection = Vector2.Reflect(direction, hit.normal);            

            // Create second raycast
            RaycastHit2D hit2 = Physics2D.CircleCast(origin, radius, secondDirection);

            if (hit2)
            
                if(hit.collider.gameObject.tag != "Destroy")
                
                    // Enable prediction points
                    for (int i = 0; i < numOfPoints; i++)
                    
                        predictionPoints2[i].SetActive(true);
                    

                    // Calculate reflect direction
                    Vector2 origin2 = hit2.point + (hit2.normal * radius);
                    // Draw blue line from hit point 1 to predicted reflect direction
                    Debug.DrawLine(origin, secondDirection * 10000, UnityEngine.Color.blue);
                      
            
            
        
    

    Vector2 predictionPointPosition(float time)
    
        Vector2 position = (Vector2)firePoint.position + direction.normalized * 10f * time;
        return position;
    

    Vector2 predictionPointPosition2(float time, Vector2 origin, Vector2 direction)
    
        Vector2 position = origin + direction.normalized * 10f * time;
        return position;
    

注意事项:

虽然我会使用常规光线投射,但我发现普通光线投射不会削减它,因为光线投射只有 1 像素宽,而对象是(大约)512 像素乘 512 像素,这意味着对象会在光线投射之前物理接触墙壁确实,导致不准确。

我已经创建了一个系统,可以沿光线投射路径生成点,类似于愤怒的小鸟,以便玩家可以在游戏视图中看到光线投射在做什么,但因为它与我删除的问题无关我上面的脚本中的那部分代码。这意味着我需要做的就是限制光线投射的距离,而不是找到让玩家看到正在发生的事情的方法。 (我在注释中添加了这一点,以避免引发关于玩家是否可以看到正在发生的事情的对话。)

firepoint 是发射弹丸的武器的枪管/尖端。 (武器根据/跟随鼠标旋转)

【问题讨论】:

Debug.DrawLine 将 2 个点作为参数,而不是点和方向,您的意思是使用 Debug.DrawRay 吗?你可以等到知道你是否撞到东西并且你有碰撞点/信息来绘制它之后再绘制路径。 @Pluto 我以前从未使用过 Debug.DrawRay,你能告诉我在这种情况下它会是什么样子吗? Debug.DrawLine(origin, origin + direction * 10000, UnityEngine.Color.black); 等价于Debug.DrawRay(origin, direction * 10000, UnityEngine.Color.black); @Pluto 好的,但是如何让它在撞到物体后停止? 【参考方案1】:

你可以在之后画出你知道它是否撞到一个物体的线/路径:

Vector2 origin = firePoint.transform.position; //unity has a built in type converter that converts vector3 to vector2 by dropping the z component
direction = firePoint.transform.up;
float radius = 0.4f;
RaycastHit2D hit = Physics2D.CircleCast(origin, radius, direction);

var firstPathStart = origin;
var firstPathEnd = origin + direction * 10000;    

if (hit)
          
    origin = hit.point + (hit.normal * radius);
    firstPathEnd = origin;
    
    Vector2 secondDirection = Vector2.Reflect(direction, hit.normal); 
    var secondPathStart = firstPathEnd;
    var secondPathEnd = origin + secondDirection * 3f;           

    // Create second raycast
    RaycastHit2D hit2 = Physics2D.CircleCast(origin, radius, secondDirection);

    if (hit2)
    
        if(hit.collider.gameObject.tag != "Destroy")
        
            // Enable prediction points
            for (int i = 0; i < numOfPoints; i++)
            
                predictionPoints2[i].SetActive(true);
            

            // Calculate reflect direction
            Vector2 origin2 = hit2.point + (hit2.normal * radius);
            secondPathEnd = origin2;
              
    
    // Draw blue line from hit point 1 to predicted reflect direction
    Debug.DrawLine(secondPathStart, secondPathEnd, UnityEngine.Color.blue);                  
 

// Draw black line from firepoint to hit point 1
Debug.DrawLine(firstPathStart, firstPathEnd, UnityEngine.Color.black);  

您可以创建一个类来存储路径信息(路径有多少段,每个段的开始和结束位置),在检查碰撞时填充并在最后绘制。

【讨论】:

我花了几分钟来实现,但我现在有 2 个光线投射发射,一旦它们撞到墙就会停止(像这样:imgur.com/a/1E7EhVZ)。在我将您的答案标记为正确之前,我唯一要问的另一件事是:我们能否在第二次光线投射在一定(预定)距离后撞到墙壁时停止? (像这样:imgur.com/a/1CqjbYQ) 嗯...当我做if(hit2) var secondPathEnd = origin + secondDirection * 3f; Debug.DrawLine(firstPathEnd, secondPathEnd, UnityEngine.Color.blue); 我得到这个:imgur.com/a/l3H1T6s(暂时忽略点)它限制了距离,但如果它撞到墙上就会忽略。 您的说法是有道理的,但是在实践中,如果我在 if(hit) 中声明 secondPathEnd 作为您的建议,则没有任何变化(如预期的那样)。但是,当我将secondPathEnd = hit2.point + (hit2.normal * radius); 添加到if(hit2) 时,它会无限熄灭并忽略原来的 3f 距离限制,就好像它一直在撞到什么东西,而实际上它不是。 @JhonPiper 哦,我想我明白你的意思了。你需要检查if ( Vector3.Distance(secondPathStart, origin2) &lt; predeterminedDistance) secondPathEnd = origin2; 。您还可以将距离参数添加到 Physics2D.CircleCast ,将其保留为默认值,即 Mathf.Infinity。 通过在 2nd Circlecast 上设置距离,如果墙在 raycast 原点的 3f 范围内,它现在会显示并完美工作,但如果墙不在 3f 范围内,它会完全消失。并且将if ( Vector3.Distance(secondPathStart, origin2) &lt; predeterminedDistance) secondPathEnd = origin2; 放入if(hit2) 似乎没有任何效果。

以上是关于一旦CircleCast在Unity中碰到某些东西就停止它?的主要内容,如果未能解决你的问题,请参考以下文章

Unity3d台球/台球瞄准问题

unity+vuforia打包Android,AR扫描界面是黑白的,而在某些角度又会变成彩色,或是闪烁不定,是啥原因?

当Lantent函数碰到BehaviorTree的Abort

[Unity+Android]横版扫描二维码

unity碰到物体血条减少

Unity 记录 Unity Shader 碰到的一个奇怪bug记录。