贪吃蛇游戏:快速响应 vs. 碰撞错误
Snake game: fast response vs. collision bug
我有一个用 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 语句中,该语句只允许每帧更新一次,错误已解决,但控件的流畅性和响应性要差得多。
所以我的问题是,如何保持让机芯快速更新的响应性,同时避免移动到自身的错误?
我没有游戏开发经验,我什至不确定我是否理解你的问题。
但是,我想知道您的代码的以下结构是否有助于控制更新过程:
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 和 update 或 save timestamp 和 move(然后仅当最后一个时间戳减去当前时间戳比某个数字 more/less 时才移动)。
那是你制作的贪吃蛇;问题不在于您的输入(但那些 "if's" 应该是一个 switch 语句),而是在与输入反应的对象内,例如。 "Snake_Object"。当按下一个方向时,正常游戏会强制进行一定数量的位置移动。如果你看比赛,如果你向上按,那么蛇会立即被迫在它之前的位置上方一个碰撞箱。这确保您不会立即发生不需要的碰撞,并且仍然保持正常的 fps 流。
所以当 move 变量被发送到 Snake 时,它应该首先将整个碰撞盒朝那个方向移动,然后以正常速度移动。
我有一个用 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 语句中,该语句只允许每帧更新一次,错误已解决,但控件的流畅性和响应性要差得多。
所以我的问题是,如何保持让机芯快速更新的响应性,同时避免移动到自身的错误?
我没有游戏开发经验,我什至不确定我是否理解你的问题。
但是,我想知道您的代码的以下结构是否有助于控制更新过程:
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 和 update 或 save timestamp 和 move(然后仅当最后一个时间戳减去当前时间戳比某个数字 more/less 时才移动)。
那是你制作的贪吃蛇;问题不在于您的输入(但那些 "if's" 应该是一个 switch 语句),而是在与输入反应的对象内,例如。 "Snake_Object"。当按下一个方向时,正常游戏会强制进行一定数量的位置移动。如果你看比赛,如果你向上按,那么蛇会立即被迫在它之前的位置上方一个碰撞箱。这确保您不会立即发生不需要的碰撞,并且仍然保持正常的 fps 流。
所以当 move 变量被发送到 Snake 时,它应该首先将整个碰撞盒朝那个方向移动,然后以正常速度移动。