摘要 本次论文设计的主题是贪吃蛇游戏。游戏的主要内容大致分为游戏界面设计和游戏功能设计两大部分,其中游戏界面设计是以满足用户的视觉体验为主,游戏功能设计是在满足原有的贪吃蛇游戏基本功能的基础上添加一些其他的功能。本次的实现代码也较为简洁,总共170行左右,运用了Python的一些函数库和模块库,其中最主要的是pygame模块。
1.引言 1.1背景、意义 现如今,人们的生活节奏日益加快,繁忙冗杂的工作、学习和生活使人们的生活变得枯燥,没有新意,休息时间越来越少。面对这样的生活,人们大都渴望在这仅有的休息时间里,找到一些能让身心放松的娱乐活动。于是,贪吃蛇这款游戏就进入了大众的视野。 1997年,诺基亚工程师Taneli Armanto为诺基亚N6610手机写了一款贪吃蛇程序,命名为Snake,中译贪吃蛇。而后,在我们更加熟悉的诺基亚3310等机型上安装了升级版的SnakeII。2000年,诺基亚重写了程序Snake EX,安装在同年发行的诺基亚9200上。近十年来,贪吃蛇游戏以各种形式出现在各大游戏网站,模式新颖,层出不穷,吸引了数以亿计的游戏爱好者前来游玩。2016年,《贪吃蛇大作战》横空出世,火爆一时。同年腾讯游戏退出《疯狂贪吃蛇》网络游戏,下载量居高不下。如此种种,使得贪吃蛇游戏成为国内外游戏史上传播最广泛的作品之一。 1.2相关研究、功能介绍 本次的贪吃蛇游戏主要是仿照前人开发的源代码进行设计的,该游戏拥有和普通贪吃蛇一样的基本功能,主要就是在屏幕区域内绘制出一条小蛇,并且在与蛇不重合的屏幕区域内随机出现一个食物,游戏者通过键盘操纵游戏小蛇上下左右移动来吃到食物,当食物成功被小蛇吃到后,会在另外的区域重新刷新出食物,而小蛇由于吃到食物,身体会增长。除此之外,本游戏的贪吃蛇可以通过吃不同颜色的食物增加不同的分数,同时,分数每增加100,速度也会随之增加1。 1.3开发工具 本次游戏的开发平台为windows7(64位),程序设计语言为Python,程序运行环境为Python3.5。
2.系统结构 2.1系统结构图 图1系统结构图 2.11画面设计 ①游戏的界面构造主要包括游戏运行界面尺寸的定义、背景幕布的覆盖以及墙壁的添加等。 ②贪吃蛇的构造主要是蛇身的构造,具有贪吃蛇的大部分功能,例如移动、变换方向、碰撞、吃食物等,随着贪吃蛇不断吃到食物,蛇的身体会不断增加。 ③食物的构造主要是食物随机刷新在界面内,且不与蛇身重合,与蛇头触碰后会消失,并在其他区域重新生成,蛇吃到不同颜色的食物将得到不同的得分 2.12游戏过程 ①贪吃蛇必须从蛇的头部开始移动,所以蛇不能反方向移动。也就是尾巴不能变成蛇头。如果你不按任何键,蛇就会以当前的方向向前移动。当玩家按下有效的箭头键时,蛇头按指定的方向移动,一次移动身体一部分。所以当按下有效的箭头键时,首先要确定蛇头的位置,然后身体随着蛇头移动,实现图形就是蛇头从新的位置开始画一条蛇,此时,由于没有清屏,程序在不停地更新屏幕,原来的蛇差了一个单元,看起来蛇的身体会多一部分,所以蛇的最后一部分被覆盖了背景颜色,使贪吃蛇看起来好像是在到处移动。 ②碰撞检测包含两种情况:第一种是蛇头和墙壁的碰撞,第二种是蛇头和蛇身的碰撞。 2.13游戏结束 当蛇头与墙壁或自己的身体发生碰撞时会死亡,这时候游戏进程停止,画面显示GAME OVER。 2.14添加功能 ①设置不同颜色的食物,给不同颜色的食物设置不同的分数,贪吃蛇吃到不同颜色的食物就会增加相应的分数。 ②贪吃蛇每得到100分,速度就加快1。 ③在游戏设计中添加常规功能。 2.2主要函数及模块 2.21主要模块 表1贪吃蛇主要模块
模块作用pygamePython内置模块,游戏设计模块sys系统相关的信息模块random生成随机数time时间模块,控制游戏帧频collections调用deque双向队列形成贪吃蛇2.22主要函数 表2贪吃蛇主要函数
函数作用Main()主函数,控制游戏的所有进程print_text()绘制界面幕布init_snake()初始化贪吃蛇create_food()初始化食物get_food_style()吃到食物事件pygame.display.set_caption()定义屏幕窗口的标题内容pygame.font.SysFont()从系统内加载字体pygame.event.get()键盘点击事件screen.fill()填充窗口的背景色pygame.draw.line()画网格线time.time()获取当前时间pygame.display.update()把我们绘制的东西显示在屏幕上3.实现代码 3.1初始框架 在制作游戏之前基本工作都是要初始化框架。首先是导入游戏设计模块pygame并初始化该模块,然后设置框架的宽度和高度,用pygame.display.set_mode()函数初始化准备显示的窗口,再用pygame.display.set_caption()函数给这个窗口添加标题。代码如下:
python import pygame SCREEN_WIDTH = 600 # 屏幕宽度 SCREEN_HEIGHT = 480 # 屏幕高度 pygame.init() #初始化模块 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) #显示窗口 pygame.display.set_caption('贪吃蛇')效果图如下: 3.2初始游戏画布 有了游戏框架之后,要在框架里面初始游戏画布。首先要设置小方格的大小以及网格线的宽度,然后设置游戏区域的坐标范围,再设置网格线的颜色以及画布的背景颜色,接着用screen.fill()函数填充背景颜色,用pygame.draw.line()函数绘制网格线,最后用pygame.display.update()函数将我们绘制的东西显示在屏幕上。代码如下:
SIZE = 20 # 小方格大小 LINE_WIDTH = 1 # 网格线宽度 #游戏区域坐标范围 SCOPE_X = (0, SCREEN_WIDTH // SIZE - 1) SCOPE_Y = (2, SCREEN_HEIGHT // SIZE - 1) BLACK = (0, 0, 0) # 网格线颜色 BGCOLOR = (40, 40, 60) # 背景色 screen.fill(BGCOLOR) # 填充背景色 #画网格线 竖线 for x in range(SIZE, SCREEN_WIDTH, SIZE): pygame.draw.line(screen, BLACK, (x, SCOPE_Y[0] * SIZE), (x, SCREEN_HEIGHT), LINE_WIDTH) #画网格线 横线 for y in range(SCOPE_Y[0] * SIZE, SCREEN_HEIGHT, SIZE): pygame.draw.line(screen, BLACK, (0, y), (SCREEN_WIDTH, y), LINE_WIDTH) pygame.display.update() #显示绘制的东西效果图如下: 3.3构建贪吃蛇 初始化完游戏画布后要给画布添加贪吃蛇。首先要导入必要的一些模块,如监听键盘控制的sys模块,监听时间的time模块,构成贪吃蛇的collections模块中的deque()以及pygame模块中的各种常量。代码如下:
import sys import time from pygame.locals import * from collections import deque然后先初始化蛇,包括蛇的颜色和蛇的初始长度。代码如下: DARK = (200, 200, 200) # 蛇的颜色 #初始化蛇
def init_snake(): snake = deque() snake.append((2, SCOPE_Y[0])) snake.append((1, SCOPE_Y[0])) snake.append((0, SCOPE_Y[0])) return snake然后是贪吃蛇方向的控制,这里采用pygame中的键盘监听事件,代码如下:
while True: for event in pygame.event.get(): if event.type == QUIT: sys.exit() elif event.type == KEYDOWN: if event.key == K_RETURN: if game_over: start = True game_over = False b = True snake = init_snake() pos = (1, 0) # 得分 score = 0 last_move_time = time.time() elif event.key == K_SPACE: if not game_over: pause = not pause elif event.key in (K_w, K_UP): # 这个判断是为了防止蛇向上移时按了向下键,导致直接 GAME OVER if b and not pos[1]: pos = (0, -1) b = False elif event.key in (K_s, K_DOWN): if b and not pos[1]: pos = (0, 1) b = False elif event.key in (K_a, K_LEFT): if b and not pos[0]: pos = (-1, 0) b = False elif event.key in (K_d, K_RIGHT): if b and not pos[0]: pos = (1, 0) b = False接着是给画布添加蛇的速度和得分文本框,代码如下:
def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): imgText = font.render(text, True, fcolor) screen.blit(imgText, (x, y)) font1 = pygame.font.SysFont('SimHei', 24) # 得分的字体 score = 0 # 得分 print_text(screen, font1, 30, 7, '速度:'+str(score//100)) print_text(screen, font1, 450, 7, '得分:'+str(score))最后用time模块模拟贪吃蛇的移动,代码如下:
orispeed = 0.5 # 原始速度 speed = orispeed last_move_time = None curTime = time.time() if curTime - last_move_time > speed: if not pause: b = True last_move_time = curTime next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1]) 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 snake: snake.appendleft(next_s) #将下一格的坐标添加到列表开头 snake.pop() #移除最后一个元素效果图如下: 3.4构建食物 首先要导入random模块用于随机生成食物的位置,然后设置食物的颜色和分值,再初始化食物,最后判断蛇是否吃到食物,如果吃到食物就随机生成新的食物,代码如下:
import random #用于生成随机数 #食物的分值及颜色 FOOD_STYLE_LIST = [(10, (255, 100, 100)), (20, (100, 255, 100)), (30, (100, 100, 255))] def create_food(snake): food_x = random.randint(SCOPE_X[0], SCOPE_X[1]) food_y = random.randint(SCOPE_Y[0], SCOPE_Y[1]) while (food_x, food_y) in snake: # 如果食物出现在蛇身上,则重来 food_x = random.randint(SCOPE_X[0], SCOPE_X[1]) food_y = random.randint(SCOPE_Y[0], SCOPE_Y[1]) return food_x, food_y def get_food_style(): return FOOD_STYLE_LIST[random.randint(0, 2)] next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1]) if next_s == food: # 吃到了食物 snake.appendleft(next_s) score += food_style[0] speed = orispeed - 0.03 * (score // 100) food = create_food(snake) food_style = get_food_style() #画食物 if not game_over: pygame.draw.rect(screen, food_style[1], (food[0] * SIZE, food[1] * SIZE, SIZE, SIZE), 0)3.5碰撞检测 当贪吃蛇撞到自己或者墙壁后无法继续向前移动时进程停止,游戏结束,显示GAME OVER! 代码如下:
font2 = pygame.font.Font(None, 72) # GAME OVER 的字体 fwidth, fheight = font2.size('GAME OVER') game_over = True start = False # 是否开始,当start = True,game_over = True 时,才显示 GAME OVER if not game_over: curTime = time.time() if curTime - last_move_time > speed: if not pause: b = True last_move_time = curTime next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1]) if next_s == food: # 吃到了食物 snake.appendleft(next_s) score += food_style[0] speed = orispeed - 0.03 * (score // 100) food = create_food(snake) food_style = get_food_style() 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 snake: snake.appendleft(next_s) snake.pop() else: game_over = True if game_over: if start: print_text(screen, font2, (SCREEN_WIDTH - fwidth) // 2, (SCREEN_HEIGHT - fheight) // 2, 'GAME OVER', RED)效果图如下:
4.实验结果 5.总结和展望 本次实验过程中也是遇到了许多的问题,比如一些模块的功能函数等,不过,通过较长时间的翻阅查找也研究清楚了代码的实现原理。该游戏还有一些不足之处就是未能实现高分榜等功能,总的来说还是收获满满。