1.引言
我们python的基本知识已经学习得差不多了,老师说其实python强大的地方除了它的简便和灵活外,还有很多的模块供以使用。通过了解,我对python中的pygame模块产生了好奇心。接下来就是利用这个模块,对经典小游戏贪吃蛇进行解析和实现。
2.前期准备
游戏规则:游戏中,玩家将化作一条单一方向移动的蛇,通过控制上下左右四个方向,获取随机出现的食物,增长自身长度,如果在游戏过程中,触碰四周墙壁或者嘴巴与自己的身体有接触,则游戏结束。
关键词:
(1) 单一方向移动。
(2) 方向控制。
(3) 食物随机出现。
(4) 吃掉食物增长蛇的长度。
(5) 死亡(游戏结束)条件。
除此之外我们还需要对游戏环境,游戏窗口以及对其操作,游戏画面设计等进行编写实现。
3.代码实现
(1) 先编写main函数大概构造出代码纲领。
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT
#初始化
pygame.init()
#时钟
FPSCLOCK = pygame.time.Clock()
#显示窗口大小
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
#字体
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
#窗口名字
pygame.display.set_caption('Snake')
showStartScreen()
while True:
runGame()
showGameOverScreen()
在此设置了一些比如时钟、游戏窗口大小、窗口名字等基本信息,还编写了在游戏程序的运行经过——简单开场之后进入循环,循环游戏主体以及游戏结束收场。
接下来完善showStartScreen()、runGame()和showGameOverScreen()三个游戏运行过程函数的内容。
(2) 为了方便规划设计与画图,把窗口划分成相对于像素来说更大的单位。
#窗口大小
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
#基本单位
CELLSIZE = 20
CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
(3) 对showStartScreen()与showGameOverScreen()的编写(他们是一样的设计元素):
应该实现的功能:
(1)开场有游戏的标题snake,结束有游戏的状态gameover。
(2)有操作提示语句
(3)完成操作之后进入游戏
图1 showStartScreen()函数效果图
实现功能(1)需要包括如下类型的代码:
title = pygame.font.Font('freesansbold.ttf', 150) #字体
gameSurf = title.render('Snake', True, WHITE) #内容
gameRect = gameSurf.get_rect()
gameRect.midtop = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2 - 100) #位置
DISPLAYSURF.blit(gameSurf, gameRect)
实现功能(2)也是如此,但是因为这个’Press a key to play.'提示语句也需要出现在结束的页面,所以写了个函数。代码如下:
def drawPressKeyMsg():
pressKeySurf = BASICFONT.render('Press a key to play.', True, WHITE)
pressKeyRect = pressKeySurf.get_rect()
pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
功能(3)即实现对窗口的关闭和键盘输入任意一个非退出的按键进入游戏主体。代码如下:
def checkForKeyPress():
if len(pygame.event.get(QUIT)) > 0:
pygame.quit()
sys.exit()
keyUpEvents = pygame.event.get(KEYUP)
if len(keyUpEvents) == 0:
return None
if keyUpEvents[0].key == K_ESCAPE:
pygame.quit()
sys.exit()
return keyUpEvents[0].key
(4) 对runGame()的编写:
在这个环节,我们需要一条蛇和一个苹果。随机出现。哈的的度度和法法,以及苹果随机出现一个。
在这个游戏的主体部分,我们需要随机出现一个食物和一条长度为3的蛇,蛇需要一直在一个方向移动。
代码如下:
#随机生成蛇的位置(有范围:防止开场撞墙死亡)
snakex = random.randrange(5, CELLWIDTH - 6)
snakey = random.randrange(5, CELLHEIGHT - 6)
#蛇的长度
snake = [{'x': snakex, 'y': snakey},
{'x': snakex - 1, 'y': snakey},
{'x': snakex - 2, 'y': snakey}]
#蛇的方向
direction = 'right'
#随机生成食物的位置
food={'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
接下来进行游戏的主循环部分:
① 外部输入——退出游戏和按键部分
for event in pygame.event.get():
# 如果单击关闭窗口,则退出
if event.type == pygame.QUIT:
sys.exit()
elif event.type == KEYDOWN:
# 判断键盘事件,用w,s,a,d或者上下左右键来表示上下左右,esc按键退出
if event.key == K_RIGHT or event.key == ord('d')and not direction == 'left':
direction = "right"
if event.key == K_LEFT or event.key == ord('a')and not direction == 'right':
direction = "left"
if event.key == K_UP or event.key == ord('w')and not direction == 'down':
direction = "up"
if event.key == K_DOWN or event.key == ord('s')and not direction == 'up':
direction = "down"
if event.key == K_ESCAPE:
pygame.event.post(pygame.event.Event(QUIT))
② 详细逻辑
按键使得蛇的方向改变,路径改变的时候如果蛇头与食物的坐标相同,则判断为贪吃蛇吃掉了食物。吃了一个食物的蛇,蛇身增长一个单位;没有吃到食物的蛇,蛇身的长度不变。
通过时间的流逝,对蛇进行新增一个蛇头的操作,接着判断是否吃了食物。如果没有吃到食物,对刚刚新增蛇头的蛇进行去除蛇尾一个单位的操作;如果吃到了食物,则保持不变。
图2 贪吃蛇移动与吃食物时身体变化解析
尝试写出如下代码:
#蛇的移动:时间流逝使得新增了一个蛇头位置,整条蛇身+1,后面根据判断是否吃了食物进行-1
if direction == 'up':
newHead = {'x': snake[0]['x'], 'y': snake[0]['y'] - 1}
elif direction == 'down':
newHead = {'x': snake[0]['x'], 'y': snake[0]['y'] + 1}
elif direction == 'left':
newHead = {'x': snake[0]['x'] - 1, 'y': snake[0]['y']}
elif direction == 'right':
newHead = {'x': snake[0]['x'] + 1, 'y': snake[0]['y']}
snake.insert(0, newHead)
#判断吃食物,根据上面的代码,蛇的移动蛇身+1,则在此环节如果吃了食物,保持不变,没吃即要-1
if snake[0]['x'] == food['x'] and snake[0]['y'] == food['y']:
# 随机生成新的苹果
food={'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
else:
# 尾巴-1个格子
del snake[-1]
③ 判断游戏结束——撞到墙或者蛇吃到了自己的身体。
#游戏被动结束情况
if snake[0]['x'] == -1 or snake[0]['x'] == CELLWIDTH or\
snake[0]['y'] == -1 or snake[0]['y'] == CELLHEIGHT:
return #进入游戏结束画面,原因:蛇撞到墙
for snakeBody in snake[1:]:
if snakeBody['x'] == snake[0]['x'] and snakeBody['y'] == snake[0]['y']:
return #进入游戏结束画面,原因:蛇吃到自己
④ 显示画面
#基本显示
DISPLAYSURF.fill(BLACK)
#食物
pygame.draw.rect(DISPLAYSURF, RED, pygame.Rect(food['x'] * CELLSIZE, food['y'] * CELLSIZE, CELLSIZE, CELLSIZE))
#蛇
for each in snake:
x = each['x'] * CELLSIZE
y = each['y'] * CELLSIZE
pygame.draw.rect(DISPLAYSURF, GREEN, pygame.Rect(x, y, CELLSIZE, CELLSIZE))
⑤ 刷新
#刷新
pygame.display.update()
FPSCLOCK.tick(15)
代码下载地址:
见博客评论区博主留言
参考文献:
[1]https://www.jianshu.com/p/8ddeb797d1be
[2]https://inventwithpython.com/wormy.py