自制贪吃蛇游戏中的几个“大坑”

  贪吃蛇游戏已经告一段落了,在完成这个游戏的过程中,我遭遇了许多“坎坷”和“挫折”,下面就几个让我印象深刻的“挫折”做一个具体的讲解,以此来为这个贪吃蛇项目画上一个完整句号。(包括打包这个游戏时遇到的问题及解决方式。)

  • BUG1  在运行贪吃蛇游戏时,如果同时按下两个方向键会出现贪吃蛇“莫名其妙”死亡的情况。针对此情况我先是判断贪吃蛇的死亡原因:
    #贪吃蛇死亡判定
    def isdead(self):
        #条件1——贪吃蛇撞墙
        if (self.snake_body[len(self.snake_body)-1][0] == self.living_space[0] - self.size or             self.snake_body[len(self.snake_body)-1][0] == self.living_space[0] + self.living_space[2])        or (self.snake_body[len(self.snake_body)-1][1] == self.living_space[1] - self.size or             self.snake_body[len(self.snake_body)-1][1] == self.living_space[1] + self.living_space[3]):
            #print(‘die for me 1‘)
            return True
        #条件2——贪吃蛇“追尾”
        for bodynet in self.snake_body[:-1]:
            if bodynet == self.snake_body[len(self.snake_body)-1]:
                #print(‘die for me 2‘)
                return True

  通过贪吃蛇再次因此死亡而呈现的死亡原因(die for me 2)我得出贪吃蛇是因头部触碰到身体其他部位而“死亡”的结论。(即头部坐标与身体其他部分坐标出现重合)。然而在贪吃蛇因为这种情况而死亡时窗体中并没有呈现出其头部与身体其他部分触碰的情形,看来答案只能在代码中寻找了。

  #开始主循环
    while True:
    #for _ in range(8):

        print(‘while start‘)

        for event in pygame.event.get():
            #print(‘get event‘)
            #print(‘direction‘,DIRECTION)
            if event.type == QUIT:
                pygame.quit()
                exit()

            elif event.type == KEYDOWN:
                if event.key == K_LEFT and DIRECTION != ‘RIGHT‘:
                    DIRECTION = ‘LEFT‘
                elif event.key == K_RIGHT and DIRECTION != ‘LEFT‘:
                    DIRECTION = ‘RIGHT‘
                    #print(DIRECTION)
                elif event.key == K_UP and DIRECTION != ‘DOWN‘:
                    DIRECTION = ‘UP‘
                elif event.key == K_DOWN and DIRECTION != ‘UP‘:
                    DIRECTION = ‘DOWN‘
                    #print(DIRECTION)
                elif event.key == K_SPACE:
                    pause_flag = 0
                    while True:
                        for event in pygame.event.get():
                            if event.type == QUIT:
                                pygame.quit()
                                exit()

                            if event.type == KEYDOWN:
                                if event.key == K_SPACE:
                                    pause_flag = 1

                        if pause_flag == 1:
                            break

                elif event.key == K_LSHIFT:
                    SNAKE_SPEED *= 3
                print(‘DIRECTION‘,DIRECTION)
            elif event.type == KEYUP:
                if event.key == K_LSHIFT:
                    SNAKE_SPEED /= 3

        foodbody = food._food_pos            #获取当前食物的坐标,用以判断贪吃蛇移动后是否是吃食物
        snake.move(DIRECTION,foodbody)       #贪吃蛇开始移动
        #print(‘before:‘,food._food_pos,snake.snake_body[snake.head])

        snakebody = snake.snake_body         #获取移动后贪吃蛇的坐标集,用以确保食物不会在贪吃蛇身体中生成
        exist     = snake.foodstate          #获取食物状态标志位,判断食物是否被贪吃蛇吃了
        food.if_exist(exist,snakebody)       #根据食物状态判断是否随机生成新的食物
        #print(‘foodbody:‘,food._food_pos)
        #print(‘snakebodyhead:‘,snake.snake_body[snake.head])

        if snake.isdead():                   #判断贪吃蛇是否死亡
            #pygame.mixer.music.stop()
            #print(‘dead:‘,snakebody)
            print(‘dead‘,DIRECTION)
            sounddead.play()
            terminate(screen)

        else:
            pass         

  我在循环开始的地方添加了“print(‘while start‘)",在循环结束的地方,也就是pygame.display.update()之后添加了“print("update")”;通过这两个语句来表示一次while循环的过程,根据这种方法可以分析出贪吃蛇死亡的那次while循环中发生了什么。然后在监测键盘输入的代码之后添加“print(‘DIRECTION‘,DIRECTION)”,以此来打印出监测到的方向DIRECTION的值;并在terminate()之前打印出贪吃蛇死亡前的移动方向做确认。下面是贪吃蛇非正常死亡时命令行显示的结果:

  

  我在第一次看到这个结果时,感到十分纳闷,为什么print("DIRECTION",DIRECTION)这个语句会被执行两次,这明明是在一次while循环里面,真正百思不得其解。后面我看到了在这个语句外面还有一个while循环(之前的暂停功能while循环是写在监听键盘代码的外面),于是就把暂停功能的while循环改了,放到了监听方向的代码之后(改后的代码就是上面贴出的代码);但是,然并卵,还是会出现这种问题,于是我继续把这一段的代码看了一遍,寻找循环语句。

  然后我突然就看到了"for event in pygame.event.get():"这句代码,再去看了一下pygame.event.get()方法的详细资料,发现原来问题还真出现在这里。(pygame.event资料链接:http://www.pygame.org/docs/ref/event.html)  

  通过上面的资料信息可以了解到pygame.event.get()方法返回的是Eventlist,是一个事件序列(多个事件的集合),那么当在键盘按下不同按键的时间间隔足够短,pygame.event.get()方法就会在一次while主循环中获取到多个事件,for event in pygame.event.get(): 语句就会执行不止一次,这样就会出现上面一次while主循环中打印两次DIRECTION的结果。这样一来,如果在游戏初始贪吃蛇移动方向DIRECTION是RIGHT,那么先按下上UP后再按下LEFT,就会使“elif event.key == K_RIGHT and DIRECTION != ‘LEFT‘”中的"and DIRECTION != ‘LEFT‘"语句的作用失效,就会出现贪吃蛇“逆行”的情况导致其头部坐标与身体其他部位的坐标出现重合,进而死亡。

  这个bug的解决办法就是换.get()方法改用.poll()方法,因为.poll()方法在一次while主循环中只会监听并返回一个事件,不会出现先UP后LEFT的情况。

  • BUG 2  在普通模式我设置了一个传送门,测试时发现贪吃蛇进入传送门后如果马上按方向键贪吃蛇会“无视”传送门去往其他方向,传送门“失效”。针对这个BUG,我直接限制贪吃蛇的“行动能力”,即在贪吃蛇进入传送门的时候通过"pygame.event.get_blocked(KEYDOWN)“关闭键盘监听,使玩家无法在此时控制贪吃蛇方向;同时在贪吃蛇彻底进入下一关之前使用”pygame.event.get_allowed(KEYDOWN)“恢复玩家对贪吃蛇移动方向的控制。

  GATEWAY_FLAG标志位为1表示贪吃蛇触发了传送门,正在进入

  while True:
    #for _ in range(8):

        #print(‘while start‘)

        #进入传送门的过程限制移动
        if GATEWAY_FLAG == 1:
            pygame.event.set_blocked(KEYDOWN)

        #获取事件
        event = pygame.event.poll()
        #print(‘get event‘)
        #print(‘direction‘,DIRECTION) 

        #判定事件
        if event.type == QUIT:
            pygame.quit()
            exit()
        #控制贪吃蛇移动方向
        elif event.type == KEYDOWN:
            if event.key == K_LEFT and DIRECTION != ‘RIGHT‘:
                DIRECTION = ‘LEFT‘
            elif event.key == K_RIGHT and DIRECTION != ‘LEFT‘:
                DIRECTION = ‘RIGHT‘
                #print(DIRECTION)
            elif event.key == K_UP and DIRECTION != ‘DOWN‘:
                DIRECTION = ‘UP‘
            elif event.key == K_DOWN and DIRECTION != ‘UP‘:
                DIRECTION = ‘DOWN‘
                #print(DIRECTION)

  GATEWAY_FLAG标志位为2表示贪吃蛇已经彻底进入传送门,即将前第三关

        #判定是否进行传送
        if GATEWAY_FLAG == 2:
            #恢复贪吃蛇移动锁定
            pygame.event.set_allowed(KEYDOWN)
            GATEWAY_FLAG = 0
  • 这个不算程序中的BUG,而是打包贪吃蛇游戏时的一次惨痛经历(解决这个的时候真的要哭了)。我使用的打包工具是pyinstaller,使用pip install pyinstaller指令安装。(pyinstaller的安装教程网上很多,这边就不具体介绍了)我打包的环境是WIN10.。打包的时候要注意以下几点(根据自己的打包过程总结):
  1. 打包后要把程序中用到的图片、音频文件拷贝到exe程序所在文件夹中(如果在程序中写的路径是当前工作路径的话),程序中写的文件路径要对应为exe程序的路径;否则会出现"failed to execute script"的错误。
  2. 要确保你的电脑有连接音频设备,有安装音频驱动,否则程序同样无法正常运行(这个教训很惨痛,我后面发现是因为没接喇叭导致的,真的巨蛋疼)
  3. 背景音乐无法打包。我在打包贪吃蛇的时候,发现背景音乐始终无法顺利打包(始终会报错),各种方法都尝试了一遍,最后才发现是预初始化语句”pygame.mixer.pre_init()“出的幺蛾子,要使用”pygame.mixer.init()“进行初始化才能顺利打包背景音乐。

  贪吃蛇篇章,就此结束。

原文地址:https://www.cnblogs.com/3fman/p/9363097.html

时间: 2024-10-12 10:11:20

自制贪吃蛇游戏中的几个“大坑”的相关文章

JS贪吃蛇游戏

<!DOCTYPE html><html> <head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>JS贪吃蛇游戏</title>    <style>    * {        margin: 0;    

用Java开发贪吃蛇游戏

贪吃蛇游戏的设计步骤: Part 1: 设计游戏图纸 画出900*700的白色窗口 在窗口上添加画布 在画布上添加标题 在画布上添加黑色游戏区 Part 2: 放置静态的蛇:一个头.两个身体 加上开始提示:按空格键开始游戏 让蛇动起来:监听Timer事件,平移数据 实现游戏暂停 实现转向功能 Part 3: 添加食物 吃掉食物 添加死亡条件 实现“重新开始”功能 添加分数和长度 游戏图纸如下: 蛇及游戏框的素材如下:                              Snake主类: 1

Qt版贪吃蛇游戏

Qt版贪吃蛇游戏 转载请标明出处:牟尼的专栏 http://blog.csdn.net/u012027907 最近在学习Qt,用了一个多月的时间掌握了Qt中最基本的知识,也完成了<Qt版音乐播放器>.<Qt版贪吃蛇游戏>.<Qt版双人俄罗斯方块>以及<Qt版科学计算器>等,之前在VC下写过这些程序,所以在Qt下只是改变了显示等语句,我写过<C++版贪吃蛇游戏>.<VC版贪吃蛇游戏>,当时将与显示等无关的东西封装起来,在Qt下直接用,只

贪吃蛇游戏

学习C语言也差不多学完了想做一个游戏,而贪吃蛇和俄罗斯方块都是非常经典的游戏,在网上也找到了许多相关的参考资料,便动手做了,这个游戏室控制台版的 游戏流程图 函数模块 函数名 函数功能 CursorPosition 光标定位函数 CreateSnake 蛇初始化函数 ShowWall 显示墙体 UpdateSnake 更新界面上的蛇体.分数.等级.食物 CollisionDetection 判断蛇是否咬到自己 RandFood 随机产生食物 Move 控制方向 程序代码 #include <st

贪吃蛇 游戏

结队作业  结队人 郑丁鹏(负责 (二)流程图和(四)游戏测试 ) 我负责 (二)游戏需求分析 与(三)游戏代码 贪吃蛇游戏程序设计 一.基本内容描述 运用java技术开发出贪吃蛇游戏,这个程序是用一个小矩形表示蛇的一节身体,身体每长一节,增加一个矩形块.移动时必须从蛇头开始,也就是蛇尾不能改作蛇头.当游戏者按了方向键后,蛇头朝着指定的方向移动,一步移动一节身体.图形的实现是从蛇头的新位置开始画出蛇.用户可以用上下左右键控制蛇头的方向,用空格键暂停或继续,非常简单! 可以实现如下功能: 贪吃蛇游

基于控制台实现贪吃蛇游戏

1).引言 学习编程,我个人觉得最好的办法就是根据自己的水平不断的给自己设定一个小目标.而这个小目标就是一个有意思的项目,通过完成这个项目,对自己的成果(也包括失败的)进行分析总结,从中提炼出对应的技术并分享出来,不断的往复,如此,为的就是让我们永远保持编写程序的兴趣和热情,完了,还提高我们的技术.而本文就是总结自己的一个小目标(基于控制台实现的贪吃蛇游戏而写的总结) 2).技术实现 大家小时候一定玩过贪吃蛇的游戏.贪吃蛇游戏的控制过程其实也不复杂.简单的可以概括为以下4个部分. 1.1  .组

做一个简单的贪吃蛇游戏

这是一个贪吃蛇游戏,你可以忽略他的外表,好了,先上html代码 <style type="text/css"> * {margin: 0;padding: 0;} #container {width: 1000px;height: 550px;border: 1px solid #000;margin: 0 auto;} #container #ground {width: 1000px;height: 500px;background-color:#eeeeee;posi

Java控制台下的贪吃蛇游戏

实现贪吃蛇游戏的思路:   class Node(i,j)  //表示坐标 class Worm(List<Node> nodes)        //   行数:10行//用LinkedList存储蛇的坐标点.当前进是用addFirst(Node node)方法添加一个一个坐标点(可以通过getFirst()得到上一个坐标-1得出):然后再删除尾节点.如果碰到食物则不删除尾节点. // 列数:32列 step()//往前走一步 step(int dir)//根据方向往前走一步 class W

使用Love2D引擎开发贪吃蛇游戏

今天来介绍博主最近捣腾的一个小游戏[贪吃蛇],贪吃蛇这个游戏相信大家都不会感到陌生吧.今天博主将通过Love2D这款游戏引擎来为大家实现一个简单的贪吃蛇游戏,在本篇文章当中我们将会涉及到贪吃蛇的基本算法.Lua语言编程等基本的内容,希望能够对大家开发类似的游戏提供借鉴和思考,文章中如有不足之处,还希望大家能够谅解,因为博主的游戏开发基本就是这样慢慢摸索着学习,所以难免会有不足的地方. 游戏算法 我们首先来看看贪吃蛇是怎么移动的? 通过这四张图的演示,我们可以发现这样一个规律: 蛇的移动其实是将蛇