矩形的碰撞响应

时间:2016-02-19 15:18:32

标签: physics collision

我已经在物理引擎上工作了大约一个星期,被困了几天试图找出如何解决碰撞。

我的问题是,如果有一个盒子卡在另外两个盒子的中间,或者盒子和墙壁之间,我的应用程序将陷入一段时间。它不会解决碰撞。

这是我的代码(注意:如果碰撞是右侧,则意味着物体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);
}

}

更新2

感谢艾曼,我解决了我的问题。更新了我的collisionResponse代码以及匹配我处理碰撞的新方法。我现在有另一个问题,重力使得它在触摸另一个物体时无法沿X方向移动。如果任何熟悉这个问题的人都希望提供任何解决方法,我很感激:)。

更新3

所以看起来重力实际上不是问题,因为我可以将重力交换到x轴,然后能够沿着墙壁滑动盒子。三角学似乎仍有问题。

1 个答案:

答案 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/290表示两个表面平行相互接触,根本不会阻挡任何动量。介于两者之间,我们插入:

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速度中减去重力。