弹丸游戏边界弹跳不正常

时间:2012-10-28 19:53:30

标签: c# xna

在我的游戏中有一个加强,使得玩家的弹丸从游戏区域的墙壁反弹。我似乎无法让它发挥作用,游戏边界是正常的水平和垂直。

目前我的代码就是这个;

public void UpdatePlasma()
{
    Direction = new Vector2((float)Math.Cos(Angle), (float)Math.Sin(Angle));
    //Vector2 Velocity = new Vector2(1, 1);
    Position += Direction * projSpeed;

    if ((Position.X >= viewport.Width) || (Position.X <= 0))
    {
        Angle = -Angle;
    }

    else if ((Position.Y >= viewport.Height) || (Position.Y <= 0))
    {
        Angle = -Angle;
    }
}

这种作品。抛射物有时会反弹顶部和底部边界(认为这可能是由于角度变为0因此在否定并通过时方向不会改变)而在左右边界上根本不会。然后我尝试将我的位置乘以注释掉的速度矢量,然后否定X或Y坐标,但这并不能完全起作用,只是继续在边界之外。

1 个答案:

答案 0 :(得分:4)

Radians counter-clockwise (positive) Radians clockwise (negative)

这些图表显示了围绕圆圈顺时针或逆时针移动时的弧度角。我假设,在你的游戏中,红色箭头的方向相当于给定特定角度的球的运动(即0 rad是正确的,PI / 2 rad是向上的,依此类推)。

使用这些图表作为参考,考虑球撞击墙壁的四种情况:分别向上,向右,向下和向左移动时的顶部,右侧,底部和左侧。

首先,我将使用当前代码查看案例,以说明错误行为发生的原因。我指的是&#34;入射角度&#34;作为球在碰撞前(与相应的墙壁)的角度,以及&#34;偏转的角度&#34;作为碰撞后球应该具有的角度。


使用deflected_angle = -incidence_angle

案例1:球向上移动,击中顶壁:

incidence_angle = PI/2 = up
deflected_angle = -PI/2 = 3PI/2 = down

好!

案例2:球向下移动,击中底壁:

incidence_angle = 3PI/2 = down
deflected_angle = -3PI/2 = up

好!

案例3:球向右移动,击中右墙:

incidence_angle = 0 = right
deflected_angle = -0 = 0 = right

糟糕!

案例4:球向左移动,击中左墙:

incidence_angle = PI = left
deflected_angle = -PI = PI = left

糟糕!


现在我们已经理解了为什么当前代码在某些情况下表现正常而在其他情况下却没有,我们必须提出一些解决方案。应该清楚的是,我们对简单地否定角度不感兴趣。相反,(至少对于四个样本案例),我们希望球在相反方向上偏转;我们可以通过将PI添加到我们的角度来实现这一点,这是一个半圈转。

现在让我们用新的等式来讨论我们的案例。


使用deflected_angle = incidence_angle + PI

案例1:球向上移动,击中顶壁:

incidence_angle = PI/2 = up
deflected_angle = PI/2 + PI = 3PI/2 = down

好!

案例2:球向下移动,击中底壁:

incidence_angle = 3PI/2 = down
deflected_angle = 3PI/2 + PI = 5PI/2 = PI/2 = up

好! (请注意,5PI/2围绕圆圈完成一圈,然后是一些。我们可以通过计算5PI/2 - 2PI PI/2获得相同的角度。)

案例3:球向右移动,击中右墙:

incidence_angle = 0 = right
deflected_angle = 0 + PI = PI = left

好!

案例4:球向左移动,击中左墙:

incidence_angle = PI = left
deflected_angle = PI + PI = 2PI = 0 = right

好!


我建议尝试此解决方案并观察结果。当球以一个我们正在考虑的四个角度以外的角度撞击两侧时,你仍然应该观察到奇怪的行为(特别是,它会朝着它来的方向反弹,而不是像我们所期望的那样偏转)

为了纠正这个问题,当我们撞到垂直墙(左侧或右侧)时,我们想要将偏转角计算为deflected_angle = PI - incident_angle,当我们到达水平墙(顶部或底部)时,我们想要计算角度为deflected_angle = 2PI - incident_angle

为什么会出现这种情况,如下图所示。为简洁起见,我们只会看看球击中顶壁的情况;其他案例也有类似的说明。

红色矢量表示入射角,蓝色矢量表示偏转角。每个向量出现两次,只是被翻译,没有改变它们的含义(唯一的目的是澄清图表)。此外,角度还被示为弧ABC(即:红色矢量和A,以及蓝色矢量和{{1代表同样的事情。)

Deflection example (vertical normal)

从此图表中,我们可以推导出CC = PI + B。我们将这些放在一起以得出最终的等式。 (请注意B = PI - A是我们的偏转角度,C是入射角度。

A

同样,你可以用类似的方式检查其他情况并得出其余的方程式。您会注意到击中底部的球用与击中顶部相同的等式求解,并且您会发现左侧和右侧的等式let: C = PI + B B = PI - A then: C = PI + (PI - A) C = PI + PI - A C = 2PI - A note: 2PI = 0 therefore, C = -A (this is why the top and bottom cases worked) therefore: deflected_angle = 2PI - incidence_angle 是相同的。

如果你想进一步阅读,你可以将球偏离任何线(即:不仅仅是水平或垂直);这可以通过观察你偏离的表面的法线来完成。我会避免列出和特定链接,因为它们可能会被破坏;相反,我会推荐一些谷歌搜索(他们可能会有一段时间;))。


其他注意事项

你必须在游戏物理中处理的另一个问题,至少使用离散物理(与连续方法相反,试图在碰撞发生之前确定碰撞时间),对象将相互渗透。要了解这个问题,请考虑如果您的球停留在边界之外超过一个更新周期会发生什么(根据您的更新频率,球速度,球加速度和碰撞分辨率,可能会或可能不会) 。在第一个更新周期中,假设您检测到球在边界上方,因此您正确计算了偏转角度并将其设置为球的新角度。现在,在你的第二个更新周期中,你按照这个角度移动球,但是球仍然在边界之上(也就是说,由于它的速度和加速度重新进入边界,它没有移动得足够远);你的代码将再次检测到球在界限之上并向上偏转球!结果是你的球将被困在墙上一小段时间,永久地卡在墙上,或完全离开比赛场地。有许多方法可以解决这个问题,这个问题超出了这个特定问题的范围。

还有一个缺失的案例(好吧,实际上有四个,但对所有人来说都是一样的想法):如果球穿过球场的一角怎么办?如果您只将球视为撞到一面墙,那么您的偏转角将是不正确的并且会使球飞出边界。因此,您需要额外的逻辑来解释这种可能性。