使用Pygame实现简单的贪吃蛇游戏

    技术2022-07-11  77

    简单贪吃蛇游戏的实现

    摘要引言背景意义实现的功能 系统结构实现代码block模块yard模块snake模块food模块main模块 实验结果总结和展望

    摘要

    本项目使用Pygame编写了一款贪吃蛇游戏,实现了键盘对蛇的移动控制、蛇吃下食物成长、食物的随机生成、当前分数和当前剩余目标的显示、最高分的存档记录、暂停游戏和继续游戏、游戏结束提示、重新开始游戏、结束游戏、背景音乐和音效的播放等功能。

    引言

    背景

    Pygame 是一个跨平台 Python 模块,专为电子游戏设计。包含图像、声音。创建在 SDL基础上,允许实时电子游戏研发而无需被低级语言,如 C语言或是更低级的汇编语言束缚。基于这样一个设想,所有需要的游戏功能和理念都完全简化位游戏逻辑本身,所有的资源结构都可以由高级语言提供,如Python。引用自此处

    本项目是通过使用Pygame模块,实现一款贪吃蛇游戏。

    意义

    在现在这种快节奏的生活中,偶尔也需要放松身心,贪吃蛇游戏是一款休闲小游戏,加上本游戏所具有的欢快愉悦的背景音乐和趣味的音效,可以让玩家从紧张的生活节奏中解放,得到放松。

    实现的功能

    1、使用键盘控制蛇的移动方向,长按按键可以使蛇加速移动

    w键或方向上键 → 蛇向上移动s键或方向下键 → 蛇向下移动a键或方向左键 → 蛇向左移动d键或方向右键 → 蛇向右移动

    2、随机位置生成食物 3、蛇吃下食物并成长 4、显示当前分数 5、显示当前剩余目标 6、对最高分的存档记录 7、点击暂停按钮或按下空格键暂停游戏或继续游戏 8、当蛇撞上墙壁或自身任何部位时,游戏失败 9、当达到目标时,游戏胜利 10、显示游戏结束界面 11、点击重新开始按钮或按下r键重新开始游戏 12、点击结束游戏按钮结束游戏 13、游戏进行中时,播放背景音乐 14、蛇吃下食物、蛇死亡或游戏胜利时,播放对应的音效

    系统结构

    本程序主要由main、block、yard、snake和food五个模块组成。其中main模块中有SnakeGame类,SnakeGame类主要由Yard类、Snake类和Food类组成,分别用于绘画院子、蛇和食物。而Yard、Snake和Food都由Block类组成,Block类用于绘画一个方形色块或圆形色块。

    实现代码

    block模块

    1、创建Block类,并做好初始化操作

    import pygame class Block(pygame.sprite.Sprite): def __init__(self, surface, rect, fill_color, border_color): super(Block, self).__init__() # 要绘制的目标surface self.__surface = surface # 要绘制的色块的填充色 self.__fill_color = fill_color # 要绘制的色块的边框色 self.__border_color = border_color # 当前色块的矩形信息 self.rect = pygame.Rect(rect)

    创建一个Block类,需要传入该色块要绘制的目标surface、要绘制的rect信息,rect信息包括了要绘制的X、Y坐标及绘制的长宽、色块要填充的颜色以及边框颜色。并对该色块的rect信息进行保存。 2、实现绘制方形色块的方法

    # 绘制色块 def draw(self): # 绘制色块 pygame.draw.rect(self.__surface, self.__fill_color, self.rect, 0) # # 绘制边框所需要的坐标点 points = [ # 上边框直线的首尾坐标点 (self.rect.left, self.rect.top), (self.rect.left + self.rect.width, self.rect.top), # 右边框直线的首尾坐标点 (self.rect.left + self.rect.width, self.rect.top), (self.rect.left + self.rect.width, self.rect.top + self.rect.height), # 下边框直线的首尾坐标点 (self.rect.left + self.rect.width, self.rect.top + self.rect.height), (self.rect.left, self.rect.top + self.rect.height) ] # 绘制边框 pygame.draw.polygon(self.__surface, self.__border_color, points, 1)

    先使用pygame中draw模块的rect()函数,通过传入的数据绘制一个填充色的色块,然后通过计算,得到该色块各个点的坐标,使用pygame中draw模块的polygon()函数,绘制一个闭合的四边形,充当该色块的边框。 也可以直接使用rect()函数绘制无填充的矩形,充当该色块的边框,如下:

    pygame.draw.rect(self.__surface, self.__border_color, self.rect, 1)

    但使用这种方式,重合的边会显得比较粗。 3、实现绘制圆形色块的方法

    # 绘制圆形色块 def draw_circle(self): # 绘制圆形色块 pygame.draw.circle(self.__surface, self.__fill_color, self.rect.center, self.rect.width // 2, 0) # 绘制圆形色块的边框 pygame.draw.circle(self.__surface, self.__border_color, self.rect.center, self.rect.width // 2, 1)

    先使用pygame中draw模块的circle()函数绘制填充色的圆形色块,再绘制无填充的圆形,充当该色块的边框。

    yard模块

    1、创建Yard类,并初始化

    import pygame import block class Yard(pygame.sprite.Sprite): def __init__(self, surface, block_size, rows, cols, position, color, border_color): super(Yard, self).__init__() # 院子的矩形信息 self.rect = pygame.Rect(position, (cols * block_size[0], rows * block_size[1])) # 保存院子里所有的色块 self.blocks = [] # 根据行列数依次创建每个色块并保存 for i in range(rows): for j in range(cols): # 计算每个色块的位置 x = position[0] + (j * block_size[0]) y = position[1] + (i * block_size[1]) rect = (x, y), block_size _block = block.Block(surface, rect, color, border_color) # 记录每个色块所在的行列号 _block.row = i _block.col = j # 保存每个色块 self.blocks.append(_block)

    创建一个Yard类,需要传入该院子要绘制的目标surface、要绘制的院子中一个色块的长宽、院子的行数、列数、绘制的X、Y坐标位置、绘制的色块要填充的颜色以及边框颜色。并对该院子的rect信息进行保存。通过传入的数据依次创建所有需要绘制的色块,并为每个色块设置所在的行列号信息,将所有创建的色块进行保存。 2、实现绘制院子的方法

    # 绘制院子 def draw(self): # 绘制每个色块 for _block in self.blocks: _block.draw()

    通过Block类的draw()方法,将创建的所有色块绘制出来。

    snake模块

    1、创建Snake类,定义表示蛇移动方向的静态变量,并初始化

    import pygame import block class Snake(pygame.sprite.Sprite): # 代表向上移动 DIR_UP = 1 # 代表向下移动 DIR_DOWN = 2 # 代表向左移动 DIR_LEFT = 3 # 代表向右移动 DIR_RIGHT = 4 def __init__(self, surface, yard, length, row, col, color): super(Snake, self).__init__() # 要绘制的目标surface self.__surface = surface # 要放入的院子 self.__yard = yard # 要绘制的蛇的颜色 self.__color = color # 蛇的移动方向 self.__dir = Snake.DIR_LEFT # 绘制蛇身的所有色块 self.blocks = [] # 保存每次移动前的最后一块蛇身 self.tail = None # 根据行列号找到要绘制的蛇身的坐标点 for _block in yard.blocks: if _block.row == row and _block.col == col: # 整个蛇身的色块 for i in range(length): rect = _block.rect.copy() rect.left += _block.rect.width * i # 创建一块蛇身的色块 b = block.Block(surface, rect, color, color) # 保存蛇身的所有色块 self.blocks.append(b) break

    创建一个Snake类,需要传入该蛇要绘制的目标surface、要放入的院子、蛇身的初始长度,蛇头在院子中的行号和列号、以及要绘制的颜色。并保存蛇当前的移动方向。保存每次移动前的最后一块蛇身的色块信息。通过计算,得到每块蛇身的色块信息,创建所有色块并保存。蛇身默认水平绘制。 2、实现绘制蛇的方法

    # 绘制蛇 def draw(self): # 绘制所有色块 for _block in self.blocks: _block.draw()

    通过Block类的draw()方法,将创建的所有色块绘制出来。 3、实现蛇移动的方法

    # 移动蛇 def move(self): snake_head = self.blocks[0] # 确定移动后蛇头的下一个位置 rect = snake_head.rect.copy() if self.__dir == Snake.DIR_UP: rect.top -= rect.height elif self.__dir == Snake.DIR_DOWN: rect.top += rect.height elif self.__dir == Snake.DIR_LEFT: rect.left -= rect.width else: rect.left += rect.width # 创建一个新的蛇头 _block = block.Block(self.__surface, rect, self.__color, self.__color) self.blocks.insert(0, _block) # 去掉最后一块蛇身,并保存 self.tail = self.blocks.pop()

    该方法实现了蛇在当前方向上的一次移动,通过当前蛇头的位置和移动的方向,得到此次移动后,蛇头的下一个位置,并创建新的蛇头,插入到保存蛇身所有色块的列表的第一个位置,使其成为新的蛇头,并去掉最后一块蛇身,以保证蛇的长度不变,对最后一块蛇身的信息进行保存。这样就能在视觉上呈现蛇在当前方向上移动了一个位置的效果。 4、实现蛇向各个方向移动的方法,修改蛇当前的移动方向

    # 向上移动 def move_up(self): self.__dir = Snake.DIR_UP # 向下移动 def move_down(self): self.__dir = Snake.DIR_DOWN # 向左移动 def move_left(self): self.__dir = Snake.DIR_LEFT # 向右移动 def move_right(self): self.__dir = Snake.DIR_RIGHT

    5、实现判断蛇是否吃到了食物的方法

    # 判断是否吃到了食物 def is_eat(self, _food): snake_head = self.blocks[0] if pygame.sprite.collide_rect(snake_head, _food): self.blocks.append(self.tail) return True return False

    通过pygame中sprite模块的collide_rect()函数,将蛇头和食物进行碰撞检测,如果碰撞了说明吃到了食物,并将本次移动应该去掉的最后一块蛇身添加上去,使蛇长度增加1。 6、实现判断蛇是否死亡的方法

    # 判断是否死亡 def is_dead(self): snake_head = self.blocks[0] # 检测是否碰壁 if snake_head.rect.left < self.__yard.rect.left or \ snake_head.rect.right > self.__yard.rect.right or \ snake_head.rect.top < self.__yard.rect.top or \ snake_head.rect.bottom > self.__yard.rect.bottom: # 碰壁后去掉蛇头,避免显示出蛇头撞出墙壁 # self.blocks.pop(0) return True # 深拷贝蛇的色块组 group = self.blocks.copy() # 取出蛇头 snake_head = group[0] group.remove(snake_head) # 检测蛇头与蛇身是否发生碰撞 if pygame.sprite.spritecollide(snake_head, group, False): return True return False

    先检测蛇头的位置,判断是否超出了院子的范围,如果是,说明蛇撞上了墙壁,然后通过pygame中sprite的spritecollide()函数,检测蛇头是否跟任一蛇身发生碰撞,如果是,说明蛇撞到了自己,以上两种情况,任意一个成立,都判定为蛇死亡,否则没有死亡。

    food模块

    1、创建Food类,并初始化

    import pygame import block class Food(pygame.sprite.Sprite): def __init__(self, surface, yard, row, col, color): super(Food, self).__init__() # 根据行列号找到要绘制的食物的坐标点 for _block in yard.blocks: if _block.row == row and _block.col == col: # 食物的矩形信息 self.rect = _block.rect.copy() break # 创建食物的色块 self.__block = block.Block(surface, self.rect, color, color)

    创建一个Food类,需要传入该食物要绘制的目标surface、要放入的院子、在院子中的行号、列号、要绘制的颜色。通过行列号得到该食物色块的信息,并创建色块。 2、实现绘制食物的方法

    # 绘制食物 def draw(self): self.__block.draw_circle()

    通过Block类的draw_circle()方法,将色块绘制出来。 3、实现判断当前食物是否位置合法的方法

    # 判断当前食物的位置是否非法 def is_invalid(self, _snake): return pygame.sprite.spritecollide(self, _snake.blocks, False)

    将食物与蛇的所有色块进行碰撞检测,如果发生碰撞则说明位置不合法,否则合法。

    main模块

    1、定义需要用到的颜色信息

    import pygame import sys from pygame.locals import * import traceback import yard import snake import food import random # 定义颜色 WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GRAY = (88, 87, 86)

    2、创建SnakeGame类,并定义静态变量

    class SnakeGame: # 游戏界面大小 SCREEN_SIZE = SCREEN_WIDTH, SCREEN_HEIGHT = (500, 800) # 背景颜色 BG_COLOR = GRAY # 块大小 BLOCK_SIZE = (30, 30) # 块行个数 ROWS = 20 # 块列个数 COLS = 15 # 蛇的初始长度 SNAKE_LENGTH = 3 # 蛇的出生位置(行列号) snake_row = (ROWS - 1) // 2 snake_col = (COLS - SNAKE_LENGTH) // 2 # 蛇的移动速度(越大越慢) SPEED = 30 # 吃到一个食物的得分 FOOD_POINT = 10 # 游戏胜利的目标食物个数 TARGET = ROWS * COLS - SNAKE_LENGTH

    3、进行初始化操作

    def __init__(self): # 初始化 pygame.init() pygame.mixer.init() # 创建界面 self.screen = pygame.display.set_mode(SnakeGame.SCREEN_SIZE) # 设置标题 pygame.display.set_caption("贪吃蛇") # 加载音乐音效 # 背景音 pygame.mixer.music.load("sounds/bgm.mp3") # 死亡音效 self.die_sound = pygame.mixer.Sound("sounds/die.wav") # 进食音效 self.eat_sound = pygame.mixer.Sound("sounds/eat.wav") # 胜利音效 self.victory_sound = pygame.mixer.Sound("sounds/victory.wav") # 加载字体 # 得分提示字体 self.score_font = pygame.font.Font("fonts/font.otf", 36) # 游戏提示字体 self.game_font = pygame.font.Font("fonts/font.otf", 64) # 游戏结束后分数提示字体 self.gg_score_font = pygame.font.Font("fonts/font.otf", 52) # 加载图片 # 未按下时暂停按钮图片 self.pause_nor_image = pygame.image.load("images/pause_nor.png").convert_alpha() # 按下时暂停按钮图片 self.pause_pressed_image = pygame.image.load("images/pause_pressed.png").convert_alpha() # 未按下时继续游戏按钮图片 self.resume_nor_image = pygame.image.load("images/resume_nor.png").convert_alpha() # 按下时继续游戏按钮图片 self.resume_pressed_image = pygame.image.load("images/resume_pressed.png").convert_alpha() # 重新开始按钮图片 self.restart_image = pygame.image.load("images/restart.png").convert_alpha() # 结束游戏按钮图片 self.game_over_image = pygame.image.load("images/game_over.png").convert_alpha() self.clock = pygame.time.Clock() # 院子位置 yard_position = (SnakeGame.SCREEN_WIDTH - SnakeGame.BLOCK_SIZE[0] * SnakeGame.COLS) // 2, \ (SnakeGame.SCREEN_HEIGHT - SnakeGame.BLOCK_SIZE[1] * SnakeGame.ROWS) // 2 + 30 # 创建院子 self._yard = yard.Yard(self.screen, SnakeGame.BLOCK_SIZE, SnakeGame.ROWS, SnakeGame.COLS, yard_position, RED, WHITE) self._snake = self._food = None # 暂停处当前显示的图片 self.paused_image = self.pause_nor_image # 暂停按钮的位置 self.paused_image_rect = self.paused_image.get_rect() self.paused_image_rect.left = self._yard.rect.right - self.paused_image_rect.width self.paused_image_rect.top = self._yard.rect.top - self.paused_image_rect.height * 2 # 重新开始按钮的矩阵信息 self.restart_image_rect = None # 结束游戏按钮的矩阵信息 self.game_over_image_rect = None self.step = self.is_gaming = self.is_dead = self.is_win = self.score = self.target = self.recorded = None

    先对pygame的模块进行初始化,然后创建游戏窗口,将需要用到的背景音乐和音效文件进行加载,加载需要用到的字体,加载需要用到的图片,并创建院子,设置当前在暂停游戏处要显示的图片。 4、实现生成食物的方法

    # 生成食物 def create_food(self): # 创建食物 self._food = food.Food(self.screen, self._yard, random.randint(0, SnakeGame.ROWS - 1), random.randint(0, SnakeGame.COLS - 1), WHITE) # 如果创建的是非法的则继续创建 while self._food.is_invalid(self._snake): self._food = food.Food(self.screen, self._yard, random.randint(0, SnakeGame.ROWS - 1), random.randint(0, SnakeGame.COLS - 1), WHITE)

    创建Food类的实例,并判断是否位置非法,如果非法则继续创建,直到创建出合法位置的食物为止。 5、实现初始化游戏数据的方法

    # 初始化游戏数据 def init_data(self): # 创建蛇 self._snake = snake.Snake(self.screen, self._yard, SnakeGame.SNAKE_LENGTH, SnakeGame.snake_row, SnakeGame.snake_col, BLACK) # 生成食物 self.create_food() # 标志是否需要进行下一次移动(值为0时进行移动) self.step = SnakeGame.SPEED # 标志是否处于游戏中 self.is_gaming = True # 是否死亡 self.is_dead = False # 是否游戏胜利 self.is_win = False # 统计得分 self.score = 0 # 统计剩余目标 self.target = SnakeGame.TARGET # 标志是否已经记录了得分 self.recorded = False

    创建蛇和食物的实例,并初始化一些游戏需要的数据。 6、实现判断是否游戏结束的方法

    # 判断是否游戏结束 def is_game_over(self): return self.is_win or self.is_dead

    当玩家达到目标赢了或者蛇死亡输了,均判定为游戏结束。 7、实现暂停或继续游戏的方法

    # 暂停或继续游戏 def pause_resume_game(self): if not self.is_game_over(): self.is_gaming = not self.is_gaming # 切换暂停游戏处的显示图片 self.paused_image = self.pause_nor_image if self.is_gaming else self.resume_nor_image # 暂停或继续播放背景音乐 if self.is_gaming: pygame.mixer.music.unpause() else: pygame.mixer.music.pause()

    当游戏还未结束时,将判定游戏是否正在进行的标志取反,然后将暂停游戏处的按钮图片修改为对应的图片,并暂停背景音乐或继续播放背景音乐。 8、实现重新开始游戏的方法

    # 重新开始游戏 def restart_game(self): self.init_data() # 暂停处当前显示的图片 self.paused_image = self.pause_nor_image # 重新播放背景音乐 pygame.mixer.music.play(-1)

    重新初始化游戏数据,设置暂停游戏处的按钮的图片,并重新开始播放背景音乐。 9、实现运行游戏的方法

    # 运行游戏 def run(self): # 播放背景音乐 pygame.mixer.music.play(-1) # 初始化游戏数据 self.init_data() while True: for event in pygame.event.get(): # 监听用户退出操作 if event.type == QUIT: pygame.quit() sys.exit() # 监听用户键盘按下 elif event.type == KEYDOWN: # 空格按键按下后,暂停游戏或继续游戏 if event.key == K_SPACE: self.pause_resume_game() # 按下r键,重新开始游戏 if event.key == K_r: self.restart_game() # 监听鼠标按键操作 elif event.type == MOUSEBUTTONDOWN: # 点击鼠标左键 if event.button == 1: # 点击暂停按钮时,暂停游戏或继续游戏 if self.paused_image_rect.collidepoint(event.pos): self.pause_resume_game() # 点击重新开始按钮 elif self.restart_image_rect and self.restart_image_rect.collidepoint(event.pos): # 避免游戏中误触 if self.is_game_over(): self.restart_game() # 点击结束游戏按钮,退出游戏 elif self.game_over_image_rect and self.game_over_image_rect.collidepoint(event.pos): # 避免游戏中误触 if self.is_game_over(): pygame.quit() sys.exit() # 监听鼠标移动操作 elif event.type == MOUSEMOTION: # 将暂停处的按钮切换成对应的图片 if self.paused_image_rect.collidepoint(event.pos): if self.is_gaming: self.paused_image = self.pause_pressed_image else: self.paused_image = self.resume_pressed_image else: if self.is_gaming: self.paused_image = self.pause_nor_image else: self.paused_image = self.resume_nor_image if self.is_gaming: # 监听用户的键盘操作 pressed = pygame.key.get_pressed() if pressed[K_w] or pressed[K_UP]: self.step -= 5 self._snake.move_up() if pressed[K_s] or pressed[K_DOWN]: self.step -= 5 self._snake.move_down() if pressed[K_a] or pressed[K_LEFT]: self.step -= 5 self._snake.move_left() if pressed[K_d] or pressed[K_RIGHT]: self.step -= 5 self._snake.move_right()

    先播放背景音乐,并初始化游戏数据,然后实现事件监听,对用户的键盘和鼠标操作进行监听,实现使用鼠标控制游戏的暂停和继续、重新开始游戏、结束游戏以及对暂停游戏处按钮图片的切换的操作,实现使用键盘对蛇进行控制、控制游戏的暂停和继续以及重新开始游戏的操作。当按下控制蛇移动的按键时,还会增加step变量的衰减幅度,如果一直按着就会持续对step变量的大幅度衰减,达到加速蛇的移动的效果。

    # 填充背景色 self.screen.fill(SnakeGame.BG_COLOR) # 游戏未结束时绘制 if not self.is_game_over(): # 绘制院子 self._yard.draw() # 绘制食物 self._food.draw() # 绘制蛇 self._snake.draw() # 绘制暂停按钮 self.screen.blit(self.paused_image, self.paused_image_rect) # 绘制得分 score_text = self.score_font.render("Score : %d" % self.score, True, WHITE) self.screen.blit(score_text, (self._yard.rect.left, 20)) # 绘制剩余目标提示 target_text = self.score_font.render("Target : %d" % self.target, True, WHITE) self.screen.blit(target_text, (self._yard.rect.left, score_text.get_rect().height + 40))

    然后对游戏的元素进行绘制。

    # 移动蛇,每SPEED帧移动一次 if self.is_gaming and self.step <= 0: # 移动一次蛇的位置 self._snake.move() # 判断是否吃到食物 if self._snake.is_eat(self._food): self.create_food() self.score += SnakeGame.FOOD_POINT self.target -= 1 # 播放音效 self.eat_sound.play() # 判断蛇是否死亡 if self._snake.is_dead(): self.is_gaming = False self.is_dead = True # 播放音效 self.die_sound.play() # 淡出结束背景音乐 pygame.mixer.music.fadeout(1000) # 判断是否游戏胜利 if self.target == 0: self.is_gaming = False self.is_win = True # 播放音效 self.victory_sound.play() # 淡出结束背景音乐 pygame.mixer.music.fadeout(1000) self.step = SnakeGame.SPEED else: self.step -= 1

    然后使蛇进行移动,通过step变量确定是否要让蛇进行一次移动,当step为0的时候进行一次移动,否则使step递减。当蛇发生一次移动时,判断蛇是否吃到食物、是否死亡或者是否游戏胜利,并进行相应的操作,播放对应的音效。

    # 绘制游戏提示 if not self.is_gaming: # 设置游戏提示内容 if self.is_game_over(): game_text = "GAME OVER!" if not self.is_win else "YOU WIN!" else: game_text = "PAUSED" # 创建用于游戏提示的文字surface game_text_surface = self.game_font.render(game_text, True, WHITE) # 游戏提示显示位置 game_text_x = self._yard.rect.left + (self._yard.rect.width - game_text_surface.get_rect().width) // 2 game_text_y = self._yard.rect.top + (self._yard.rect.height - game_text_surface.get_rect().height) // 2 # 显示游戏提示 self.screen.blit(game_text_surface, (game_text_x, game_text_y))

    绘制游戏提示,包括游戏暂停、游戏失败或游戏胜利时的提示。

    # 记录最高分并绘制游戏结束界面 if self.is_game_over(): # 判断是否已经记录了分数 if not self.recorded: self.recorded = True # 读取历史最高分数 try: with open("record.txt", "r") as f: record_score = int(f.read()) except FileNotFoundError: record_score = 0 # 如果本局游戏玩家得分超过历史最高分,则存档记录 if self.score >= record_score: with open("record.txt", "w") as f: f.write(str(self.score)) f.close()

    当游戏结束时,读取最高分记录,如果玩家分数超过历史最高分,则记录本次玩家分数为最高分。

    # 绘制历史最高分数 best_text = self.score_font.render("Best : %d" % record_score, True, WHITE) self.screen.blit(best_text, (self._yard.rect.left, target_text.get_rect().height * 2 + 60)) # 绘制当前得分 your_score_tip_text = self.gg_score_font.render("Your Score", True, WHITE) your_score_text = self.gg_score_font.render(str(self.score), True, WHITE) # 当前得分提示信息显示位置 tip_text_x = self._yard.rect.left + (self._yard.rect.width - your_score_tip_text.get_rect().width) // 2 tip_text_y = game_text_y - 180 self.screen.blit(your_score_tip_text, (tip_text_x, tip_text_y)) # 当前得分显示位置 score_text_x = self._yard.rect.left + ( self._yard.rect.width - your_score_text.get_rect().width) // 2 score_text_y = game_text_y - 90 self.screen.blit(your_score_text, (score_text_x, score_text_y)) # 绘制重新开始按钮 self.restart_image_rect = self.restart_image.get_rect() self.restart_image_rect.left = self._yard.rect.left + ( self._yard.rect.width - self.restart_image_rect.width) // 2 self.restart_image_rect.top = game_text_y + game_text_surface.get_rect().height + 60 self.screen.blit(self.restart_image, self.restart_image_rect) # 绘制结束游戏按钮 self.game_over_image_rect = self.game_over_image.get_rect() self.game_over_image_rect.left = self._yard.rect.left + ( self._yard.rect.width - self.game_over_image_rect.width) // 2 self.game_over_image_rect.top = self.restart_image_rect.bottom + 20 self.screen.blit(self.game_over_image, self.game_over_image_rect)

    当游戏结束时,绘制游戏结束界面。

    pygame.display.flip() # 设定帧率 self.clock.tick(60)

    刷新双缓冲,并设置游戏帧率。 10、运行游戏

    if __name__ == '__main__': try: snake_game = SnakeGame() snake_game.run() except SystemExit: pass except: traceback.print_exc() input()

    当此模块被运行时,创建SnakeGame实例,并调用run()方法运行游戏。

    实验结果

    1、游戏进行中界面 2、游戏暂停界面 3、游戏结束界面

    总结和展望

    本次实验实现了一个基本功能比较完善的贪吃蛇游戏,但是还有一些待改进的地方,如: 1、 判断蛇是否吃到食物的逻辑应该跟蛇成长的逻辑分开,当判定蛇吃到了食物之后,再进行蛇的成长。 2、 对文件的操作可以放大到整个程序运行的过程中,而不是结束一局游戏就操作一次。刚开始运行游戏的时候就从文件中读取历史最高分记录,将该记录保存在全局变量中,每次结束一局游戏时,将本次得分跟该全局变量进行比较,将该全局变量的值修改为当前的最高分,作为新的历史最高分记录,在退出游戏时,将该分数保存到文件中。 而且还有一些扩展的功能没有实现,如: 1、 游戏开始界面的显示 2、 游戏难度的选择 3、 声音的打开和关闭 4、 增加一些经典玩法没有的元素,如隔离墙、随机道具等。

    Processed: 0.013, SQL: 9