实施射弹运动和碰撞检测 - 在2D自上而下的游戏中进行响应

时间:2013-03-05 07:46:06

标签: collision-detection topdown projectile

有很多关于2D游戏中弹丸运动的例子。

  • 但是,在2D俯视视图游戏中实现射弹运动的公式是什么?例如,我们想踢球并增加其高度(就像明智的足球一样)。

我读到可能有两个精灵,一个用于球,另一个用于阴影,可以创造出球越来越高的幻觉。

  • 但是,当球击中球时,我们如何实现碰撞检测和响应?我们还必须使用z坐标吗?

1 个答案:

答案 0 :(得分:3)

您面临的问题说明了图形和逻辑之间的重要区别 - 即用户看到的内容与图像反映的底层虚拟世界之间的差异。

2D和3D世界的维度不必总是匹配。事实上,从根本上说,所有图形都是2D,从Pong到Skyrim。游戏开发者必须做出的关于维度的唯一决定是:

  • 是游戏逻辑3D?
  • 如果是这样,3D世界如何投影到2D屏幕,从什么角度来看?

在你的情况下,第一个问题的答案似乎是肯定的,考虑到球可以在空中踢球。这意味着您现在正处于成熟的“3D”图形领域,这种图形可能存在。通过“2D自上而下”游戏,你现在可能意味着“无底3D自上而下游戏”。这可以使用正交或等距投影来完成,如果你很好奇,你可以谷歌。

阴影效果是完成这种投射的一个很好的选择,因为非常简单的线索可以在玩家对空间的视觉感知中有很长的路要走。请记住,它不仅仅是一种错觉,而不是光环中的3D图形是一种幻觉。屏幕是平的,我们的视网膜是平的,图形也应该是平的。这不会使虚拟或物理世界变得更少3D。

对于第二个问题,你可能不会完全自上而下地投射。如果你是这样的话,那个阴影总会被球遮挡,你只会看到足球运动员的头顶。我猜你可能正在谈论45度角向下投影,它看起来更自然,并且从一开始就用于游戏。口袋妖怪是一个很好的例子。这就是所有行动:

class SoccerBall extends GameObject3D {
    voic draw() {
        translate(x, y / 2); // the camera is at an angle, so we foreshorten in the y direction
        drawShadow();
        translate(0, z / 2);
        drawBall();
        // cleanup the changes we made to the graphics state
        translate(-x, -y / 2 - z / 2);
    }
}

现在,回到你原来的问题,主要是游戏逻辑。通过向球的位置引入高度,您毫无疑问地引入了z维度。对于您的情况,可能很少使用此z维度。您可能希望将对象拆分为GameObjectGameObject3D s,前者需要xy,而后者需要额外z (或者可能是height,这可能会提供更多信息。)

射弹运动非常简单。只需根据需要增加和减少高度

class SoccerBall extends GameObject3D {
    float vel_x;
    float vel_y;
    float vel_z;

    // most of the soccer ball class...

    void kick(angle direction, angle inclination, float force) {
        // calculate based on direction
        vel_x = force * cos(direction);
        vel_y = force * sin(direction);
        // take into account inclination
        vel_z = force * sin(inclination);
        vel_x *= cos(inclination);
        vel_y *= cos(inclination);
    }

    void movement_update(float delta_time) {
        // this function assumes our location
        // units are in meters
        // and our velocity units
        // are in meters/second

        // apply gravity
        vel_z -= 9.8 * delta_time; // EDIT: switched from += to -=.  += could be useful if you're playing soccer with a balloon for a ball!

        // move
        x += vel_x * delta_time;
        y += vel_y * delta_time;
        z += vel_z * delta_time;
    }
}

对于碰撞检测,如果您只关心与地面的碰撞,您可以进行简单的if (z < 0) {z = 0; vel_z = 0}检查。对于任何更复杂的事情,基于网格的系统始终是碰撞检测的理想选择,因为计算对象的网格方块很便宜(floor(x), floor(y)),然后您只需要检查方块中的其他对象。这在3D中与在2D中一样容易,并且在互联网上的其他地方有很多很好的解释。

玩得开心:)