2D 圆矩形碰撞和反射不起作用



我有游戏,地图由矩形构建,较暗的矩形(称为"封闭"(表示球应该能够移动的地方,球应该从较亮的矩形(称为"开放"(边框反射。将来我会添加更多的球,它们会相互反射。

问题出在碰撞后的新矢量上。

我强制函数 circleRectGetCollisionNormal(( 返回 vector(-1,0( 我认为在这种情况下是正常的(球朝正确的方向移动(。 球从度开始,然后简单地将其更改为矢量,这种反射工作了 45 度,但是当我将角度更改为 10 度时,球移动到较轻的矩形(称为"打开"(。

这是它的样子(图片(

我是这样做的:

1-检查球是否与较轻的矩形碰撞, 2-如果它发生碰撞,我想改变方向,所以我返回矢量,例如球的右侧与矩形返回 [-1,0] 碰撞(我认为它的垂直线的法线,以及它的指向左方向(。

3-计算新球移动 这个等式中的矢量:newMoveVector = oldMoveVector − (2 * dotProduct(oldMoveVector, normalVector) * normalVector)

以下是每个步骤的代码:

1.

circleRect(circlePos, circleSize, rectPos, rectSize) { 
//its rectRect collision but it doesnt matter because reflection surface is always horizontal or vertical
let r1 = {
left: circlePos.x - circleSize.x/2,
right: circlePos.x + circleSize.x/2,
top: circlePos.y - circleSize.y/2,
bottom: circlePos.y + circleSize.y/2
};
let r2 = {
left: rectPos.x,
right: rectPos.x + rectSize.x,
top: rectPos.y,
bottom: rectPos.y + rectSize.y
};  
return !(r2.left > r1.right || 
r2.right < r1.left || 
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
isOnOpenTile(pos: Vector, size: Vector) {
let openTiles = this.getTiles('open');
let result = false;
openTiles.forEach(element => {
if( this.circleRect(pos,size,element.pos,element.size) ){
result = element;
return;
}
});
return result;
}

阿拉伯数字。

circleRectGetCollisionNormal(c, r) {
if(c.pos.y <= r.pos.y - (r.size.y/2)) return new Vector(0,-1);
//Hit was from below the brick
if(c.pos.y >= r.pos.y + (r.size.y/2)) return new Vector(0,1);
//Hit was from above the brick
if(c.pos.x < r.pos.x) return new Vector(1,0);
//Hit was on left
if(c.pos.x > r.pos.x) return new Vector(-1,0);
//Hit was on right
return false;
}

3.

getNewMoveVector(moveVector, normalVector) {
normalVector = this.normalize(normalVector);
let dot = (moveVector.x * moveVector.y) + (normalVector.x * normalVector.y);
let dotProduct = new Vector(dot, dot);
return moveVector.sub(dotProduct.mult(normalVector).mult(new Vector(2,2)));
}
normalize(v) {
let length = Math.sqrt((v.x*v.x) + (v.y*v.y));
return new Vector(v.x/length,v.y/length);
}

这是主要功能

getMoveVectorOnCollision(circle) {
let coll = this.isOnOpenTile( circle.pos, circle.size );
if( coll != false) {
let vector = this.circleRectGetCollisionNormal(circle, coll);
return this.getNewMoveVector(circle.moveVector, vector);
} else return false;
}

对象向量始终包含 2 个值,所有函数(mult、sub、div、add(的工作方式都像这里一样。

sub(vector: Vector) {
return new Vector(this.x - vector.x, this.y - vector.y);
}

请给我建议,实际解决方案或告诉进行此反思的不同方法。我浪费了3天多的时间试图解决这个问题,我必须继续前进。

Yor 点积计算是错误的。更改这些行:

let dot = (moveVector.x * moveVector.y) + (normalVector.x * normalVector.y);
let dotProduct = new Vector(dot, dot);

通过这一行:

let dotProduct = (moveVector.x * normalVector.x  + moveVector.y * normalVector.y);

请注意,dotProduct标量值,而不是向量,因此您必须将矢量减法为

subvec.x = 2 * dotProduct * normalVector.x
subvec.y = 2 * dotProduct * normalVector.y

return moveVector.sub(subvec);