自制贪吃蛇游戏中的几个“大坑”(代码片段)

3fman 3fman     2022-12-17     540

关键词:

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

    • 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()“进行初始化才能顺利打包背景音乐。

      贪吃蛇篇章,就此结束。

    react-redux自制简易贪吃蛇小游戏(代码片段)

    初始化用脚手架新建一个react项目:npxcreate-react-appsnake-demo关于安装和创建、启动,可以看我的这篇文章:React入门:基本环境搭建首先画一个框,当作边界,再初始化贪吃蛇,就像这样:左上角两个小黑... 查看详情

    react-redux自制简易贪吃蛇小游戏(代码片段)

    初始化用脚手架新建一个react项目:npxcreate-react-appsnake-demo关于安装和创建、启动,可以看我的这篇文章:React入门:基本环境搭建首先画一个框,当作边界,再初始化贪吃蛇,就像这样:左上角两个小黑... 查看详情

    一条贪吃蛇的使命——零基础入门贪吃蛇游戏(代码片段)

    零基础入门贪吃蛇游戏贪吃蛇是一款最常见、最经典、最受欢迎的小游戏之一。本篇文章带你零基础实现贪吃蛇游戏,一条蛇的使命从这里开始。1、游戏描述????贪吃蛇是一款非常经典的休闲类游戏。在一块固定大小的区域内,... 查看详情

    贪吃蛇小游戏程序(c语言)(代码片段)

    这次来分享一个我写的贪吃蛇小游戏程序(C语言)最近暑假无事开始用C语言写一些小游戏小游戏程序,这个贪吃蛇当然是经典中的经典,所以先开始写。文件引用#include<redio.h>//输入输出#include<time.h>//用... 查看详情

    一条贪吃蛇的使命——零基础入门贪吃蛇游戏(附演示地址)(代码片段)

    零基础入门贪吃蛇游戏贪吃蛇是一款最常见、最经典、最受欢迎的小游戏之一。本篇文章带你零基础实现贪吃蛇游戏,一条蛇的使命从这里开始。演示地址:贪吃蛇演示,可能会提示危险操作,请忽略,放心访问。1、游戏描述??... 查看详情

    gui简单实战——贪吃蛇(代码片段)

    将前面学到的GUI基础知识完成实战,完成一个简单的贪吃蛇项目项目功能用键盘上下左右实现贪吃蛇的自动移动贪吃蛇吃到食物后,长度加一,分数加一贪吃蛇吃到自己的身体,则游戏结束按空格键实现游戏的暂停和继续效果截... 查看详情

    贪吃蛇(c语言实现)(代码片段)

    ...中没有打印相关的按键说明,这里先逐一列出,贪吃蛇游戏按键说明:按方向键上下左右,可以实现蛇移动方向的改变。短时间长按 查看详情

    py小游戏系列贪吃蛇,儿时的回忆(代码片段)

    ...写有趣小玩意的老诗。老规矩,先上效果图这是一个贪吃蛇的小游戏。我们8090后这一代人肯定会碰到过。蛇会随着吃到的食物变得越来越长。然后碰到墙壁或者碰到自己的身体都会输掉游戏。这个是简陋版的贪吃蛇,但... 查看详情

    py小游戏系列贪吃蛇,儿时的回忆(代码片段)

    ...写有趣小玩意的老诗。老规矩,先上效果图这是一个贪吃蛇的小游戏。我们8090后这一代人肯定会碰到过。蛇会随着吃到的食物变得越来越长。然后碰到墙壁或者碰到自己的身体都会输掉游戏。这个是简陋版的贪吃蛇,但... 查看详情

    c语言实现《贪吃蛇》小游戏,代码分享+思路注释(代码片段)

    贪吃蛇(也叫做贪食蛇)游戏是一款休闲益智类游戏,有PC和手机等多平台版本。既简单又耐玩。该游戏通过控制蛇头方向吃蛋,从而使得蛇变得越来越长。 [1]贪吃蛇游戏最初为单机模式,后续又陆续推出团... 查看详情

    游戏基于matlabgui贪吃蛇游戏含matlab源码1146期(代码片段)

    一、简介基于matlabGUI贪吃蛇游戏二、源代码functionvarargout=Snake(varargin)%SNAKEM-fileforSnake.fig%SNAKE,byitself,createsanewSNAKEorraisestheexisting%singleton*.%%H=SNAKEreturnsthehandletoanewSNAKEorthehandle 查看详情

    贪吃蛇小游戏(代码片段)

    MOVE__BOX部分:代码如下#include<iostream>#include<Windows.h>#include<conio.h>usingnamespacestd;voidPutPlace(intx,inty);//设定输出位置voidcolor(inta);//设定输出颜色//设定输出位置voidPutPlace(intx,inty)COORDB 查看详情

    面向对象案例——贪吃蛇游戏(代码片段)

    ...近一个星期没更博了,今天来写一个经典的游戏案例——贪吃蛇。在这个简单的案例里可以体会javaScript面向对象开发相关模式,学习使用面向对象的方式分析问题。1.功能实现1.1搭建页面:放一个容器盛放游戏场景div#map,设置... 查看详情

    c++入门——实现贪吃蛇游戏(代码片段)

    参考《C和C++游戏趣味编程》贪吃蛇游戏键盘控制小蛇上、下、左、右移动,迟到食物后长度加1;蛇头碰到自身或窗口边缘,游戏失败程序框架#include<graphics.h>#include<conio.h>#include<stdio.h>//全局变量定... 查看详情

    游戏基于matlabgui贪吃蛇游戏(难度地图音乐)含matlab源码1160期(代码片段)

    一、简介基于matlabGUI贪吃蛇游戏(难度、地图、音乐)二、源代码functionsnake(cmd)%SNAKEGraphicalUserInterfaceforplaying"NokiaClassicGame"Snake.%%TheGame:%Makethesnakegrowlongerbydirectingittothefood.%Extrabonuspointsareg 查看详情

    贪吃蛇二代——穿墙版(c语言实现)(代码片段)

    文章目录游戏说明游戏效果展示游戏代码游戏代码详解游戏框架构建初始化界面隐藏光标光标跳转颜色设置初始化蛇随机生成食物打印蛇与覆盖蛇移动蛇游戏主体逻辑函数执行按键判断得分与结束从文件读取最高分更新最高分到... 查看详情

    python:贪吃蛇小游戏(代码片段)

    #pygame游戏库,sys操控python运行的环境importpygame,sys,random#这个模块包含所有pygame所使用的常亮frompygame.localsimport*#1,定义颜色变量#0-2550黑色255白色redColor=pygame.Color(255,0,0)#背景为黑色blackColor=pygame.Color(0,0,0)# 查看详情

    javascript实现贪吃蛇小游戏(代码片段)

    JavaScript实现贪吃蛇小游戏功能概述本程序实现了如下功能:贪吃蛇的基本功能统计得分开始与暂停选择难度等级设置快捷键5.1通过ijkl,wsad也能实现方向的切换5.2通过“P”表示暂停,“C”表示开始或继续,"R&#... 查看详情