【问题标题】:Killing the invaders doesn't work in C++杀死入侵者在 C++ 中不起作用
【发布时间】:2012-10-09 21:50:35
【问题描述】:

我知道为了在 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");
    }
}

有人知道怎么回事吗?

【问题讨论】:

  • 你能把它放在一个小提琴(jsfiddle.com),保存并发布小提琴地址吗?
  • @PhilH 这是 C++,不是 JavaScript。
  • 有史以来最好的问题标题。
  • memset 任何带有0 的东西都可以轻松杀死它们。
  • 你只是对那些入侵者的 C++ 不够努力!

标签: c++ visual-c++ collision


【解决方案1】:

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

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

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

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

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

【讨论】:

  • +1 不错的概述。但是我不认为他会在任何时候在屏幕上出现成千上万的入侵者和/或成千上万的子弹。对于实际数量,基础容器恕我直言的选择并不重要。
  • @Fiktik - 在这种情况下可能不是,但最好了解每种不同 C++ 标准库容器类型的优缺点。
【解决方案2】:

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

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

【讨论】:

  • 尝试将碰撞测试放在 if(code==57) 语句之外
【解决方案3】:

别担心,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");
}

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 空间有效,这不是问题。问题是,我无法向入侵者发射子弹。
    【解决方案5】:

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

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

    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");
          }
        }
      }
    }
    

    现在这应该可以正常工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      相关资源
      最近更新 更多