反射 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
我正在尝试为涉及 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