相信很多学习编程的小伙伴们都写/抄过“贪吃蛇”这个小游戏吧
我们先引入一段代码
#python
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
direction = LEFT
elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
direction = RIGHT
elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
direction = UP
elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
direction = DOWN
elif event.key == K_ESCAPE:
terminate()
// c\c++
void dir_control(char _dir){
switch(_dir)
{
case 's': this->dir = go_stop;
break;
case 'l': if(this->dir != go_right)this->dir = go_left;
break;
case 'r': if(this->dir != go_left)this->dir = go_right;
break;
case 'u': if(this->dir != go_down)this->dir = go_up;
break;
case 'd': if(this->dir != go_up)this->dir = go_down;
break;
}
}
怎么样,写过的朋友们看上去是不是感觉非常的眼熟,没写过的也没关系,听我解释一下。
- 贪吃蛇实现的一般思路:
- 初始化,将地图造出来。
- 如果有键盘输入的话,就重新设置运动方向。
- 制造食物。
- 让蛇移动,如果吃掉食物就重新生成一个食物,如果会死亡就break。
- 用蛇的坐标将地图中的空格替换为’#‘和’@’,将食物所在的坐标设置为’O’。
- 输出视图,即将最终生成的地图打印出来。
- Sleep(n) 暂停n毫秒之后在进行上面的。
上述的代码是在刷新贪吃蛇游戏界面(刷新画布)前,先去检测一下是否有用户输入,有输入就把输入取出,然后根据情况去改变贪吃蛇的移动方向(本质是改变蛇头的移动方向)。
到这里为止,是不是感觉没什么问题,确实,大家也都是这么做、这么写的。(然后我就是在这里,遇到了那个bug)
在玩的过程中,有的时候我们想让蛇快速的完成两次转向,一些速度快的贪吃蛇能够正确做出反应,不过有一些慢的,你就会发现你莫名奇妙的就 game over 了(我不知道你们有没有遇到过,反正我能找到的贪吃蛇代码、贪吃蛇开发教程等,下载下来试玩,都会遇到这个问题;相信能看到这篇文章的你一定也遇到了)
为什么会有这样的问题?
再回过去看代码,或者去看看网上能找到代码,都是在检测到方向键后直接去改变蛇的运动方向,然后根据方向变量的值move snake,然后因为要控制蛇的移动速度,会加上一小段的延迟。
那么问题来了,当我操作得很快,在延迟还没结束的时候,先后按下了正确的两个方向变更按键。
那是不是在下一次刷新画面前,检测按键会检测到两次按下并变更、或者是只检测到后面那次变更?
对,这两者都会产生问题:前者会连续2次改变蛇运动方向变量,使蛇头之后开始反向运动,导致吃到身体,game over;后者因为只检测到后一次的输入,而后一次输入是在上次输入被检测并正确执行的预期之上的,这就相当于检测到的输入与原来的运动方向相反或者同向,不发生变化,在你看来就好像自己啥都没按一样。
如何解决
我的解决方法是,将输入存入队列,每次move snake前从队列头部取出一个值,进行对应的按键操作。(将按键检测作为协程)
还有嘛,就是不要方向变量,按键按下时直接操作整条蛇的移动。