python实现贪吃蛇游戏

news2024/12/24 21:09:32

文章目录

        • 1、项目说明
        • 2、项目预览
        • 3、开发必备
        • 4、贪吃蛇代码实现
          • 4.1、窗口和基本参数实现
          • 4.2、绘制背景
          • 4.3、绘制墙壁
          • 4.4、绘制贪吃蛇
          • 4.5、绘制食物
          • 4.6、实现长度信息显示
          • 4.7、定义游戏暂停界面
          • 4.8、定义贪吃蛇死亡界面
          • 4.9、实现贪吃蛇碰撞效果
          • 4.10、实现添加食物功能
          • 4.11、实现贪吃蛇身体增长功能
          • 4.12、实现贪吃蛇吃食物功能
          • 4.12、贪吃蛇死亡功能
          • 4.13、实现键盘控制游戏
          • 4.14、更新贪吃蛇位置功能
          • 4.15、更新游戏画面和处理用户输入功能
        • 5、结束

1、项目说明

介绍

贪吃蛇是我们小时候的一款经典游戏,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Python(蛇)玩Snake(贪吃蛇),那再合适不过了。

需求分析

我们先来回顾下贪吃蛇中的游戏元素及游戏规则:

  1. 需要有贪吃蛇、有食物
  2. 需要能控制贪吃蛇来上下移动获取食物
  3. 贪吃蛇在吃取食物后,自身长度增加,同时食物消失并随机生成新的食物
  4. 如果贪吃蛇触碰到四周墙壁或是触碰到自己身体时,则游戏结束
2、项目预览

image-20231219171058611

3、开发必备

游戏开发运行环境

  1. python3.7以上
  2. 开发工具PyCharm
  3. Python内置模块:random
  4. 第三方模块:pygame
4、贪吃蛇代码实现
4.1、窗口和基本参数实现

分析

我们首先需要初始化一些参数:游戏界面大小、蛇和食物的参数以及一些游戏边界和障碍的设置等等

  1. 初始化 Pygame 模块,让游戏程序能够使用 Pygame 提供的功能;
  2. 设置游戏窗口的大小;
  3. 定义两个字体对象,分别用于绘制不同大小的文字;
  4. 定义了一个方向列表,包含了贪吃蛇可能移动的四个方向;
  5. 定义了 X 和 Y 的坐标列表,方便后续使用;
  6. 定义了几种不同的食物颜色,用于给不同等级的食物染色;
  7. 定义了障碍物(墙)的位置和尺寸以及食物的初始位置和尺寸;
  8. 设置蛇的一些参数,如速度、长度、宽度和高度等;
  9. 设置游戏的等级和初始等待时间;
  10. 设置游戏窗口的标题和一些初始化的变量。

代码实现

import pygame

if __name__ == "__main__":
    # 初始化pygame
    pygame.init()
    
    # 游戏界面大小
    GAME_SIZE = [900,900]
    SIZE = [GAME_SIZE[0],GAME_SIZE[1]+100]
    
    # 字体设置
    FONT_S = pygame.font.SysFont('Times', 50)
    FONT_M = pygame.font.SysFont('Times', 90)
    
    # 方向列表
    DIRECTION = ['up','right','down','left']
    
    # X 和 Y 坐标列表
    X_LIST = [x for x in range(GAME_SIZE[0])]
    Y_LIST = [y for y in range(GAME_SIZE[1])]
    
    # 食物颜色
    FOOD_COLORS = ((46,139,87),(199,21,133),(25,25,112),(255,215,0))

    # 墙
    wall_list = [[100,200],[600,500],[350,200],[500,800]]
    WALL_WIDTH,WALL_HEIGHT = 30,30

    # 食物
    food_list = [(150,200,1),(300,500,1),(740,542,1),(300,600,1),(700,600,1)]
    FOOD_WIDTH,FOOD_HEIGHT = 14,14
    
    # 创建游戏窗口 900*1000
    screen = pygame.display.set_mode(SIZE)
    
    # 蛇的参数
    snake_list = [[100+12*4,100],[100+12*3,100],[100+12*2,100],[100+12*1,100],[100,100]]
    SNAKE_WIDTH,SNAKE_HEIGHT = 12,12
    snake_v = 0
    count_time = 0

    # 等级
    frame = 0.05
    level = 1
    
    # 主循环
    running = True
    pause = False
    dead = False
    head = 'right'
4.2、绘制背景

分析

定义一个名为 draw_background() 的函数,它用来绘制游戏的背景。

具体的绘制过程如下:

  1. screen.fill(COLORS['white']) 使用白色填充背景屏幕,将屏幕背景设置为白色。
  2. pygame.draw.rect(screen,COLORS['black'],(-100,GAME_SIZE[1],3000,200),0) 绘制一个长方形作为地面。该矩形的位置 (x, y)(-100, GAME_SIZE[1]),宽度为 3000,高度为 200。矩形的颜色是 COLORS 字典中的 black

通过调用 draw_background() 函数,可以在游戏屏幕上绘制出白色的背景以及一个黑色的长方形作为地面

代码

def draw_background():
    # white background
    screen.fill(COLORS['white'])
    pygame.draw.rect(screen,COLORS['black'],(-100,GAME_SIZE[1],3000,200),0)
4.3、绘制墙壁

分析

定义一个名为 draw_wall() 的函数,它用来绘制游戏中的墙壁。

具体的绘制过程如下:

  1. 使用 for 循环遍历墙壁列表 wall_list 中的每个元素,每个元素表示一个墙壁的位置。
  2. 对于每个墙壁位置,调用 pygame.draw.rect() 函数绘制一个矩形,位置 (x, y)(xy[0]-WALL_WIDTH/2, xy[1]-WALL_WIDTH/2),宽度为 WALL_WIDTH,高度为 WALL_HEIGHT。矩形的颜色是 COLORS 字典中的 darkgray

通过调用 draw_wall() 函数,可以在游戏屏幕上绘制出墙壁。每个墙壁由一个矩形组成,矩形的位置和大小均在调用时指定。注意,墙壁的位置需要减去一半的墙壁宽度和高度,以便将矩形的中心对齐到墙壁位置上。

代码

def draw_wall():
    for xy in wall_list:
        pygame.draw.rect(screen,COLORS['darkgray'],(xy[0]-WALL_WIDTH/2,xy[1]-WALL_WIDTH/2,WALL_WIDTH,WALL_HEIGHT),0)
4.4、绘制贪吃蛇

分析

定义一个名为 draw_snake() 的函数,它用来绘制游戏中的蛇。

具体的绘制过程如下:

  1. 使用 snake_list 列表中的第一个元素作为蛇头,调用 pygame.draw.circle() 函数绘制一个圆作为蛇头。圆心的位置 (x, y)(head[0], head[1]),半径为 SNAKE_WIDTH/2。圆的颜色是 COLORS 字典中的 darkred
  2. 对于蛇身上的其他部分(不包括蛇头),使用 for 循环遍历 snake_list 中除了第一个元素以外的其他元素。对于每个元素,调用 pygame.draw.rect() 函数绘制一个矩形,位置 (x, y)(xy[0]-SNAKE_WIDTH/2, xy[1]-SNAKE_WIDTH/2),宽度为 SNAKE_WIDTH,高度为 SNAKE_HEIGHT,边框宽度为 2。矩形的颜色与圆的颜色相同。

通过调用 draw_snake() 函数,可以在游戏屏幕上绘制出蛇。蛇头使用一个圆表示,蛇身使用一系列矩形拼接而成,每个矩形的位置和大小均在调用时指定。注意,蛇头和蛇身分别使用了不同的绘制方式,因为它们形状不同。

代码

def draw_snake():
    head = snake_list[0]
    pygame.draw.circle(screen,COLORS['darkred'],(head[0],head[1]),int(SNAKE_WIDTH/2),0)
    for xy in snake_list[1:]:
        pygame.draw.rect(screen,COLORS['darkred'],(xy[0]-SNAKE_WIDTH/2,xy[1]-SNAKE_WIDTH/2,SNAKE_WIDTH,SNAKE_HEIGHT),2)
4.5、绘制食物

分析

定义一个名为 draw_food() 的函数,它用来绘制食物物品。

具体的绘制过程如下:

  1. 使用 for 循环遍历食物列表 food_list 中的每个元素,每个元素表示一个食物的位置和类型。
  2. 对于每个食物位置,调用 pygame.draw.rect() 函数绘制一个矩形,位置 (x, y)(xyz[0]-FOOD_WIDTH/2, xyz[1]-FOOD_WIDTH/2),宽度为 FOOD_WIDTH,高度为 FOOD_HEIGHT。矩形的颜色是 FOOD_COLORS 列表中根据食物类型 xyz[2] 所对应的颜色值。

通过调用 draw_food() 函数,可以在游戏屏幕上绘制出各种类型的食物。每个食物由一个矩形组成,矩形的位置和大小均在调用时指定。注意,食物的位置需要减去一半的食物宽度和高度,以便将矩形的中心对齐到食物位置上。

代码

# 绘制食物
def draw_food():
    # 遍历食物列表
    for xyz in food_list:
        # 获取食物位置和类型,绘制食物矩形
        pygame.draw.rect(screen, FOOD_COLORS[xyz[2]-1], (xyz[0] - FOOD_WIDTH/2, xyz[1] - FOOD_WIDTH/2, FOOD_WIDTH, FOOD_HEIGHT), 0)
4.6、实现长度信息显示

分析

定义一个名为 draw_context() 的函数,它用来绘制游戏的上下文信息。

具体的绘制过程如下:

  1. 创建一个文本对象 txt,文本内容是 "Snake length: " 连接上蛇身长度 len(snake_list)-1。使用 FONT_M 字体来渲染文本,文本颜色是 COLORS 字典中的 lightblue
  2. 计算文本的位置 (x, y),其中 x 的初始值为 10y 的初始值为 GAME_SIZE[1]+(int((SIZE[1]-GAME_SIZE[1])/2))。接下来,将 y 的值减去文本字体尺寸的一半,以实现垂直居中。
  3. 使用 screen.blit() 函数将文本对象绘制到屏幕上,位置为 (x, y)

通过调用 draw_context() 函数,可以在游戏屏幕上绘制出游戏的上下文信息,包括蛇的长度

代码

# 绘制游戏上下文信息
def draw_context():
    # 创建文本对象,包括蛇的长度信息
    txt = FONT_M.render('Snake length: '+str(len(snake_list)-1),True,COLORS['lightblue'])
    # 计算文本位置
    x,y = 10,GAME_SIZE[1]+(int((SIZE[1]-GAME_SIZE[1])/2))
    y = int(y-FONT_M.size('Count')[1]/2)
    # 绘制文本
    screen.blit(txt,(x,y))
4.7、定义游戏暂停界面

分析

定义一个名为 draw_pause() 的函数,它用于在游戏暂停时绘制暂停界面。

具体的绘制过程如下:

  1. 创建一个透明表面 s,大小与 SIZE 相同,并填充为带有半透明的白色 (255,255,255,220)
  2. 使用 screen.blit() 函数将表面 s 绘制到屏幕上的位置 (0, 0),实现背景的半透明效果。
  3. 创建一个文本对象 txt,文本内容为 “PAUSE”,使用 FONT_M 字体渲染文本,文本颜色为 COLORS 字典中的 darkgray
  4. 计算文本的位置 (x, y),其中 x 的初始值为 SIZE[0]/2y 的初始值为 SIZE[1]/2。然后,将 xy 的值减去文本字体尺寸的一半,以实现水平和垂直居中。
  5. 使用 screen.blit() 函数将文本对象绘制到屏幕上的位置 (x, y)

通过调用 draw_pause() 函数,可以在游戏屏幕上绘制暂停界面。呈现为一个半透明的背景,并显示 “PAUSE” 文本在中间位置。注意,需要使用透明度为 220 的色彩值来填充表面,以实现半透明效果。

代码

# 绘制暂停界面
def draw_pause():
    # 创建一个带有半透明的透明表面
    s = pygame.Surface(SIZE, pygame.SRCALPHA)
    s.fill((255,255,255,220))
    # 将透明表面绘制到屏幕上
    screen.blit(s, (0,0))
    # 创建文本对象,显示 "PAUSE"
    txt = FONT_M.render('PAUSE',True,COLORS['darkgray'])
    # 计算文本的位置
    x,y = SIZE[0]/2,SIZE[1]/2
    x,y = int(x-FONT_M.size('PAUSE')[0]/2),int(y-FONT_M.size('PAUSE')[1]/2)
    # 绘制文本
    screen.blit(txt,(x,y))
4.8、定义贪吃蛇死亡界面

分析

定义一个名为 draw_dead() 的函数,用于在游戏中玩家死亡时绘制死亡界面。

具体的绘制过程如下:

  1. 创建一个透明表面 s,大小与 SIZE 相同,并填充为带有半透明的白色 (255,255,255,240)
  2. 使用 screen.blit() 函数将表面 s 绘制到屏幕上的位置 (0, 0),实现背景的半透明效果。
  3. 创建一个文本对象 txt,文本内容为 “YOU DEAD”,使用 FONT_M 字体渲染文本,文本颜色为 COLORS 字典中的 black
  4. 计算文本的位置 (x, y),其中 x 的初始值为 SIZE[0]/2y 的初始值为 SIZE[1]/2。然后,将 xy 的值减去文本字体尺寸的一半,以实现水平和垂直居中。
  5. 使用 screen.blit() 函数将文本对象绘制到屏幕上的位置 (x, y)

通过调用 draw_dead() 函数,可以在游戏屏幕上绘制死亡界面。呈现为一个更加明亮的背景,并显示 “YOU DEAD” 文本在中间位置。注意,需要使用透明度为 240 的色彩值来填充表面,以实现更明显的半透明效果。

代码

# 绘制死亡界面
def draw_dead():
    # 创建一个更明亮的带有半透明的透明表面
    s = pygame.Surface(SIZE, pygame.SRCALPHA)
    s.fill((255,255,255,240))
    # 将透明表面绘制到屏幕上
    screen.blit(s, (0,0))
    # 创建文本对象,显示 "YOU DEAD"
    txt = FONT_M.render('YOU DEAD',True,COLORS['black'])
    # 计算文本的位置
    x,y = SIZE[0]/2,SIZE[1]/2
    x,y = int(x-FONT_M.size('YOU DEAD')[0]/2),int(y-FONT_M.size('YOU DEAD')[1]/2)
    # 绘制文本
    screen.blit(txt,(x,y))
4.9、实现贪吃蛇碰撞效果

分析

定义一个名为 rect_cover(rect1,rect2) 的函数,用于判断两个矩形是否相交。

具体的判断过程如下:

  1. 将每个矩形的四个边界值提取出来,并转换为整数类型。其中,left1 表示矩形 rect1 左边界,right1 表示矩形 rect1 右边界,up1 表示矩形 rect1 上边界,down1 表示矩形 rect1 下边界;同理,left2right2up2down2 分别为矩形 rect2 的四个边界值。
  2. 如果矩形 rect1 和矩形 rect2 相交,则它们的边界值应该满足下面的四种情况之一:
  • rect2 的右边界 right2 小于或等于 rect1 的左边界 left1
  • rect2 的左边界 left2 大于或等于 rect1 的右边界 right1
  • rect2 的下边界 down2 小于或等于 rect1 的上边界 up1
  • rect2 的上边界 up2 大于或等于 rect1 的下边界 down1

如果不满足上述四种情况,则认为它们相交,此时函数返回值为 True;否则,返回值为 False

代码

# 判断两个矩形是否相交
def rect_cover(rect1, rect2):
    # 提取矩形1的边界值
    left1 = int(rect1[0])
    right1 = int(rect1[0] + rect1[2])
    up1 = int(rect1[1])
    down1 = int(rect1[1] + rect1[3])

    # 提取矩形2的边界值
    left2 = int(rect2[0])
    right2 = int(rect2[0] + rect2[2])
    up2 = int(rect2[1])
    down2 = int(rect2[1] + rect2[3])

    # 判断两个矩形是否相交
    if not (right2 <= left1 or left2 >= right1 or down2 <= up1 or up2 >= down1):
        return True

    return False
4.10、实现添加食物功能

分析

定义一个名为 add_food() 的函数,用于向食物列表 food_list 中添加食物。

具体的过程如下:

  1. 进入一个无限循环 while(True)
  2. 在每次循环中,生成一个由随机选择的 X_LIST 中的元素、随机选择的 Y_LIST 中的元素和随机选择的 [1,2,3,4] 中的元素组成的列表 xyz
  3. 检查 xyz 是否存在于墙壁列表 wall_list 中。如果不存在,说明 xyz 没有被墙壁占据,可以作为食物的位置。
  4. xyz 添加到食物列表 food_list 中,并使用 break 语句跳出循环。

通过调用 add_food() 函数,可以在游戏中不断添加新的食物位置。在添加食物之前,会进行检查,确保新位置不与墙壁重叠。

代码

import random

# 向食物列表中添加食物
def add_food():
    while True:
        # 随机选择X、Y和数值
        xyz = [
            random.choice(X_LIST),
            random.choice(Y_LIST),
            random.choice([1, 2, 3, 4])
        ]
        
        # 检查食物位置是否与墙壁重叠
        if xyz not in wall_list:
            # 将食物位置添加到食物列表
            food_list.append(xyz)
            break  # 跳出循环
4.11、实现贪吃蛇身体增长功能

分析

一个名为 add_body() 的函数,用于向蛇的身体列表 snake_list 中添加身体节。

具体的过程如下:

  1. 使用一个循环来控制添加的身体节的数量,循环的次数由参数 length 决定,默认为1。
  2. 在每次循环中,获取蛇身体列表 snake_list 中的倒数第二个和最后一个元素,并分别赋值给 last2last1
  3. 检查最后两个身体节的相对位置:如果它们在垂直方向上相等,则代表这两节身体是竖直排列的;如果它们在水平方向上相等,则代表这两节身体是水平排列的。
  4. 根据身体节的相对位置,确定新的身体节的坐标。如果是竖直排列,根据最后一节的朝向选择向上或向下添加一节;如果是水平排列,根据最后一节的朝向选择向左或向右添加一节。
  5. 将新的身体节坐标添加到蛇的身体列表 snake_list 中。

通过调用 add_body() 函数,可以向蛇的身体列表中添加指定数量的身体节,以延长蛇的长度。

代码

# 向蛇的身体列表中添加身体节
def add_body(length=1):
    for c in range(length):
        # 获取最后两个身体节的坐标
        last2, last1 = snake_list[-2], snake_list[-1]
        
        if last2[0] == last1[0]:  # 如果最后两节身体在垂直方向上相等
            if last2[1] > last1[1]:  # 朝下
                # 向下添加一节身体
                snake_list.append([last1[0], last1[1] - SNAKE_WIDTH])
            else:
                # 向上添加一节身体
                snake_list.append([last1[0], last1[1] + SNAKE_WIDTH])
        else:  # 如果最后两节身体在水平方向上相等
            if last2[0] > last1[0]:  # 朝右
                # 向右添加一节身体
                snake_list.append([last1[0] - SNAKE_WIDTH, last1[1]])
            else:
                # 向左添加一节身体
                snake_list.append([last1[0] + SNAKE_WIDTH, last1[1]])
4.12、实现贪吃蛇吃食物功能

分析

定义一个检查蛇头是否与食物碰撞的函数。具体的实现逻辑如下:

  1. 首先获取蛇的头部坐标 snake_list[0],并计算出蛇头的矩形区域 snake_head_rect。矩形区域的坐标为 (蛇头x坐标-SNAKE_WIDTH/2, 蛇头y坐标-SNAKE_WIDTH/2, SNAKE_WIDTH, SNAKE_HEIGHT)
  2. 遍历食物列表 food_list,获取每个食物的坐标 xyz。再计算出食物的矩形区域 food_rect。矩形区域的坐标为 (食物x坐标-FOOD_WIDTH/2, 食物y坐标-FOOD_WIDTH/2, FOOD_WIDTH, FOOD_HEIGHT)
  3. 调用 rect_cover 函数判断蛇头的矩形区域是否与当前食物的矩形区域重叠。如果重叠,则表示蛇头与该食物碰撞了。
  4. 如果蛇头与食物碰撞,则调用 add_body 函数将食物的类型 xyz[2] 加入到蛇的身体中,并从食物列表中移除该食物。
  5. 最后返回一个布尔值,表示蛇头是否与任何食物碰撞。

代码

# 检查是否有食物被吃掉
def check_food():
    # 获取蛇头的位置
    first = snake_list[0]
    
    # 创建蛇头的矩形区域
    snake_head_rect = (first[0] - SNAKE_WIDTH/2, first[1] - SNAKE_WIDTH/2, SNAKE_WIDTH, SNAKE_HEIGHT)
    
    # 遍历食物列表
    for i in range(len(food_list)):
        xyz = food_list[i]
        
        # 创建食物的矩形区域
        food_rect = (xyz[0] - FOOD_WIDTH/2, xyz[1] - FOOD_WIDTH/2, FOOD_WIDTH, FOOD_HEIGHT)
        
        # 检查蛇头是否与食物重叠
        if rect_cover(snake_head_rect, food_rect):
            # 添加食物对应的身体节
            add_body(xyz[2])
            
            # 从食物列表中删除已被吃掉的食物
            del food_list[i]
            
            return True
  
    return False
4.12、贪吃蛇死亡功能

分析

定义一个check_dead() 函数用于检查蛇是否死亡,即判断蛇头是否与边缘、墙壁或自身的身体发生碰撞。具体过程如下:

  1. 获取蛇头的位置,即蛇列表中的第一个元素。
  2. 创建蛇头的矩形区域,以便后续与边缘、墙壁或自身的身体进行碰撞检测。
  3. 检查蛇头是否与边缘发生碰撞,即蛇头是否超出了游戏区域的范围。如果超出范围,则视为蛇死亡,返回 True
  4. 遍历墙壁列表,获取每个墙壁的坐标。
  5. 创建墙壁的矩形区域,以便后续与蛇头的矩形区域进行碰撞检测。
  6. 检查蛇头是否与墙壁发生碰撞。如果发生碰撞,则视为蛇死亡,返回 True
  7. 遍历蛇列表中除蛇头外的元素,即蛇的身体。
  8. 创建身体节的矩形区域,以便后续与蛇头的矩形区域进行碰撞检测。
  9. 检查蛇头是否与自身的身体发生碰撞。如果发生碰撞,则视为蛇死亡,返回 True
  10. 如果以上都未发生,即蛇未死亡,返回 False

代码

# 检查蛇是否死亡
def check_dead():
    # 获取蛇头的位置
    first = snake_list[0]
    
    # 创建蛇头的矩形区域
    snake_head_rect = (first[0] - SNAKE_WIDTH/2, first[1] - SNAKE_WIDTH/2, SNAKE_WIDTH, SNAKE_HEIGHT)
    
    # 检查蛇头是否与边缘发生碰撞
    if first[0] < 0 or first[0] > GAME_SIZE[0] or first[1] < 0 or first[1] > GAME_SIZE[1]:
        return True
    
    # 检查蛇头是否与墙壁发生碰撞
    for xy in wall_list:
        wall_rect = (xy[0] - WALL_WIDTH/2, xy[1] - WALL_WIDTH/2, WALL_WIDTH, WALL_HEIGHT)
        if rect_cover(snake_head_rect, wall_rect):
            return True
    
    # 检查蛇头是否与自身的身体发生碰撞
    for xy in snake_list[1:]:
        body_rect = (xy[0] - SNAKE_WIDTH/2, xy[1] - SNAKE_WIDTH/2, SNAKE_WIDTH, SNAKE_HEIGHT)
        if rect_cover(snake_head_rect, body_rect):
            return True
    
    return False
4.13、实现键盘控制游戏

分析

编写一个处理事件的循环,它的作用是根据用户的输入来控制游戏的行为。主要包含以下几个事件处理:

  1. pygame.QUIT 事件:当用户点击窗口的关闭按钮时,这个事件会触发。在这段代码中,会将 running 变量设置为 False,从而退出游戏循环。
  2. pygame.MOUSEBUTTONDOWN 事件:当用户点击鼠标按钮时,这个事件会触发。在这段代码中,每次点击鼠标按钮会切换 pause 变量的状态,用来暂停游戏。
  3. pygame.KEYUP 事件:当用户松开键盘上的按键时,这个事件会触发。在这段代码中,根据松开的按键来控制蛇头的移动方向。具体的处理逻辑如下:
    • 如果松开的键是 K_LEFT(即左箭头键),并且当前蛇头方向不是向右(head 不为 ‘right’),则将新的蛇头方向设置为向左(‘left’)。
    • 如果松开的键是 K_RIGHT(即右箭头键),并且当前蛇头方向不是向左(head 不为 ‘left’),则将新的蛇头方向设置为向右(‘right’)。
    • 如果松开的键是 K_UP(即上箭头键),并且当前蛇头方向不是向下(head 不为 ‘down’),则将新的蛇头方向设置为向上(‘up’)。
    • 如果松开的键是 K_DOWN(即下箭头键),并且当前蛇头方向不是向上(head 不为 ‘up’),则将新的蛇头方向设置为向下(‘down’)。

代码

# 事件循环
while running:
    # 获取所有事件并逐个处理
    for event in pygame.event.get():
        # 处理关闭窗口事件
        if event.type == pygame.QUIT:
            # 退出游戏循环
            running = False
            break
        # 处理鼠标点击事件
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 切换暂停状态(pause变量为True时暂停,为False时正常运行)
            pause = not pause
        # 处理按键松开事件
        elif event.type == pygame.KEYUP:
            # 如果松开的键是左箭头键,并且当前蛇头方向不是向右,则将新的蛇头方向设置为向左
            if event.key == K_LEFT:
                if head in ['up','down']:
                    head = 'left'
            # 如果松开的键是右箭头键,并且当前蛇头方向不是向左,则将新的蛇头方向设置为向右
            elif event.key == K_RIGHT:
                if head in ['up','down']:
                    head = 'right'
            # 如果松开的键是上箭头键,并且当前蛇头方向不是向下,则将新的蛇头方向设置为向上
            elif event.key == K_UP:
                if head in ['left','right']:
                    head = 'up'
            # 如果松开的键是下箭头键,并且当前蛇头方向不是向上,则将新的蛇头方向设置为向下
            elif event.key == K_DOWN:
                if head in ['left','right']:
                    head = 'down'
4.14、更新贪吃蛇位置功能

分析

在游戏不暂停且蛇没有死亡的情况下,更新蛇的位置。具体操作如下:

  • 计算时间:根据帧率 frame 和游戏难度 level 来计算游戏进行的时间。
  • 获取蛇的头部位置:将蛇列表中的第一个元素作为蛇头的当前位置。
  • 移动蛇身:将蛇列表中索引为1以及之后的元素赋值为索引减1以及之前的元素,即每个蛇身的位置向前移动一个单位。
  • 根据当前头部的方向更新蛇头的位置:根据变量 head 的值,更新蛇头的位置。如果头部方向是 ‘up’,则将头部位置的纵坐标减去一个单位;如果方向是 ‘down’,则将纵坐标加上一个单位;如果方向是 ‘left’,则将横坐标减去一个单位;如果方向是 ‘right’,则将横坐标加上一个单位。

代码

# 如果游戏没有暂停,并且蛇没有死亡,则执行以下操作
if not pause and not dead:
    # 计算时间
    count_time += frame * level
    
    # 获取蛇的头部位置
    first = snake_list[0]
    
    # 将蛇身的每个部分向前移动一个单位
    snake_list[1:] = snake_list[:-1]
    
    # 根据当前头部的方向更新蛇头的位置
    if head == 'up':
        snake_list[0] = [first[0], first[1] - SNAKE_WIDTH]
    elif head == 'down':
        snake_list[0] = [first[0], first[1] + SNAKE_WIDTH]
    elif head == 'left':
        snake_list[0] = [first[0] - SNAKE_WIDTH, first[1]]
    elif head == 'right':
        snake_list[0] = [first[0] + SNAKE_WIDTH, first[1]]
4.15、更新游戏画面和处理用户输入功能

分析

负责更新游戏画面和处理用户输入,具体操作如下:

  • 绘制背景:绘制游戏的背景。
  • 绘制隧道:绘制游戏中的隧道。
  • 选择物品:绘制游戏的角色,即蛇。
  • 绘制食物:绘制游戏中的食物。
  • 绘制得分:绘制游戏中的得分。
  • 如果游戏暂停且蛇没有死亡,绘制暂停界面。
  • 如果蛇死亡,绘制游戏结束界面。
  • 刷新显示:更新显示,将绘制的内容显示在屏幕上。
  • 暂停 20 毫秒:暂停游戏的执行一段时间,控制游戏的帧率。
  • 检查是否死亡:检查当前游戏状态是否为死亡状态。
  • 检查是否吃到食物:检查蛇是否吃到食物。
  • 关闭 pygame:结束游戏。

代码

# 绘制背景
draw_background()

# 绘制隧道
draw_wall()

# 选择物品
draw_snake()

# 绘制食物
draw_food()

# 绘制得分
draw_context()

# 如果游戏暂停且蛇没有死亡,绘制暂停界面
if not dead and pause:
    draw_pause()

# 如果蛇死亡,绘制游戏结束界面
if dead:
    draw_dead()

# 刷新显示
pygame.display.flip()

# 暂停 20 毫秒
pygame.time.delay(int(frame/level*1000))

# 检查是否死亡
dead = check_dead()

# 检查是否吃到食物
if check_food():
    add_food()

# 关闭 pygame
pygame.quit()
5、结束

需要源码留言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1322519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么检测DC-DC电源模块稳定性?电源测试系统测试有什么优势?

DC-DC电源模块稳定性测试 稳定性是衡量DC电源模块的重要指标&#xff0c;电源模块的稳定性直接影响着电源产品和设备的工作稳定性。DC-DC电源模块的稳定性&#xff0c;可以通过检测输出电压、输出电流、负载、波形、效率等参数来评估。 1. 静态测试方法 静态测试是通过直流电压…

理解SwiftUI中的matchedGeometryEffect

matchedGeometryEffect SwiftUI 2.0 引入了一个新的修饰符&#xff1a;matchedGeometryEffect 。使用matchedGeometryEffect可以为整个层次结构中的视图创建过渡动画。只需要将它附加到要进行动画处理的两个视图上&#xff0c;并给它们指定相同的标识符。有了 matchedGeometry…

深耕元宇宙领域,强势发力文旅市场

2023年12月14日&#xff0c;“承上启下 智元宇宙&#xff1a;2024元宇宙与人工智能应用场景闭门会——苏州”在苏州泰山路2号百度VR&#xff08;苏州&#xff09;赋能中心成功举办。会议邀请了苏州本地的相关优秀企业代表、科创精英、投资与行业技术代表、公司创始人共计约50余…

龙迅LT6211B,HDMI1.4转LVDS,应用于AR/VR市场

产品描述 LT6211B 是一款用于 VR/ 显示应用的高性能 HDMI1.4 至 LVDS 芯片。 对于 LVDS 输出&#xff0c;LT6211B 可配置为单端口、双端口或四端口。对于2D视频流&#xff0c;同一视频流可以映射到两个单独的面板&#xff0c;对于3D视频格式&#xff0c;左侧数据可以发送到一个…

MySQL表的增删改查(初阶)

CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首字母缩写。且增删改查&#xff08;CRUD&#xff0c;create&#xff0c;retrieve&#xff0c;update&#xff0c;delete&#xff09;数据库的核心模块。 1. 新增&#xff08;Create&#xff09; 实…

去面试性能测试工程师必问的问题,

性能测试的三个核心原理是什么&#xff1f; 1.基于协议。性能测试的对象是网络分布式架构的软件&#xff0c;而网络分布式架构的核心是网络协议 2.多线程。人的大脑是单线程的&#xff0c;电脑的cpu是多线程的。性能测试就是利用多线程的技术模拟多用户去负载 3.模拟真实场景。…

(详解版)创建线程的四种方式

文章目录 Java中创建线程的四种方式1. 继承Thread类并重写 run 方法来创建线程2. 实现Runnable接口并实现 run 方法来创建线程。3. 使用Callable接口创建线程4. 使用Executor框架创建线程 Java中创建线程的四种方式 接下来我会详细解释这四种方式创建线程如何实现. 我们如果要…

STM32——串口通信应用篇

一、引言 STM32微控制器是一款功能强大的嵌入式系统芯片&#xff0c;广泛应用于各种领域。其中&#xff0c;串口通信是其重要功能之一&#xff0c;可用于与外部设备进行数据交换和控制。本文将介绍STM32串口通信的基本原理、应用场景以及实现方法。 二、STM32串口通信基本原理 …

linux xxd命令(将文件或标准输入转换为hex(十六进制)和ASCII(美国信息交换标准代码)表示,或者从hex dump(十六进制转储)反向到二进制)

文章目录 Linux xxd命令安装xxd基本使用方法创建hex dump从hex dump恢复到二进制 命令选项疑难技术点解析在脚本中使用xxd从hex dump恢复数据 总结 Linux xxd命令 xxd是一个在Linux和UNIX系统中常用的工具&#xff0c;主要用于将文件或标准输入转换为hex&#xff08;十六进制&…

Java中线程状态的描述

多线程-基础方法的认识 截止目前线程的复习 Thread 类 创建Thread类的方法 继承Thread类,重写run方法实现Runnable接口,重写run方法使用匿名内部类继承Thread类,重写run方法使用匿名内部类实现Runnable接口,重写run方法使用Lambda表达式 run方法中的所有的代码是当前线程对…

[Linux] LVS负载均衡群集——DR模式

一、 DR模式的特点 直接路由&#xff1a; 在LVS_DR模式下&#xff0c;负载均衡器不修改数据包的IP地址&#xff0c;只修改目的MAC地址。这使得数据包可以直接路由到后端实际服务器上&#xff0c;而不需要返回到负载均衡器。 高性能&#xff1a; 由于数据包在传输过程中不需要回…

dubbo--03--- dubbo 支持的9种协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Dubbo框架特性Dubbo 和 Spring Cloud区别 dubbo 支持的9种协议协议类型1、dubbo 协议 (默认)特性配置常见问题 2、rmi 协议3、hessian 协议4、http 协议特性 5、web…

案例073:基于微信小程序的智慧旅游平台开发

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【MYSQL】-表的操作

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

functools.partial:Python中灵活函数部分应用的工具

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python编程中&#xff0c;functools.partial是一个强大的工具&#xff0c;它提供了一种部分应用函数的方式&#xff0c;能够在创建新函数时固定部分参数&#xff0c;从而在后续调用中减少需要传递的参数数量。…

python中random.seed()和random.getstate()用法详解

python中random.seed()和random.getstate()用法详解 摘要 python的random包经常被用于模拟实验的重现&#xff0c;数据集的随机划分的确定性重现。然而&#xff0c;我本人之前对random.seed()什么时候调用&#xff0c;调用之后会对之后多少代码起决定性作用这一块感到云里雾里…

压测方案设计..

01 为什么要做压测 1、什么是压力测试&#xff1f; 不断向被测对象施加压力&#xff0c;测试系统在压力情况下的表现。 2、压力测试的目的是什么&#xff1f; 测试得出系统的极限性能指标&#xff0c;从而给出合理的承诺值或者容量告警&#xff1b; 找出系统的性能瓶颈&am…

清华提出ViLa,揭秘 GPT-4V 在机器人视觉规划中的潜力

人类在面对简洁的语言指令时&#xff0c;可以根据上下文进行一连串的操作。对于“拿一罐可乐”的指令&#xff0c;若可乐近在眼前&#xff0c;下意识的反应会是迅速去拿&#xff1b;而当没看到可乐时&#xff0c;人们会主动去冰箱或储物柜中寻找。这种自适应的能力源于对场景的…

51单片机简易出租车计费系统仿真设计

51单片机简易出租车计费系统仿真设计( proteus仿真程序报告讲解视频&#xff09; 仿真图proteus 8.9及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0036 1.主要功能&#xff1a; 出租车计费系统设计内容&#xff1a; 1、…

JDK17 SpringBoot3 整合常见依赖

JDK版本:17 SpringBoot 整合Mybatis Plus 、Redis等 依赖文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xs…