Snake游戏:快速反应vs碰撞漏洞

Snake game: fast response vs. collision bug

本文关键字:碰撞 漏洞 vs 快速反应 游戏 Snake      更新时间:2023-10-16

我在SFML c++中有一个蛇游戏,我在两个选项之间卡住了。如果这样设置控件:

    if(event.type == sf::Event::KeyPressed && (event.key.code == sf::Keyboard::Up
            || event.key.code == sf::Keyboard::W) && move != Down)
        move = Up;
    else if(event.type == sf::Event::KeyPressed && (event.key.code == sf::Keyboard::Down
            || event.key.code == sf::Keyboard::S) && move != Up)
        move = Down;
    else if(event.type == sf::Event::KeyPressed && (event.key.code == sf::Keyboard::Left
            || event.key.code == sf::Keyboard::A)&& move != Right)
        move = Left;
    else if(event.type == sf::Event::KeyPressed && (event.key.code == sf::Keyboard::Right
            || event.key.code == sf::Keyboard::D) && move != Left)
        move = Right;

这里,控件非常灵敏。问题是,例如,如果蛇向右移动,而你要快速连续按下向上和向左键,蛇还没有向上移动,但是向上的控制将被缓冲,所以蛇将被允许向左移动到自己身上,从而死亡。

如果我将这些移动条件包装在一个只允许每帧更新一次的If语句中,那么漏洞就得到了解决,但控制就不那么流畅和响应性了。

所以我的问题是,我如何保持允许运动快速更新的响应性,同时避免移动到自己的bug ?

既然你在制作Snake;问题不在于你的输入(但那些"if"应该是一个开关语句),而在于与输入反应的对象,例如"Snake_Object"。正常的游戏中,当一个方向被按下时,会强制进行一定数量的位置移动。如果你观看游戏,如果你向上按压,那么蛇就会立即被推到它原来所在位置上方的一个碰撞箱。这确保你不能做你不想要的直接碰撞,仍然保持正常的fps流。

所以当move变量被发送给Snake时,它应该在第一个实例中向那个方向移动整个碰撞框,然后以正常速度移动。

我没有游戏开发经验,我甚至不确定我是否理解你的问题。

但是,我想知道您的代码的以下结构是否有助于控制更新过程:

inline void UpdateMoveUp(Move& move)      { if(move != Down)  { move = Up;    }}
inline void UpdateMoveDown(Move& move)    { if(move != Up)    { move = Down;  }}
inline void UpdateMoveLeft(Move& move)    { if(move != Right) { move = Left;  }}
inline void UpdateMoveRight(Move& move)   { if(move != Left)  { move = Right; }}
inline void UpdateMoveInvalid(Move& move) { move = Invalid; }
inline void HandleUpdate(const Code& code, Move& move) {
  switch(code) {
    case sf::Keyboard::Up:
      return UpdateMoveUp(move);
    case sf::Keyboard::W:
      return UpdateMoveUp(move);
    case sf::Keyboard::Down:
      return UpdateMoveDown(move);
    case sf::Keyboard::S:
      return UpdateMoveDown(move);
    case sf::Keyboard::Left:
      return UpdateMoveLeft(move);
    case sf::Keyboard::A:
      return UpdateMoveLeft(move);
    case sf::Keyboard::Right:
      return UpdateMoveRight(move);
    case sf::Keyboard::D:
      return UpdateMoveRight(move);
    default:
      return UpdateMoveInvalid(move);
  }
}
void HandleInput(const Event& event, Move& move) {
  // I assume that `move` comes from somewhere else
  if(event.type == sf::Event::KeyPressed) {
    return HandleUpdate(event.key.code, move);
  }
}

我的看法是,您将更新函数隔离到一个地方,您可以在那里添加更多的更新条件,而不必再次测试整个条件。

换句话说,您可以为每个UpdateMoveXXXX函数添加进一步的条件,例如unbuffer并更新保存时间戳并移动(然后仅当最后一个时间戳减去当前时间戳大于/小于某个数字时移动)。