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