我正在制作一个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;
}
只是让“攻击者”偶尔粘在“后卫”身上,有什么建议可以解决这个问题吗?
添加评论以解释有兴趣使用它的其他人的代码。
答案 0 :(得分:0)
我会对此进行一次尝试,而不是实际尝试,所以我无法保证这是准确的。此外,这是伪代码。
我们需要知道球体之间的碰撞点。如果你在等待每一帧检测到碰撞,那么你的球体可能会部分穿透,所以我要做的第一件事就是把它们推出去。为了做到这一点,你需要知道推动每个人的距离。
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);
正如我之前所说,我没有测试过这段代码,所以它可能根本不起作用,但至少这对你来说可能是一个很好的起点,或者可能接近功能。希望这会有所帮助。祝你好运。