python游戏代码开发,pygame贪吃蛇2.0版

文章目录

概要

欢迎各位朋友阅读,先展示效果视频吧。

只是想玩游戏可以到末尾直接拿源代码,想要学习的朋友请继续阅读。

相对于开发的大部分贪吃蛇1.0版本,我增加了一些玩法:

改变蛇的形状,模样更贴近一些

设置积分制

吃一个食物速度增加,设置了最大速度

倒计时时间,时间结束死亡

可以按键暂停和重开

吃一个食物获得10积分,剩余时间增加2s,有2s的猫咪吃东西音效(个人爱好)

计算历史最高积分,死亡时结算积分

开发流程

1、初始化界面

搭建基本的界面,定义游戏窗口大小、题目、背景色和退出功能,代码如下:

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度

bgcolor = (40, 40, 60)  # 背景色


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

2、显示栏

空白界面有了,接下来我们先画一下展示栏

我先定义显示文本函数,然后在初始化界面中调用

代码和效果如下:

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2), 0)
        self.print_text(self.screen, self.font2, 30, 7, '速度: ')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

746f44c23d4e4e44ab1c4cd29dc74aba.png

3、画食物和蛇

(1)概述

到了关键的食物和蛇了

我理解pygame开发游戏就是先画出各种静态图,再通过玩家操作,让各个静态图发生交互

如果没有概念的话可以先百度了解动态图

所以接下来我们需要判断各种情况,并制作相关的静态图,为之后开始游戏做准备

(2)定义食物和蛇的性质

我们可以把画静态图分为两步:

第一步 定义数据也就是以什么形式存放坐标

第二步 绘画就是根据存放的数据进行画出静态图

这么做方便修改和减少重复性代码

代码如下:

from collections import deque
import random
import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体       
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()
        
    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])
            
    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2), 0)
        self.print_text(self.screen, self.font2, 30, 7, '速度: ')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")
(3)绘画食物和蛇

接下来绘画比较麻烦,大家应该看过完整的效果图

食物只是一个圆就行

蛇的话我分为三个部分绘画,蛇头、蛇身、蛇尾

蛇头是半圆加矩形组成轮廓,再绘画眼睛由白色圆加黑色圆组成

蛇身是一个矩形,我定义为非蛇头和蛇尾的躯体

蛇尾是半圆加矩形组成

由于蛇头和蛇尾向左、右、上、下方向移动的静态图形状不同,所以我们需要画四张图

蛇头的话方向有定义,根据方向画就行

蛇尾方向比较麻烦,我想到通过比较蛇尾与相近蛇身的坐标差另定义方向

代码和效果如下:

import random
from collections import deque
import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                           SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, '速度: ')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

f02a69df8a2947448da3444daac8f2c1.png

4、开始移动

好了,我们我们静态图有了,就可以让他们发生交互了

先设定发生交互的原因是什么,常用是时间。到了指定时间后,换下一张静态图

我这里指定时间就是蛇的速度,而蛇速度单位是格/s

也就是说每过蛇速度x的时间后,移动一格距离

在3(2)讲过绘画静态图的原理,让蛇移动就是数据的坐标移动

所以我们正常修改数据,让数据变化产生动画效果,也就实现了游戏移动

代码和效果如下:

import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        self.speed = 0.5  # 初始速度 0.5s/格
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, '速度: ')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

5、玩家操作

蛇能移动了,接下来需要添加键盘操作,让玩家能够正常控制

蛇的移动上节说过,就是数据的坐标发生改变

方向键:我们通过修改蛇头下一步坐标变化达到效果

开始键:我们需要在蛇移动前添加条件开始,死亡时将其关闭,重开再打开(别忘记初始化数据)

暂停键:我们需要在蛇移动前添加条件未暂停,暂停就打开,不暂停就关闭

代码和效果如下:

import random
import time
from collections import deque
import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        self.speed = 0.5  # 初始速度 0.5s/格
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                           SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, '速度: ')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

6、速度

到这里已经完成一个贪吃蛇游戏了,只不过有些单调

我们添加一个设定,吃到一个食物蛇的速度增加,同时设置最大速度

显示栏的速度的值也可以同步了

代码和效果如下:

import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        self.speed = 0.5  # 初始速度 0.5s/格
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, f'速度: {int((0.53 - self.speed) * 100 / 3)}')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, '时间: ')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

7、倒计时

倒计时这一块比较麻烦。

python是单线程语言

所以我们写的倒计时函数,也必须放到主循环中运行

倒计时单位是秒,那么我们可以写成条件判断函数

计算时间间隔每过1s运行一次,直到倒计时时间结束

重点我们需要考虑暂停以及重开,一些数据别忘记重置

还有吃食物倒计时时间延长2s

代码和效果如下:

import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        self.speed = 0.5  # 初始速度 0.5s/格
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        self.timer = '03:00'  # 倒计时
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        self.seconds += 2
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, f'速度: {int((0.53 - self.speed) * 100 / 3)}')
        self.print_text(self.screen, self.font2, 450, 7, '积分: ')
        self.print_text(self.screen, self.font2, 240, 7, f'时间: {self.timer}')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start_time = time.time()  # 开始倒计时
                        self.seconds = 3 * 60  # 重置倒计时
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def countdown(self):
        """
        倒计时
        """
        # 循环次数
        global i
        if self.start:
            if not self.pause:
                # 剩余时间大于0
                if self.seconds >= 0:
                    mins, secs = divmod(self.seconds, 60)
                    self.timer = '{:02d}:{:02d}'.format(mins, secs)
                    last_time = time.time()
                    # 倒计时变化
                    if last_time >= self.start_time + i:
                        self.seconds -= 1
                        i += 1
            else:  # 空格暂停时
                self.start_time = time.time()  # 重置倒计时时间
                i = 1  # 重置循序

            if self.seconds < 0:  # 倒计时结束
                self.game_over = True
        else:
            i = 1  # 死亡重置

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.countdown()  # 时间倒计时
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

7

8、积分

朋友快完成了,加油

根据玩法,需要设定:

吃一个食物积分+10

死亡时计算积分并展示历史最高积分

历史最高分这个功能实现:

我写了两个函数,一个展示最高分,另一个存放最高分到本地文件

展示最高分函数:死亡时调用,通过比较最高分成绩文件中积分与当前积分实现两种文本展示

存放最高分函数:退出和重开初始化前调用,尝试读取最高分文件,没有默认为0

比较当前积分和历史最高分,结果决定是否覆盖文件

代码和效果如下:

import pickle
import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        self.score = 0  # 得分
        self.timer = '03:00'  # 倒计时
        self.speed = 0.5  # 初始速度 0.5s/格
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
            # 显示当前积分和历史最高分
            self.max_results()
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        self.score += 10
                        self.seconds += 2
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, f'速度: {int((0.53 - self.speed) * 100 / 3)}')
        self.print_text(self.screen, self.font2, 450, 7, f'积分: {self.score}')
        self.print_text(self.screen, self.font2, 240, 7, f'时间: {self.timer}')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                self.save_results()  # 是否替换历史最高分
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.save_results()  # 是否替换历史最高分
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start_time = time.time()  # 开始倒计时
                        self.seconds = 3 * 60  # 重置倒计时
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def countdown(self):
        """
        倒计时
        """
        # 循环次数
        global i
        if self.start:
            if not self.pause:
                # 剩余时间大于0
                if self.seconds >= 0:
                    mins, secs = divmod(self.seconds, 60)
                    self.timer = '{:02d}:{:02d}'.format(mins, secs)
                    last_time = time.time()
                    # 倒计时变化
                    if last_time >= self.start_time + i:
                        self.seconds -= 1
                        i += 1
            else:  # 空格暂停时
                self.start_time = time.time()  # 重置倒计时时间
                i = 1  # 重置循序

            if self.seconds < 0:  # 倒计时结束
                self.game_over = True
        else:
            i = 1  # 死亡重置

    def max_results(self):
        """展示历史最高分"""
        # 从文件加载变量
        with open('max_results.pkl', 'rb') as file:
            loaded_data = pickle.load(file)

        if self.score > loaded_data:
            # 展示恭喜你打破历史最高积分和当前积分
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'恭喜你打破历史最高分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')
        else:
            # 展示最高成绩和当前积分(先最高成绩后当前,居中上下展示)
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'历史最高积分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')

    def save_results(self):
        """
        替换历史最高分
        应该重开时或者关闭时引用
        """
        # 从文件加载变量
        try:
            with open('max_results.pkl', 'rb') as file:
                loaded_data = pickle.load(file)  # 获取历史成绩
        except:
            loaded_data = 0

        if self.score >= loaded_data:  # 覆盖第一次历史最高分
            # 替换历史最高分
            with open('max_results.pkl', 'wb') as file:
                pickle.dump(self.score, file)

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.countdown()  # 时间倒计时
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

8

9、操作说明(完成)

最后一步,要求:启动时展示操作说明

用函数封装展示操作说明,那么放哪尼

我们思考一下,什么情况下只会启动时运行

如果朋友是一步步思考过来,那么有一个状态满足条件:未开始未结束阶段

 

代码和效果如下:

import pickle
import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        self.score = 0  # 得分
        self.timer = '03:00'  # 倒计时
        self.speed = 0.5  # 初始速度 0.5s/格
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
            # 显示当前积分和历史最高分
            self.max_results()
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        self.score += 10
                        self.seconds += 2
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE))

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        elif not self.start and not self.game_over:  # 初始界面即未开始未死亡阶段
            # 展示操作说明
            self.help()
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2))
        self.print_text(self.screen, self.font2, 30, 7, f'速度: {int((0.53 - self.speed) * 100 / 3)}')
        self.print_text(self.screen, self.font2, 450, 7, f'积分: {self.score}')
        self.print_text(self.screen, self.font2, 240, 7, f'时间: {self.timer}')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家键盘操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                self.save_results()  # 是否替换历史最高分
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.save_results()  # 是否替换历史最高分
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start_time = time.time()  # 开始倒计时
                        self.seconds = 3 * 60  # 重置倒计时
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def countdown(self):
        """
        倒计时
        """
        # 循环次数
        global i
        if self.start:
            if not self.pause:
                # 剩余时间大于0
                if self.seconds >= 0:
                    mins, secs = divmod(self.seconds, 60)
                    self.timer = '{:02d}:{:02d}'.format(mins, secs)
                    last_time = time.time()
                    # 倒计时变化
                    if last_time >= self.start_time + i:
                        self.seconds -= 1
                        i += 1
            else:  # 空格暂停时
                self.start_time = time.time()  # 重置倒计时时间
                i = 1  # 重置循序

            if self.seconds < 0:  # 倒计时结束
                self.game_over = True
        else:
            i = 1  # 死亡重置

    def max_results(self):
        """展示历史最高分"""
        # 从文件加载变量
        with open('max_results.pkl', 'rb') as file:
            loaded_data = pickle.load(file)

        if self.score > loaded_data:
            # 展示恭喜你打破历史最高积分和当前积分
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'恭喜你打破历史最高分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')
        else:
            # 展示最高成绩和当前积分(先最高成绩后当前,居中上下展示)
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'历史最高积分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')

    def save_results(self):
        """
        替换历史最高分
        应该重开时或者关闭时引用
        """
        # 从文件加载变量
        try:
            with open('max_results.pkl', 'rb') as file:
                loaded_data = pickle.load(file)  # 获取历史成绩
        except:
            loaded_data = 0

        if self.score >= loaded_data:  # 覆盖第一次历史最高分
            # 替换历史最高分
            with open('max_results.pkl', 'wb') as file:
                pickle.dump(self.score, file)

    def help(self):
        """
        展示操作说明
        """
        """
            w,s,a,d/上下左右 控制移动方向
            回车键  开始/重开  
            空格键 暂停/取消暂停
        """
        # 展示操作说明
        self.centre_text(self.screen, self.font2, -SIZE * 4, '回车键:开始/重开')
        self.centre_text(self.screen, self.font2, -SIZE * 2, '空格键:暂停/取消暂停')
        self.centre_text(self.screen, self.font2, 0, 'w,s,a,d/上下左右:控制移动方向')

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.countdown()  # 时间倒计时
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

9

技术细节

本人使用:

python3.7版本开发语言

pygame 2.1.2版本

pycharm 编译器

小结

感谢大家看完这篇文章

写的不好的地方,欢迎大家指出

如果有看不懂地方,也欢迎在评论去留言

顺便说一下吃食物音效,因素材限制就没解说

如果需要的话,去下方获取完整代码另找素材包替换

游戏完整代码

不需要吃食物音效的完整代码,去上方开发流程的最后一步获取

想要有吃食物音效的完整代码如下(音效包需要自己另找wav包替代):

import pickle
import random
import time
from collections import deque

import pygame
from pygame.locals import *

SCREEN_LENGTH = 600  # 窗口长度
SCREEN_HEIGHT = 480  # 窗口宽度
SIZE = 20  # 基本单位
i = 1  # 用来倒计时,做循环次数

# 范围
scope_x = (0, SCREEN_LENGTH // SIZE - 1)
scope_y = (2, SCREEN_HEIGHT // SIZE - 1)

# 颜色
black = (0, 0, 0)  # 显示栏
bgcolor = (40, 40, 60)  # 背景色
orange = (240, 134, 80)  # 蛇颜色
red = (200, 30, 30)  # GAME OVER 的字体颜色和食物


class GAME:
    """
    贪吃蛇游戏
    """

    def __init__(self):
        # 初始化
        pygame.init()
        # 窗口
        self.screen = pygame.display.set_mode((SCREEN_LENGTH, SCREEN_HEIGHT))
        # 题目
        pygame.display.set_caption('贪吃蛇')
        self.pause = False  # 未暂停
        self.start = False  # 未开始
        self.game_over = False  # 未结束
        self.score = 0  # 得分
        self.timer = '03:00'  # 倒计时
        self.speed = 0.5  # 初始速度 0.5s/格
        # 字体格式
        self.font2 = pygame.font.SysFont('华文中宋', 26)  # 大部分字体格式
        self.font = pygame.font.SysFont('华文中宋', 72)  # 字体
        # 创建蛇对象
        self.snake = deque()  # deque(双端队列),deque([])
        # 创建食物对象
        self.food = [0, 0]
        # 确保一个方向指令执行一次改变方向的移动
        self.b = True
        # 初始方向为右
        self.direction = [1, 0]
        # 初始化蛇性质
        self.init_snake()
        # 初始化食物性质
        self.init_food()

    def init_snake(self):
        """
        初始化蛇
        """
        # 添加数据坐标
        self.snake.append((3, scope_y[0]))
        self.snake.append((2, scope_y[0]))
        self.snake.append((1, scope_y[0]))
        self.snake.append((0, scope_y[0]))

    def init_food(self):
        """
        初始化食物
        """
        # 定义食物坐标随机
        self.food[0] = random.randint(scope_x[0], scope_x[1])
        self.food[1] = random.randint(scope_y[0], scope_y[1])
        # 删除食物出现在蛇内
        while (self.food[0], self.food[1]) in self.snake:
            self.food[0] = random.randint(scope_x[0], scope_x[1])
            self.food[1] = random.randint(scope_y[0], scope_y[1])

    def init_settings(self):
        """
        初始化界面   ***
        为那些数据(蛇,食物,墙等)绘画
        """
        # 吃食物声音
        sound = pygame.mixer.Sound('猫咪吃东西.wav')
        self.screen.fill(bgcolor)  # 背景色
        # 游戏结束
        if self.game_over:
            self.start = False
            # 居中展示 GAME OVER
            self.centre_text(self.screen, self.font, 0, 'GAME OVER', color=red)
            # 显示当前积分和历史最高分
            self.max_results()
        else:
            # 正常运行时
            if not self.pause and self.start:
                curtime = time.time()
                # 每过蛇速度时,开始移动一次
                if curtime - self.last_move_time > self.speed:
                    self.b = True  # 实现速度内只有一个方向
                    self.last_move_time = curtime
                    # 蛇头下一步位置
                    next_s = (self.snake[0][0] + self.direction[0], self.snake[0][1] + self.direction[1])
                    if next_s == (self.food[0], self.food[1]):  # 吃到食物
                        self.snake.appendleft(next_s)
                        self.init_food()
                        self.score += 10
                        self.seconds += 2
                        sound.play()
                        # 设置最大速度
                        if int((0.53 - self.speed) * 100 / 3) < 15:  # 显示速度
                            self.speed -= 0.01 * 3
                    else:  # 蛇正常移动
                        # 正常移动范围内
                        if scope_x[0] <= next_s[0] <= scope_x[1] and scope_y[0] <= next_s[1] <= scope_y[
                            1] and next_s not in self.snake:
                            self.snake.appendleft(next_s)
                            self.snake.pop()
                        else:  # 吃到自己或者墙壁,死亡
                            self.game_over = True
        # 画蛇
        for s in self.snake:
            if s in list(self.snake)[1:-1]:  # 蛇身体
                pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE,
                                                       SIZE, SIZE))
            # 画蛇头和蛇尾需要知道方向,每个方向不一样
            elif s == list(self.snake)[0]:  # 蛇头
                if self.direction == [0, -1]:  # 向上
                    # 蛇头 由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                    # 蛇眼睛 白色圆和黑色圆组成
                    pygame.draw.circle(self.screen, (255, 255, 255), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10, 0)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4), SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10, 0)
                elif self.direction == [0, 1]:  # 向下
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10, 0)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10, 0)
                elif self.direction == [-1, 0]:  # 向左
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10, 0)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10, 0)
                elif self.direction == [1, 0]:  # 向右
                    # 蛇头
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                    # 蛇眼睛
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE / 4),
                                       SIZE / 10, 0)
                    pygame.draw.circle(self.screen, (255, 255, 255),
                                       (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4), SIZE / 5, 0)
                    pygame.draw.circle(self.screen, (0, 0, 0), (s[0] * SIZE + SIZE * 3 / 4, s[1] * SIZE + SIZE * 3 / 4),
                                       SIZE / 10, 0)
            else:  # 蛇尾
                dir = [self.snake[-2][0] - s[0], self.snake[-2][1] - s[1]]  # 判断蛇尾方向,通过比较蛇尾与相近身体的坐标
                if dir == [0, -1]:  # 蛇尾方向向上,蛇头与蛇尾方向是两种
                    # 蛇尾   由半圆和矩形组成
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE + SIZE), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                if dir == [0, 1]:  # 蛇尾方向向下
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE / 2, s[1] * SIZE), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                if dir == [-1, 0]:  # 蛇尾方向向左
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE + SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)
                if dir == [1, 0]:  # 蛇尾方向向右
                    # 蛇尾
                    pygame.draw.circle(self.screen, orange, (s[0] * SIZE, s[1] * SIZE + SIZE / 2), SIZE / 2, 0)
                    pygame.draw.rect(self.screen, orange, (s[0] * SIZE, s[1] * SIZE, SIZE, SIZE), 0)

        # 画食物
        if self.start:
            pygame.draw.circle(self.screen, red, (self.food[0] * SIZE + SIZE / 2, self.food[1] * SIZE + SIZE / 2),
                               SIZE / 2)
        elif not self.start and not self.game_over:  # 初始界面即未开始未死亡阶段
            # 展示操作说明
            self.help()
        # 画显示栏
        pygame.draw.rect(self.screen, black, (0, 0, SCREEN_LENGTH, SIZE * 2), 0)
        self.print_text(self.screen, self.font2, 30, 7, f'速度: {int((0.53 - self.speed) * 100 / 3)}')
        self.print_text(self.screen, self.font2, 450, 7, f'积分: {self.score}')
        self.print_text(self.screen, self.font2, 240, 7, f'时间: {self.timer}')
        pygame.display.flip()  # 刷新界面,不刷新界面没效果

    def control(self):
        """
        玩家操作
        """
        for event in pygame.event.get():  # 截取游戏的事件
            if event.type == QUIT:  # 退出
                self.save_results()  # 是否替换历史最高分
                exit()
            elif event.type == KEYDOWN:  # 键盘按键
                if event.key == K_RETURN:  # 回车键
                    if self.game_over or not self.start:  # 开始游戏
                        self.save_results()  # 是否替换历史最高分
                        self.__init__()  # 初始化大部分数据
                        self.last_move_time = time.time()  # 用来速度
                        self.start_time = time.time()  # 开始倒计时
                        self.seconds = 3 * 60  # 重置倒计时
                        self.start = True  # 开始
                elif event.key == K_SPACE:  # 暂停
                    self.pause = not self.pause
                elif event.key in (K_w, K_UP):
                    # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER
                    if self.b and not self.direction[1]:
                        self.direction = [0, -1]
                        self.b = False
                elif event.key in (K_s, K_DOWN):
                    if self.b and not self.direction[1]:
                        self.direction = [0, 1]
                        self.b = False
                elif event.key in (K_a, K_LEFT):
                    if self.b and not self.direction[0]:
                        self.direction = [-1, 0]
                        self.b = False
                elif event.key in (K_d, K_RIGHT):
                    if self.b and not self.direction[0]:
                        self.direction = [1, 0]
                        self.b = False

    def print_text(self, screen, font, x, y, text, color=(255, 255, 255)):
        """
        游戏窗口最上面显示的文本

        screen 窗口
        font 字体
        x 横坐标
        y 纵坐标
        text 文本
        color 字体颜色
        """
        imgText = font.render(text, True, color)  # 文本
        screen.blit(imgText, (x, y))  # 渲染文本

    def centre_text(self, screen, font, y, text, x=0, color=(255, 255, 255)):
        """
        游戏窗口中间显示的文本

        screen 窗口
        font 字体
        y 离中心的纵坐标偏差值
        text 文本
        x 离中心的横坐标偏差值
        color 字体颜色
        """
        Text = font.render(text, True, color)  # 文本
        width, height = font.size(text)  # 文本宽,高
        # 渲染文本
        screen.blit(Text, ((SCREEN_LENGTH - width) // 2 + x, (SCREEN_HEIGHT - height) // 2 + y))

    def countdown(self):
        """
        倒计时
        """
        # 循环次数
        global i
        if self.start:
            if not self.pause:
                # 剩余时间大于0
                if self.seconds >= 0:
                    mins, secs = divmod(self.seconds, 60)
                    self.timer = '{:02d}:{:02d}'.format(mins, secs)
                    last_time = time.time()
                    # 倒计时变化
                    if last_time >= self.start_time + i:
                        self.seconds -= 1
                        i += 1
            else:  # 空格暂停时
                self.start_time = time.time()  # 重置倒计时时间
                i = 1  # 重置循序

            if self.seconds < 0:  # 倒计时结束
                self.game_over = True
        else:
            i = 1  # 死亡重置

    def max_results(self):
        """展示历史最高分"""
        # 从文件加载变量
        with open('max_results.pkl', 'rb') as file:
            loaded_data = pickle.load(file)

        if self.score > loaded_data:
            # 展示恭喜你打破历史最高积分和当前积分
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'恭喜你打破历史最高分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')
        else:
            # 展示最高成绩和当前积分(先最高成绩后当前,居中上下展示)
            self.centre_text(self.screen, self.font2, - SIZE * 2, f'历史最高积分: {loaded_data}')
            self.centre_text(self.screen, self.font2, - SIZE * 4, f'当前积分: {self.score}')

    def save_results(self):
        """
        替换历史最高分
        应该重开时或者关闭时引用
        """
        # 从文件加载变量
        try:
            with open('max_results.pkl', 'rb') as file:
                loaded_data = pickle.load(file)  # 获取历史成绩
        except:
            loaded_data = 0

        if self.score >= loaded_data:  # 覆盖第一次历史最高分
            # 替换历史最高分
            with open('max_results.pkl', 'wb') as file:
                pickle.dump(self.score, file)

    def help(self):
        """
        展示操作说明
        """
        """
            w,s,a,d/上下左右 控制移动方向
            回车键  开始/重开  
            空格键 暂停/取消暂停
        """
        # 展示操作说明
        self.centre_text(self.screen, self.font2, -SIZE * 4, '回车键:开始/重开')
        self.centre_text(self.screen, self.font2, -SIZE * 2, '空格键:暂停/取消暂停')
        self.centre_text(self.screen, self.font2, 0, 'w,s,a,d/上下左右:控制移动方向')

    def main(self):
        """
        运行主窗口
        """
        while True:
            self.init_settings()  # 初始化界面
            self.countdown()  # 时间倒计时
            self.control()  # 玩家操作


if __name__ == '__main__':
    try:
        a = GAME()
        a.main()
    except Exception as e:
        # 处理异常的代码
        print(f"异常: {e}")

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虫虫仙人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值