9

我知道为了在 C++ 中杀死入侵者,我需要制作一个对撞机。然而,在那场比赛中,没有什么能杀死入侵者。这是标题中的代码:

bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);

这是我正在初始化的函数:

bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;

return true;
}

如果有人按下空格键,就会发生这种情况:

if (code == 57) { //Space
    myKeyInvader.MeBullet.Active = true;
    myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
    myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
    myKeyInvader.MeBullet.yvuel = 0.2;
    myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);

    if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
    Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
        //myKeyInvader.Ypos = 100;
        Invaders[counter].Active = false;
        printf("Collide!\n");
    }
}

有人知道出了什么问题吗?

4

5 回答 5

3

问题不在于 C++。问题是你如何使用它。编写代码的唯一方法是入侵者就在您的上方。但这为时已晚。外星入侵者已经杀了你。

您需要做的是将这些子弹变成您随时间传播的对象,就像您的入侵者是您随时间传播的对象一样。对用户按下空格键的响应应该是将项目符号的新实例添加到活动项目符号集中。这些活动子弹中的每一个都有一个随时间变化的位置。在每个时间步,您应该根据指示入侵者如何移动的规则推进活动入侵者的状态,并根据规定子弹如何移动的规则推进活动子弹的状态。当子弹到达屏幕顶部时移除子弹,如果外星入侵者到达屏幕底部,游戏结束。

在传播、移除屏幕外的子弹并检查游戏结束后,您想要检查 N 个子弹中的每一个与 M 个入侵者中的每一个之间的碰撞。当检测到碰撞时,从激活的子弹集合中移除子弹,并从激活的入侵者集合中删除外星入侵者。当然,你会想要一些漂亮的图形来向用户展示另一个外星人咬了灰尘。

另外:作为一个 NxM 问题,此检查可能是 CPU 使用率的最大消耗。您可以通过一些简单的启发式方法来加快速度。

您可以自己管理外星入侵者和子弹的集合,小心使用newdelete以防止您的入侵者和子弹因内存泄漏而杀死您的程序。你不必这样做。C++ 为您提供了一些漂亮的工具来管理这些集合。使用 C++ 标准库集合之一,而不是滚动您自己的集合。例如,std::vector<AlienInvader> invaders;std::list<AlienInvader> invaders,和项目符号相同。你会从中间删除很多,这表明std::list或者std::deque可能比std::vector这里更合适。

于 2012-10-19T11:06:12.077 回答
2

您在创建触发项目时测试它们的碰撞

不应该在主循环中对每一帧的每个现有项目进行测试碰撞吗?

于 2012-10-19T09:58:40.200 回答
1

不用担心,C++ 拥有杀死入侵者所需的一切 :)))

根据这么少的代码给出建议并不容易,但这里唯一的逻辑错误似乎是您仅在按下空格时测试碰撞;您可能应该在外部循环中对其进行测试:

if (code == 57) { //Space
    myKeyInvader.MeBullet.Active = true;
    myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
    myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
    myKeyInvader.MeBullet.yvuel = 0.2;
    myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}

从逻辑的角度来看,按空格键应该发射子弹:子弹的起始位置已设置,它在 Y 轴上的速度也是如此(因此它会上升)。

检查碰撞的代码应该在这个if块之外。事实上,这段代码只有在你仍然按下空格的时候才会执行——也就是说:仍然在触发——。是否应该仅在“仍在射击”时检查碰撞?你发射了一颗子弹并开始等待它摧毁入侵者的事实是否会在某种程度上干扰这颗子弹可以到达入侵者并实际上摧毁它的事实?当然不是!

if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
    Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
    //myKeyInvader.Ypos = 100;
    Invaders[counter].Active = false;
    printf("Collide!\n");
}

您希望在外部循环中检查碰撞,这可能还包含按键检查。这样,即使您只是看着屏幕等待,程序也会继续测试条件,当条件满足时,会执行与碰撞事件相关的代码(即:入侵者“未激活”)。

于 2012-10-19T10:27:12.097 回答
0

您的代码看起来不错,但是您需要围绕碰撞检查器进行两个循环:一个用于检查所有入侵者(不仅仅是其中一个),另一个用于检查沿其轨迹的每个子弹位置,而不仅仅是它离开枪的那一刻。

我假设我们有一个辅助函数来移动子弹并返回它是否仍在屏幕内:

bool BulletIsInScreen();

然后我们可以编写循环:

if (code == 57) { // Space
  while (BulletIsInScreen()) {
    for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
                                           // according to your comment to your own answer
      myKeyInvader.MeBullet.Active = true;
      myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
      myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
      myKeyInvader.MeBullet.yvuel = 0.2;
      myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);

      if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
                      Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
                      Invaders[i].Xipos, Invaders[i].Yipos,
                      Invaders[i].InvWidth, Invaders[i].InvHeight)) {
        //myKeyInvader.Ypos = 100;
        Invaders[i].Active = false;
        printf("Collide!\n");
      }
    }
  }
}

现在这应该可以按预期工作。

于 2012-10-19T11:10:37.277 回答
0

你说//Space,它是什么,还是应该是 32(如果是 ASCII)而不是 57?程序是否流入 if==57 块?

于 2012-10-19T09:50:13.220 回答