0

在我的游戏中,有一个道具可以让玩家的弹丸从游戏区的墙壁上反弹。我似乎无法让它工作,游戏边界正常水平和垂直。

目前我的代码是这样的;

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 坐标,但这根本不起作用,射弹只是继续超出边界。

4

1 回答 1

4

逆时针弧度(正) 顺时针弧度(负)

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

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

首先,我将使用当前代码查看案例,以说明为什么会发生不正确的行为。我将把“入射角”称为球在碰撞前(与相应的墙壁)的角度,将“偏转角”称为球在碰撞后应该具有的角度。


使用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、蓝色矢量 和C表示相同的事物)。

偏转示例(垂直法线)

从这个图中,我们可以推导出C = PI + BB = 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

同样,您可以以类似的方式检查其他情况并得出其余方程式。您会注意到,击中底部的球使用与击中顶部相同的方程求解,并且您会发现deflected_angle = PI - incident_angle左侧和右侧的方程相同。

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


其他注意事项

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

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

于 2012-10-28T21:02:46.047 回答