注意事项

本文需使用pygame模块,有关如何安装pygame模块,请参照我之前的文章:

为anaconda3安装pygame模块

先来段演示结果:
9gb4j-y5evk.gif

游戏编写思路

游戏入口与结束函数

注册键盘热键:上下左右

蛇的死亡:撞墙和碰到自己

食物的随机生成

那么让我们来看下各个步骤:

游戏结束函数

def gameover():
    pygame.quit()#用于退出pygame模块
    sys.exit()#用于退出程序

在入口函数中,我们需要初始化游戏界面,定义蛇的身体,方向和开始循环

入口函数

def main():
    pygame.init()#初始化pygame
    fpsClock=pygame.time.Clock()#创建时钟,屏幕刷新函数
    screen=pygame.display.set_mode((640,480))#创建一个720x560的窗口
    pygame.display.set_caption("python贪吃蛇")#将窗口命名为python贪吃蛇

定义蛇的身体、位置和方向,以及食物的初始位置

    #定义蛇的初始位置
    snake=[100,100]
    #初始为1段身体,每段间隔20个单位,以列表形式保存
    snakebody=[[100,100]]
    #定义蛇的移动方向,向300x300的方向移动
    snaket=[300,300]
    #标记方块,初始为1,吃掉后为0
    cube=1
    #初始化人为控制的按键方向,默认为向右
    direction='right'
    #人为控制的方向变量
    cdirection=direction

游戏循环开始

注册热键:

while True:
        for event in pygame.event.get(): #队列中获取事件
            if event.type==pygame.QUIT:#若点击右上角的x,则退出
                gameover()
            elif event.type==pygame.KEYDOWN:#注册热键,按键按下
                if event.key==pygame.K_d:#按下d键,以下等同
                    cdirection='right'
                #多个if判断,不用elif,防冲突
                if event.key==pygame.K_a:
                    cdirection='left'
                if event.key==pygame.K_w:
                    cdirection='up'
                if event.key==pygame.K_s:
                    cdirection='down'

这里注册了WASD四个热键,用于控制蛇的移动方向

确定蛇的方向是否相反:

        if cdirection =='left' and not direction =='right':
            direction = cdirection
        if cdirection =='right' and not direction =='left':
            direction = cdirection
        if cdirection =='up' and not direction =='down':
            direction = cdirection
        if cdirection =='down' and not direction =='up':
            direction = cdirection

移动蛇头:

        #根据方向移动蛇头,蛇头位置第一个位置加20
        if direction =='right':
            snake[0] +=20
        if direction =='left':
            snake[0] -=20
        if direction =='up':
            snake[1] -=20
        if direction =='down':
            snake[1] +=20

增加蛇的身体长度及食物判断:

        #增加蛇的长度
        snakebody.insert(0,list(snake))#在尾部插入一段身体
        #贪吃蛇和目标食物相互重叠的情况下(吃到食物情况下)
        if snake[0]==snaket[0] and snake[1]==snaket[1]:
            cube=0
        else:
            snakebody.pop()
        #随机生成食物判断
        if cube==0:
            x=random.randrange(1,32)
            y=random.randrange(1,24)
            snaket=[int(x*20),int(y*20)]#防止随机生成的数值在蛇中间无法吃到
            cube=1

绘制图形

这里我们先定义蛇,食物和界面的颜色

#各种颜色

color1=pygame.Color(255,2,2)#吃的方块的颜色
color2=pygame.Color(0,0,0)#背景颜色
color3=pygame.Color(255,100,100)#蛇的颜色

开始绘制图形:

        #开始填充颜色
        screen.fill(color2)
        #开始绘图
        for draws in snakebody:
            #第一个参数指定一个编辑区,在这个区域内绘制
            #第二个参数颜色
            #第三个参数:rect:返回一个矩形(x和y),(宽,高)
            pygame.draw.rect(screen,color3,pygame.Rect(draws[0],draws[1],20,20))
            pygame.draw.rect(screen,color1,pygame.Rect(snaket[0],snaket[1], 20, 20))
            
        pygame.display.flip()#让最近绘制的屏幕可见

游戏结束判断

        #判断游戏结束
        #触碰边境墙死亡
        if snake[0] > 640 or snake[0] < 0:
            gameover()
        elif snake[1] > 480 or snake[1] < 0:
            gameover()
        #撞到身体死亡
        for snakebodys in snakebody[1:]:
            if snake[0]==snakebodys[0] and snake[1]==snakebodys[1]:
                gameover()

这样,一个仅100多行代码的贪吃蛇游戏就基本完成了。

完整代码

import pygame
import sys
import random

#游戏结束函数
def gameover():
    pygame.quit()#用于退出pygame模块
    sys.exit()#用于退出程序

#各种颜色

color1=pygame.Color(255,2,2)#吃的方块的颜色
color2=pygame.Color(0,0,0)#背景颜色
color3=pygame.Color(255,100,100)#蛇的颜色
    
#入口函数
def main():
    pygame.init()#初始化pygame
    fpsClock=pygame.time.Clock()
    screen=pygame.display.set_mode((640,480))#创建一个720x560的窗口
    pygame.display.set_caption("python贪吃蛇")#将窗口命名为python贪吃蛇
    
    #定义蛇的初始位置
    snake=[100,100]
    #初始为1段身体,每段间隔20个单位,以列表形式保存
    snakebody=[[100,100]]
    #定义蛇的移动方向,向300x300的方向移动
    snaket=[300,300]
    #标记方块,初始为1,吃掉后为0
    cube=1
    #初始化人为控制的按键方向,默认为向右
    direction='right'
    #人为控制的方向变量
    cdirection=direction

    #开始游戏循环
    while True:
        for event in pygame.event.get(): #队列中获取事件
            if event.type==pygame.QUIT:#若点击右上角的x,则退出
                gameover()
            elif event.type==pygame.KEYDOWN:#注册热键,按键按下
                if event.key==pygame.K_d:#按下d键,以下等同
                    cdirection='right'
                #多个if判断,不用elif,防冲突
                if event.key==pygame.K_a:
                    cdirection='left'
                if event.key==pygame.K_w:
                    cdirection='up'
                if event.key==pygame.K_s:
                    cdirection='down'
                    
        #确定蛇的方向
        if cdirection =='left' and not direction =='right':
            direction = cdirection
        if cdirection =='right' and not direction =='left':
            direction = cdirection
        if cdirection =='up' and not direction =='down':
            direction = cdirection
        if cdirection =='down' and not direction =='up':
            direction = cdirection
        
        
        #根据方向移动蛇头,蛇头位置第一个位置加20
        if direction =='right':
            snake[0] +=20
        if direction =='left':
            snake[0] -=20
        if direction =='up':
            snake[1] -=20
        if direction =='down':
            snake[1] +=20
        
        #增加蛇的长度
        snakebody.insert(0,list(snake))#在尾部插入一段身体
        #贪吃蛇和目标食物相互重叠的情况下(吃到食物情况下)
        if snake[0]==snaket[0] and snake[1]==snaket[1]:
            cube=0
        else:
            snakebody.pop()
            
        if cube==0:
            x=random.randrange(1,32)
            y=random.randrange(1,24)
            snaket=[int(x*20),int(y*20)]#防止随机生成的数值在蛇中间无法吃到
            cube=1
        
        #开始填充颜色
        screen.fill(color2)
        #开始绘图
        for draws in snakebody:
            #第一个参数指定一个编辑区,在这个区域内绘制
            #第二个参数颜色
            #第三个参数:rect:返回一个矩形(x和y),(宽,高)
            pygame.draw.rect(screen,color3,pygame.Rect(draws[0],draws[1],20,20))
            pygame.draw.rect(screen,color1,pygame.Rect(snaket[0],snaket[1], 20, 20))
            
        pygame.display.flip()#让最近绘制的屏幕可见
        
        #判断游戏结束
        #触碰边境墙死亡
        if snake[0] > 640 or snake[0] < 0:
            gameover()
        elif snake[1] > 480 or snake[1] < 0:
            gameover()
        #撞到身体死亡
        for snakebodys in snakebody[1:]:
            if snake[0]==snakebodys[0] and snake[1]==snakebodys[1]:
                gameover()
                

        
        #控制刷新频率,数值越大,刷新速度越快,蛇移动的速度也越快
        fpsClock.tick(4)
        
        
#脚本函数
if __name__ =='__main__':
    main()

结论

通过以上内容,我将一个贪吃蛇游戏的基本功能都实现了,但是,这样的代码其实并不是很美观,下一步,我打算用类和继承重构这个小游戏代码。并且,从上述代码可以看出,在游戏结束判断上,游戏结束的时候是直接调用结束函数,下一步,我将添加游戏结束提示“game over”,而不是直接退出程序,并且设置一个开始引导界面。这也是我将标题命名为贪吃蛇(一)的原因。
当然,具体什么时候重构贪吃蛇(二),我也不知道,因为人的本质就是懒(笑)。