我已经在物理引擎上工作了大约一个星期,被困了几天试图找出如何解决碰撞。
我的问题是,如果有一个盒子卡在另外两个盒子的中间,或者盒子和墙壁之间,我的应用程序将陷入一段时间。它不会解决碰撞。
这是我的代码(注意:如果碰撞是右侧,则意味着物体A与物体B的右侧碰撞。距离是负的,因为物体在彼此内部,并且它在x或者中y轴取决于碰撞的一面。如果你需要更多的代码,例如碰撞类,它只是2个对象的容器,我可以提供。):
编辑:用新的处理碰撞方式编辑的代码:
//Move colliding objects so they don't collide anymore.
while (getCollidingAmount(objectVector)){
for (int i = 0; i < objectVector.size(); i++){
PhysicsObject* A = objectVector[i];
if (objectVector[i]->getPhysicsType() != PhysicsType::staticT && A->_collision.size() > 0){
Collision collision = A->_collision[A->getDeepestPenetrationCollisionIndex(A->_collision)];
PhysicsObject* B = collision.getObject();
switch (collision.getSide()){
case SideOfCollision::left:
case SideOfCollision::top:
//Opposite velocity
if (A->_saveVelocity.x < 0 && B->_saveVelocity.x > 0){
long double percentageOfVelocity = std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
case SideOfCollision::right:
case SideOfCollision::bottom:
//Opposite velocity
if (A->_saveVelocity.x > 0 && B->_saveVelocity.x < 0){
long double percentageOfVelocity = 1 - std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
}
updateCollisions(objectVector);
}
}
}
我在底部碰撞和顶部碰撞中的三角函数有问题:
sf::Vector2<long double> Collision::getVectorPenetration() const{
long double x;
long double y;
long double velX = _object->getVelocity().x;
long double velY = _object->getVelocity().y;
long double angle = atan2(velY, velX);
if (_side == SideOfCollision::left || _side == SideOfCollision::right){
x = getDistance();
y = x * tan(angle);
return sf::Vector2<long double>(x, y);
}
else if (_side == SideOfCollision::top || _side == SideOfCollision::bottom){
y = getDistance();
x = y / tan(angle);
return sf::Vector2<long double>(x, y);
}
}
感谢艾曼,我解决了我的问题。更新了我的collisionResponse代码以及匹配我处理碰撞的新方法。我现在有另一个问题,重力使得它在触摸另一个物体时无法沿X方向移动。如果任何熟悉这个问题的人都希望提供任何解决方法,我很感激:)。
所以看起来重力实际上不是问题,因为我可以将重力交换到x轴,然后能够沿着墙壁滑动盒子。三角学似乎仍有问题。
答案 0 :(得分:0)
我可以想出很多方法来解决这个问题。
1 - **更复杂的是**引入摩擦。以下是我实施它的方法,虽然这是未经测试的,但我有可能错过了一些想法。
每个形状都会产生摩擦力,并根据物体碰撞时的物体滑动。
首先,您需要获得垂直于曲面的角度。要做到这一点,你只需获得表面法线斜率的arctan
即可。法线只是-1/m
,其中m
是曲面的斜率(你是表面在y
中延伸多少的比率/商/它在x
)。我们将这个角度sNormal
称为&#34;表面正常&#34;。我们可能还需要sAngle
- &#34;表面角度&#34;以后(你可以通过arctan(m)
找到)。在角度上仍然存在一些含糊不清的问题,这与您是否正在谈论“前线”有关。或者后面的&#39;表面的。您必须手动处理。
接下来,您需要物体飞入的轨迹的角度,您已经知道如何找到(atan2(y,x)
)。我们将此角度oAngle
称为&#34;对象的曲面角度&#34;。接下来,您计算deltaAngle = sNormal - oAngle
。该角度表示表面完全阻挡了不的动量。 deltaAngle
为0表示所有动量消失,值PI/2
或90
表示两个表面平行相互接触,根本不会阻挡任何动量。介于两者之间,我们插入:
newSpeed = objectSpeed * deltaAngle/(PI/2);
newVelocity.x = cos(sAngle) * objectSpeed;
newVelocity.y = sin(sAngle) * objectSpeed;
现在这假设0摩擦。如果我们让1
的摩擦力是不允许对象滑动的最大摩擦力,我们会在应用newVelocity
值之前修改newSpeed,例如所以:newSpeed *= (1-friction);
。
我们有它!只需给你的平台一个小于1的摩擦值,你的盒子就能滑动。如果您正在处理直立盒子,那么顶墙的表面角度为PI
,底部为0
,右侧为PI/2
,而-PI/2
表面角度为{{1}}左墙。
2 - 更简单的选项是在求解器的计算中从对象的y速度中减去重力。