反射 Raycast2D 时发生 StackOverflowException

StackOverflowException when reflecting a Raycast2D

我正在尝试为涉及 Unity 中的光束和镜子的游戏制作一个简单的拼图系统。光束是使用投射 Raycast2D 并使用 LineRenderer 显示光束的空游戏对象创建的。当光束与镜面物体碰撞时,我只需使用 Vector2.Reflect 来计算新方向。

当镜像是静态的时,实现工作正常。当我尝试在游戏中移动它们时,它会导致随机堆栈溢出错误,而且似乎没有规律可循。这是工作镜像设置的示例:

以下是我尝试移动镜子时发生的情况:

我猜这是由于镜子以某种方式将光束反射回来并导致无限反射循环,但我不确定为什么会发生这种情况。

相关代码:

public class LightBeam
{
    Vector2 position;
    Vector2 direction;

    GameObject lightBeam;
    LineRenderer lightRender;

    List<Vector2> lightPoints = new List<Vector2>();

    // A new LightBeam object is created every update
    public LightBeam(Vector2 startPos, Vector2 dir, Material material)
    {
        this.lightRender = new LineRenderer();
        this.lightBeam = new GameObject();
        this.lightBeam.name = "LightBeam";

        this.position = startPos;
        this.direction = dir;

        this.lightRender = this.lightBeam.AddComponent(typeof(LineRenderer)) as LineRenderer;
        this.lightRender.startWidth = 0.1f;
        this.lightRender.endWidth = 0.1f;
        this.lightRender.material = material;
        this.lightRender.startColor = Color.white;
        this.lightRender.endColor = Color.white;

        this.lightRender.sortingLayerName = "Foreground";

        CastRay(startPos, dir, lightRender);
    }

    void CastRay(Vector2 pos, Vector2 dir, LineRenderer beam)
    {

        lightPoints.Add(pos);

        // Source of the error
        RaycastHit2D hit = Physics2D.Raycast(pos, dir, 10, LayerMask.GetMask("Solid"));

        if(hit)
        {
            CheckHit(hit, dir, lightRender);
        }
        else
        {
            lightPoints.Add(lightPoints[lightPoints.Count-1] + dir * 10);
        }

        UpdateBeam();
    }

    void UpdateBeam()
    {
        lightRender.positionCount = lightPoints.Count;

        for(int i = 0; i < lightPoints.Count; i++)
        {
            lightRender.SetPosition(i, lightPoints[i]);
        }
    }

    void CheckHit(RaycastHit2D hit, Vector2 dir, LineRenderer beam)
    {
        if(hit.collider.gameObject.tag == "Mirror")
        {
            Vector2 pos = hit.point;
            Vector2 newDir = Vector2.Reflect(dir, hit.normal);

            CastRay(pos, newDir, beam);
        }
        else
        {
            lightPoints.Add(hit.point);
            UpdateBeam();
        }
    }
}

错误信息:

WhosebugException: The requested operation caused a stack overflow.
UnityEngine.ContactFilter2D.CreateLegacyFilter (System.Int32 layerMask, System.Single minDepth, System.Single maxDepth) (at C:/buildslave/unity/build/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs:2297)
UnityEngine.Physics2D.Raycast (UnityEngine.Vector2 origin, UnityEngine.Vector2 direction, System.Single distance, System.Int32 layerMask) (at C:/buildslave/unity/build/Modules/Physics2D/ScriptBindings/Physics2D.bindings.cs:843)
LightBeam.CastRay (UnityEngine.Vector2 pos, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:50)
LightBeam.CheckHit (UnityEngine.RaycastHit2D hit, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:82)
LightBeam.CastRay (UnityEngine.Vector2 pos, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:55)
LightBeam.CheckHit (UnityEngine.RaycastHit2D hit, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:82)
LightBeam.CastRay (UnityEngine.Vector2 pos, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:55)
LightBeam.CheckHit (UnityEngine.RaycastHit2D hit, UnityEngine.Vector2 dir, UnityEngine.LineRenderer beam) (at Assets/Scripts/LightBeam.cs:82)

更新: 结果光束 无限反射。我添加了一个 maxReflections 值来限制循环次数,但它除了抑制 Whosebug 错误外并没有太大作用,并且移动镜子时光束仍然闪烁。

此外,在 CastRay 方法中尝试 Debug.Log(pos) 会使 Unity 完全崩溃。

void CastRay(Vector2 pos, Vector2 dir, LineRenderer beam, int maxReflections)
    {
        
        if(maxReflections <= 0)
        {
            Debug.Log("Too many reflections");
            return;
        }

如果不满足条件 if(hit.collider.gameObject.tag == "Mirror"),您将执行 lightPoints.Add(hit.point); 并更新梁,同时将点添加到 LineRenderer 组件位置数组。这似乎不是一个好主意,因为大概你会到达射线不再击中的地步。事实上,一旦你到达那个点,你就会继续添加点,导致堆栈溢出。

我会添加一些安全条件,如果您没有击中感兴趣的游戏对象,您将停止向 lists/arrays 添加点,可能是确定的射线长度,或者避免添加点的条件,如果射线没有命中。

我检查了您在脚本 itself 中遇到的错误行,其中的信息不是很重要。但是你在那里得到了脚本以防万一。

事实证明,光束在其原点位于内部其中一面镜子时消失了。我通过在与镜子碰撞时稍微移动新 Raycast 的原点来解决它。

我在这里找到了解决方案: https://answers.unity.com/questions/1176130/need-help-ironing-out-this-weird-error-in-raycast2.html