我正在制作一个 2d 弹球游戏并使用 BoundingSphere 作为命中框,作为捷径。

我遇到的问题是很多东西一直在旋转,我需要找到一种方法来计算球击中其他圆形物体时的“准确”反弹角度。

任何帮助、插入和线索将不胜感激

/编辑
找不到任何东西,但设法解决了这个问题,有点工作

一旦检测到两个 BoundingSphere 之间的碰撞,就会调用它。

                private void CollisionRebound(Sprites.BaseSprite attacker, Vector2 defender)
    {
        //Work out the rotation that would result in a "dead on" collision
        //thus rebounding the attacker straight back the way they came.
        float directHitRotation = (float)Math.Atan2(defender.Y - attacker.Position.Y , defender.X - attacker.Position.X);
        //only really needed if the rotation is a negative value but is easier to work from in general.
        float attackerRotation = attacker.rotation;

        //This makes the rotation a positive number, it cant be less that -2PI
        //so adding 2PI will leave us with a positive rotation.
        if (attackerRotation < 0)
        {
            attackerRotation += (float)(Math.PI * 2);
        }


        //If the rotation is greater than the "dead on" rotation the rotation
        //needs to increase.
        if (attackerRotation > directHitRotation)
        {
            //we add "PiOver2" or "90 degrees" to "dead on" rotation because we do, dont know enough
            //trig to explain it just know it works, we then add 90 degrees minus the difference between
            //our two rotation to give us our outgoing angle, the +0.01f is for the rare case where the
            //difference is 90 which would give us no change in rotation but if the two spheres have collided
            //(which they have to before coming to this code chunk) there will be at least some change.
            attackerRotation = directHitRotation + (float)MathHelper.PiOver2 + ((float)MathHelper.PiOver2 -
                (attackerRotation - directHitRotation) + 0.01f);
        }
            //If the rotation is less than the "dead on" rotation the rotation
            //need to decrease.
        else if (attackerRotation < directHitRotation)
        {
            //same as previous chunk but we will be minusing the angle
            attackerRotation = directHitRotation - (float)MathHelper.PiOver2 - ((float)MathHelper.PiOver2 -
                (attackerRotation - directHitRotation) - 0.01f);
        }
        else if (attackerRotation == directHitRotation)
        {
            //either of the two calculations could be used here but would result in the same outcome
            //which is rotating the attacker 180 degrees, so just add 2PI instead.
            attackerRotation += (float)Math.PI;
        }

        //Here we just assign out new output rotation to the attacker entity.
        attacker.rotation = attackerRotation;
    }

只是偶尔让“攻击者”粘在“防御者”中,有什么建议可以解决这个问题吗?

添加了注释以向有兴趣使用它的其他人解释代码。

最佳答案

我将尝试一下,而不实际尝试一下,所以我不能保证这是准确的。此外,这是伪代码。

我们需要知道球体之间的碰撞点。如果您正在等待每一帧来检测碰撞,那么您的球体可能会部分相互渗透,所以我要做的第一件事就是将它们相互推开。为了做到这一点,你需要知道每一个推多远。

Vector3 BtoA = (SphereA.center - SphereB.center);
Vector3 AtoB = (SphereB.center - SphereA.center);

float currentDistance = AtoB.length();

float minimumDistance = SphereA.radius + SphereB.radius;

// If the spheres are interpenetrating then push them apart until
// they're colliding only at a single point.

// Do a quick sanity check here
if ( currentDistance > minimumDistance )
{
    // Your spheres aren't close enough to be touching, how did you get here?
}
else if ( currentDistance < minimumDistance )
{
    // We move each sphere away by half of the penetration distance.
    float penetrationDistance = currentDistance - minimumDistance;

    Vector3 unitBtoA = BtoA.unitize();
    SphereA.position = SphereA.position + (unitBtoA * penetrationDistance * 0.5f);

    Vector3 unitAtoB = AtoB.unitize();
    SphereB.position = SphereB.position + (unitAtoB * penetrationDistance * 0.5f);

    // Note that now that we have repositioned the spheres they have different AtoB and
    // BtoA vectors, and theoretically could be colliding with spheres very close to
    // them that they weren't colliding with before. We now recalculate our difference vectors
    BtoA = (SphereA.center - SphereB.center);
    AtoB = (SphereB.center - SphereA.center);
}

// Ok, now we know that the spheres are only touching at one point. We can now calculate
// the reflection/deflection

// I believe the code for calculating a deflection of a velocity off of a surface
// given the normal of that surface is something like this. This assumes no energy
// is lost on the bounce as well, which isn't realistic.
Vector3 Reflect( Vector3 velocity, Vector3 surfaceNormal )
{
    const float dotProductTimesTwo = velocity.Dot(surfaceNormal) * 2.0f;
    velocity.x -= dotProductTimesTwo * surfaceNormal.x;
    velocity.y -= dotProductTimesTwo * surfaceNormal.y;
    velocity.z -= dotProductTimesTwo * surfaceNormal.z;
}

// Using the above function, we reflect the velocities of both spheres
Vector3 unitBtoA = BtoA.unitize();
Vector3 unitAtoA = AtoA.unitize();

SphereA.velocity = Reflect( SphereA.velocity, unitBtoA );
SphereB.velocity = Reflect( SphereA.velocity, unitAtoB );

如果您想使反弹更准确,您应该能够根据球体的穿透深度计算出,如果您不使用基于帧的应用程序,它们会发生碰撞后经过了多长时间。这应该可以让您计算出它们应该相距多远,因为它们已经相互弹开。如果您计算该时间,那么您可以采用我们上面计算的球体速度,并根据该时间量修改球体的位置。
// This variable would hold the amount of time since the spheres actually would have collided
float extra_time;

SphereA.position = SphereA.position + (SphereA.velocity * extra_time);
SphereB.position = SphereB.position + (SphereB.velocity * extra_time);

正如我之前所说,我没有测试过这段代码,所以它可能根本不起作用,但至少这对你来说可能是一个很好的起点,或者可能接近功能。希望这会有所帮助。祝你好运。

关于c# - 反弹旋转的边界球,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14491685/

10-11 20:55