Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# AABB与定制物理引擎中的圆碰撞_C#_Collision Detection_Physics - Fatal编程技术网

C# AABB与定制物理引擎中的圆碰撞

C# AABB与定制物理引擎中的圆碰撞,c#,collision-detection,physics,C#,Collision Detection,Physics,我遵循了这个教程:为了用c#创建一个2d物理引擎(他几乎一直在错误和不一致的伪c++中工作),我已经让圆对圆碰撞和AABB对AABB碰撞正常工作。但当尝试AABB vs Circle collison(下图)时,两个刚体只是粘在一起,慢慢地向一个方向滑动 如果有人能帮我解决这个问题,我会非常感激,因为我已经花了好几天时间,仍然不知道是什么原因导致了这个错误 如果有人需要我的代码提供更多信息,我很乐意提供 public static bool AABBvsCircle(ref Collision

我遵循了这个教程:为了用c#创建一个2d物理引擎(他几乎一直在错误和不一致的伪c++中工作),我已经让圆对圆碰撞和AABB对AABB碰撞正常工作。但当尝试AABB vs Circle collison(下图)时,两个刚体只是粘在一起,慢慢地向一个方向滑动

如果有人能帮我解决这个问题,我会非常感激,因为我已经花了好几天时间,仍然不知道是什么原因导致了这个错误

如果有人需要我的代码提供更多信息,我很乐意提供

public static bool AABBvsCircle(ref Collision result) {
        RigidBody AABB = result.a.Shape is AABB ? result.a : result.b;
        RigidBody CIRCLE = result.b.Shape is Circle ? result.b : result.a;

        Vector2 n = CIRCLE.Position - AABB.Position;

        Vector2 closest = n;

        float x_extent = ((AABB)AABB.Shape).HalfWidth;
        float y_extent = ((AABB)AABB.Shape).HalfHeight;

        closest.X = Clamp(-x_extent, x_extent, closest.X);
        closest.Y = Clamp(-y_extent, y_extent, closest.Y);


        bool inside = false;

        if (n == closest) {
            inside = true;

            if (Abs(n.X) > Abs(n.Y)) {
                // Clamp to closest extent
                if (closest.X > 0)
                    closest.X = x_extent;
                else
                    closest.X = -x_extent;
            }

            // y axis is shorter
            else {
                // Clamp to closest extent
                if (closest.Y > 0)
                    closest.Y = y_extent;
                else
                    closest.Y = -y_extent;
            }
        }

        Vector2 normal = n - closest;
        float d = normal.LengthSquared();
        float r = ((Circle)CIRCLE.Shape).Radius;

        // Early out of the radius is shorter than distance to closest point and
        // Circle not inside the AABB
        if (d > (r * r) && !inside)
            return false;

        // Avoided sqrt until we needed
        d = (float)Sqrt(d);

        if (inside) {
            result.normal = -normal / d;
            result.penetration = r - d;
        }
        else {
            result.normal = normal / d;
            result.penetration = r - d;
        }

        return true;
    }
在“碰撞”结构中编辑1碰撞解析方法


在对代码逻辑进行任何详细检查之前,我发现了以下潜在错误:

result.normal=-normal/d

由于
d
设置为
normal.LengthSquared
而不是
normal.Length
,因此应用的位置校正可能(远)小于或(远)大于预期。考虑到对象“粘在一起”,很可能是前者,即
d>1

(修复方法当然只是
result.normal=-normal/Math.Sqrt(d);


请注意,上述可能不是唯一的错误来源;如果仍有不良行为,请告诉我。

尽管您的标记指定了C#;这里是AABB到AABB和AABB的基本循环,这些碰撞是C++中完成的,因为它们取自:


AABB-AABB协商

// AABB to AABB Collision
GLboolean CheckCollision(GameObject &one, GameObject &two) {
    // Collision x-axis?
    bool collisionX = one.Position.x + one.Size.x >= two.Position.x &&
        two.Position.x + two.Size.x >= one.Position.x;
    // Collision y-axis?
    bool collisionY = one.Position.y + one.Size.y >= two.Position.y &&
        two.Position.y + two.Size.y >= one.Position.y;
    // Collision only if on both axes
    return collisionX && collisionY;
}
// AABB to Circle Collision without Resolution
GLboolean CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(
        two.Position.x + aabb_half_extents.x, 
        two.Position.y + aabb_half_extents.y
    );
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Add clamped value to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Retrieve vector between center circle and closest point AABB and check if length <= radius
    difference = closest - center;
    return glm::length(difference) < one.Radius;
}
// AABB - Circle Collision with Collision Resolution
Collision CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(two.Position.x + aabb_half_extents.x, two.Position.y + aabb_half_extents.y);
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Now that we know the the clamped values, add this to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Now retrieve vector between center circle and closest point AABB and check if length < radius
    difference = closest - center;

    if (glm::length(difference) < one.Radius) // not <= since in that case a collision also occurs when object one exactly touches object two, which they are at the end of each collision resolution stage.
        return std::make_tuple(GL_TRUE, VectorDirection(difference), difference);
    else
        return std::make_tuple(GL_FALSE, UP, glm::vec2(0, 0));
}

AABB无分辨率旋转碰撞

// AABB to AABB Collision
GLboolean CheckCollision(GameObject &one, GameObject &two) {
    // Collision x-axis?
    bool collisionX = one.Position.x + one.Size.x >= two.Position.x &&
        two.Position.x + two.Size.x >= one.Position.x;
    // Collision y-axis?
    bool collisionY = one.Position.y + one.Size.y >= two.Position.y &&
        two.Position.y + two.Size.y >= one.Position.y;
    // Collision only if on both axes
    return collisionX && collisionY;
}
// AABB to Circle Collision without Resolution
GLboolean CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(
        two.Position.x + aabb_half_extents.x, 
        two.Position.y + aabb_half_extents.y
    );
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Add clamped value to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Retrieve vector between center circle and closest point AABB and check if length <= radius
    difference = closest - center;
    return glm::length(difference) < one.Radius;
}
// AABB - Circle Collision with Collision Resolution
Collision CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(two.Position.x + aabb_half_extents.x, two.Position.y + aabb_half_extents.y);
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Now that we know the the clamped values, add this to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Now retrieve vector between center circle and closest point AABB and check if length < radius
    difference = closest - center;

    if (glm::length(difference) < one.Radius) // not <= since in that case a collision also occurs when object one exactly touches object two, which they are at the end of each collision resolution stage.
        return std::make_tuple(GL_TRUE, VectorDirection(difference), difference);
    else
        return std::make_tuple(GL_FALSE, UP, glm::vec2(0, 0));
}
但是,
AABB的原始
checkcollation()
函数有一点变化,它将声明/定义更改为返回一个
冲突,而不是一个
GLboolean

AABB-具有碰撞分辨率的圆形碰撞

// AABB to AABB Collision
GLboolean CheckCollision(GameObject &one, GameObject &two) {
    // Collision x-axis?
    bool collisionX = one.Position.x + one.Size.x >= two.Position.x &&
        two.Position.x + two.Size.x >= one.Position.x;
    // Collision y-axis?
    bool collisionY = one.Position.y + one.Size.y >= two.Position.y &&
        two.Position.y + two.Size.y >= one.Position.y;
    // Collision only if on both axes
    return collisionX && collisionY;
}
// AABB to Circle Collision without Resolution
GLboolean CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(
        two.Position.x + aabb_half_extents.x, 
        two.Position.y + aabb_half_extents.y
    );
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Add clamped value to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Retrieve vector between center circle and closest point AABB and check if length <= radius
    difference = closest - center;
    return glm::length(difference) < one.Radius;
}
// AABB - Circle Collision with Collision Resolution
Collision CheckCollision(BallObject &one, GameObject &two) {
    // Get center point circle first 
    glm::vec2 center(one.Position + one.Radius);
    // Calculate AABB info (center, half-extents)
    glm::vec2 aabb_half_extents(two.Size.x / 2, two.Size.y / 2);
    glm::vec2 aabb_center(two.Position.x + aabb_half_extents.x, two.Position.y + aabb_half_extents.y);
    // Get difference vector between both centers
    glm::vec2 difference = center - aabb_center;
    glm::vec2 clamped = glm::clamp(difference, -aabb_half_extents, aabb_half_extents);
    // Now that we know the the clamped values, add this to AABB_center and we get the value of box closest to circle
    glm::vec2 closest = aabb_center + clamped;
    // Now retrieve vector between center circle and closest point AABB and check if length < radius
    difference = closest - center;

    if (glm::length(difference) < one.Radius) // not <= since in that case a collision also occurs when object one exactly touches object two, which they are at the end of each collision resolution stage.
        return std::make_tuple(GL_TRUE, VectorDirection(difference), difference);
    else
        return std::make_tuple(GL_FALSE, UP, glm::vec2(0, 0));
}
//AABB-具有冲突解决方案的圆冲突
碰撞检查碰撞(BallobObject&1,GameObject&2){
//先得到圆心圆
glm::vec2中心(一个位置+一个半径);
//计算AABB信息(中心、半范围)
glm::vec2 aabb_半_扩展数据块(两个.Size.x/2,两个.Size.y/2);
glm::vec2 aabb_中心(两个位置.x+aabb_半个范围.x,两个位置.y+aabb_半个范围.y);
//获取两个中心之间的差向量
glm::vec2差异=中心-aabb_中心;
glm::vec2钳制=glm::钳制(差异,-aabb_半_区段,aabb_半_区段);
//现在我们知道了钳制值,将其添加到AABB_中心,我们得到最接近圆的框的值
glm::vec2最近=aabb_中心+夹紧;
//现在检索中心圆和最近点AABB之间的向量,并检查长度是否<半径
差=最近-中心;
if(glm::length(difference)级别].Bricks)
{
如果(!box.已销毁)
{
碰撞=检查碰撞(*球,盒);
if(std::get(collision))//如果collision为true
{
//如果不是固体,则销毁块
如果(!box.IsSolid)
box.destromed=GL\u TRUE;
//冲突解决
方向dir=std::get(冲突);
glm::vec2 diff_vector=std::get(冲突);
if(dir==左| | dir==右)//水平碰撞
{
Ball->Velocity.x=-Ball->Velocity.x;//反向水平速度
//重新安置
GLfloat贯穿件=球体->半径-std::abs(diff_vector.x);
if(dir==左)
球->位置.x+=穿透;//向右移动球
其他的
球->位置.x-=穿透;//向左移动球;
}
else//垂直碰撞
{
Ball->Velocity.y=-Ball->Velocity.y;//反向垂直速度
//重新安置
GLfloat贯穿件=球体->半径-std::abs(差分向量y);
if(dir==UP)
球->位置.y-=穿透;//向上移动球B
其他的
球->位置.y+=穿透;//向下移动球
}
}
}    
}
//同时检查播放器键盘的碰撞情况(除非卡住)
碰撞结果=检查碰撞(*球,*球员);
如果(!Ball->卡住&&std::get(结果))
{
//检查撞击板的位置,并根据撞击板的位置改变速度
GLfloat centerBoard=Player->Position.x+Player->Size.x/2;
GLfloat距离=(球->位置.x+球->半径)-中心板;
GLfloat百分比=距离/(玩家->大小.x/2);
//然后相应地采取行动
GLfloat强度=2.0f;
glm::vec2 oldVelocity=球->速度;
球->速度.x=初始球速度.x*百分比*强度;
//Ball->Velocity.y=-Ball->Velocity.y;
球->速度=glm::规格化(球->速度)*glm::长度(旧速度);//在两个轴上保持速度一致(乘以旧速度的长度,所以总强度不变)
//固定粘性桨
球->速度.y=-1*abs(球->速度.y);
}
}

现在,上面的一些代码是
Game-specific
,如
Game
类、
Ball
类、
Player
等。这些代码被认为是从
GameObject
继承的,但算法本身应该提供有用的信息,因为这正是您所寻找的,但来自不同的语言。现在,就你的实际问题而言,你使用的似乎不仅仅是基本运动,因为你使用的是某种形式的动力学,可以从你的
Resolve()
方法中看到

结束