Ray vs Rect碰撞检测不正常。

huangapple go评论100阅读模式
英文:

Ray vs Rect collision detection not working properly

问题

我一直在按照这个教程制作一个用于MonoGame游戏的碰撞检测算法。但出于某种原因它并未正常工作。算法的第一部分是一个检测射线与矩形相交的函数。作为测试,我设置了一个从坐标(1,1)发出的射线,方向跟随鼠标,看起来工作正常。

第一个测试,正常工作

但是一旦我将射线放置在接近中心的位置,比如(100, 1),它根本就不起作用。它返回的接触点确实位于矩形上,但与射线的轨迹完全不同。如果我将射线沿着矩形放置,它也无法检测到碰撞。

第二个测试,接触点在矩形内但不在轨迹上

以下是碰撞检测的代码:

public static bool RayVsRect(Vector2 rayOrigin, Vector2 rayDirection, Rectangle rect,
            out Vector2 contactPoint, out Vector2 contactNormal, out float tHitNear)
{
    // 代码部分
}

C#和C++之间可能存在一些差异,该教程是用C++制作的,这可能导致我的代码无法正常工作。例如,除以0似乎会给他返回无穷大,但给我返回NaN,这就是我为什么添加了一个部分,如果rayDirection为0,它会将其更改为Epsilon。但我没有看到其他可能会引起问题的地方。

如果我忽略这个问题并跟随教程进行,碰撞检测有时可以正常工作,从某些方向来说,但在其他方向上完全出现错误。

尽管在两个测试中,一个是在(1, 1),一个是在(100, 1),射线都是朝着矩形的正X和正Y方向移动,但一个有效而另一个则没有。

英文:

I've been following this tutorial to make a collision detection algorithm for a game in MonoGame. But for some reason it's not working properly. The first part of the algorithm is a funcion that detects a Ray vs Rect intersection. As a test I set up a Ray from the coordinates (1,1), with the direction following the mouse, and it seems to work fine.

First test, works fine

But as soon as I put the Ray closer to the center, like in (100, 1), it doesn't work at all. The contact point it returns is along the Rectangle, but it's nowhere near the trajectory of the Ray. And if I put the Ray along the Rectangle, it doesn't detect a collision.

Second test, contactPoint is inside the Rect but not in the trajectory

Here's the code for the collision detection:

public static bool RayVsRect(Vector2 rayOrigin, Vector2 rayDirection, Rectangle rect,
            out Vector2 contactPoint, out Vector2 contactNormal, out float tHitNear)
        {
            contactPoint = Vector2.Zero;
            contactNormal = Vector2.Zero;
            tHitNear = 0;

            if (rayDirection.X == 0) rayDirection.X = float.Epsilon;
            if (rayDirection.Y == 0) rayDirection.Y = float.Epsilon;

            Vector2 tNear;
            Vector2 tFar;

            tNear = (rect.Location.ToVector2() - rayOrigin) / rayDirection;
            tFar = (rect.Location.ToVector2() + rect.Size.ToVector2() - rayOrigin) / rayDirection;

            if (tNear.X > tFar.X) Ray2D.Swap(ref tNear.X, ref tFar.X);
            if (tNear.Y > tFar.Y) Ray2D.Swap(ref tNear.Y, ref tFar.Y);

            if (tNear.X > tFar.Y || tNear.Y > tFar.X) return false;

            tHitNear = MathF.Max(tNear.X, tNear.Y);
            float tHitFar = MathF.Min(tFar.X, tFar.Y);

            if (tHitFar < 0 || tHitNear > 1) return false;

            contactPoint = rayOrigin + tHitNear * rayDirection;

            Debug.WriteLine($"Origin: {rayOrigin}, Direction: {rayDirection}, Point: {contactPoint}");

            if (tNear.X > tNear.Y)
            {
                if (rayDirection.X < 0)
                    contactNormal = Vector2.UnitX;
                else
                    contactNormal = -Vector2.UnitX;
            }
            else if (tNear.X < tNear.Y)
            {
                if (rayDirection.Y < 0)
                    contactNormal = Vector2.UnitY;
                else
                    contactNormal = -Vector2.UnitY;
            }

            return true;
        }

There may be some differences between C# and C++, which the tutorial was made in, that make my code not work properly. Like, dividing by 0 seemed to give him infinity but game me NaN, which is why I added the part that changes the rayDirection to Epsilon if it was 0. But I don't see anything else that could be an issue.

If I ignore the issue and follow along with the tutorial, the collision detection works fine some times, from some directions, but completely bugs out in others.

Even though in both tests, where one was in (1, 1) and one in (100, 1), the Rays were going in positive X and Y towards the Rect, one worked and one didn't.

答案1

得分: 0

我找到了问题,这有点愚蠢。我把rayDirection当作射线的终点位置来处理,但实际上它应该是相对于rayOrigin的位置。从终点位置减去rayOrigin可以解决这个问题。添加rayDirection -= rayOrigin;会起作用,但这不是函数应该工作的方式,相反,我在调用函数时进行了减法操作。

碰撞系统仍然不起作用,但我猜这可能是另一个问题。如果有关联,我将编辑这个问题。

英文:

Ok, so I found the problem, it's kind of dumb. I was treating the rayDirection as just the end position of the Ray, when it should've been relative to the rayOrigin. Subtracting rayOrigin from the end position fixes the problem. Adding rayDirection -= rayOrigin; would work, but that's not how the function was supposed to work, instead I did the subtraction when calling the function.

The collision system still doesn't work, but I guess it's because of another problem. I'll edit this if it's related.

huangapple
  • 本文由 发表于 2023年7月5日 01:31:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76614805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定