大家小时候都玩过贪吃蛇吧? 小编小时候可喜欢拿爸妈的手机玩了, 厉害着呢! 今天, 小编就来用 100 行代码实现一个简易版的贪吃蛇.
在网上, 贪吃蛇教程蛮多的, 但要安装蛮多库的, 而且也不够清晰, 今天的代码比较短, 而且理解起来或者说你更改起来要简单一些.
最终会实现效果如下:
image
基本准备
首先, 我们需要安装 pygame 库, 小编通过 pip install pygame, 很快就安装好了. 在完成贪吃蛇小游戏的时候, 我们需要知道整个游戏分为四部分:
游戏显示: 游戏界面, 结束界面
贪吃蛇: 头部, 身体, 食物判断, 死亡判断
树莓: 随机生成
按键控制: 上, 下, 左, 右
游戏显示
首先, 我们来初始化 pygame, 定义颜色, 游戏界面的窗口大小, 标题和图标等.
- # 初始化 pygame
- pygame.init()
- fpsClock = pygame.time.Clock()
- # 创建 pygame 显示层
- playSurface = pygame.display.set_mode((600,460))# 窗口大小
- pygame.display.set_caption('Snake Game')# 窗口名称
- # 定义颜色变量
- redColour = pygame.Color(255,0,0)
- blackColour = pygame.Color(0,0,0)
- whiteColour = pygame.Color(255,255,255)
- greyColour = pygame.Color(150,150,150)
游戏结束界面, 我们会显示 "Game Over!" 和该局游戏所得分数, 相关代码如下:
- # 定义 gameOver 函数
- def gameOver(playSurface,score):
- gameOverFont = pygame.font.SysFont('arial.ttf',54) #游戏结束字体和大小
- gameOverSurf = gameOverFont.render('Game Over!', True, greyColour) #游戏结束内容显示
- gameOverRect = gameOverSurf.get_rect()
- gameOverRect.midtop = (300, 10) #显示位置
- playSurface.blit(gameOverSurf, gameOverRect)
- scoreFont = pygame.font.SysFont('arial.ttf',54) #得分情况显示
- scoreSurf = scoreFont.render('Score:'+str(score), True, greyColour)
- scoreRect = scoreSurf.get_rect()
- scoreRect.midtop = (300, 50)
- playSurface.blit(scoreSurf, scoreRect)
- pygame.display.flip() #刷新显示界面
- time.sleep(5) #休眠五秒钟自动退出界面
- pygame.quit()
- sys.exit()
贪吃蛇和树莓
我们需要将整个界面看成许多 20*20 的小方块, 每个方块代表一个单位, 蛇的长度用单位来表示, 同时我们采用列表的形式存储蛇的身体. 同时, 我们都知道, 树莓的位置是随机的. 所以, 我们需要让树莓出现的位置是游戏界面中的随机位置, 同时, 每吃到一颗树莓, 就需要重新生成一颗新的树莓, 并且得分加 1.
相关初始化设置如下:
- snakePosition = [100,100] #贪吃蛇 蛇头的位置
- snakeSegments = [[100,100]] #贪吃蛇 蛇的身体, 初始为一个单位
- raspberryPosition = [300,300] #树莓的初始位置
- raspberrySpawned = 1 #树莓的个数为 1
- direction = 'right' #初始方向为右
- changeDirection = direction
- score = 0 #初始得分
如何控制贪吃蛇的运动轨迹呢, 那么就需要按键控制了. 我们通过键盘的↑↓←→和 WSAD 来控制, 如果想直接退出游戏, 则可以通过 Esc 键. 这里需要强调的是, 贪吃蛇里面是不能反方向运动, 因此, 我们需要进一步的增加限制条件:
- # 检测例如按键等 pygame 事件
- for event in pygame.event.get():
- if event.type == QUIT:
- pygame.quit()
- sys.exit()
- elif event.type == KEYDOWN:
- # 判断键盘事件
- if event.key == K_RIGHT or event.key == ord('d'):
- changeDirection = 'right'
- if event.key == K_LEFT or event.key == ord('a'):
- changeDirection = 'left'
- if event.key == K_UP or event.key == ord('w'):
- changeDirection = 'up'
- if event.key == K_DOWN or event.key == ord('s'):
- changeDirection = 'down'
- if event.key == K_ESCAPE:
- pygame.event.post(pygame.event.Event(QUIT))
- # 判断是否输入了反方向
- if changeDirection == 'right' and not direction == 'left':
- direction = changeDirection
- if changeDirection == 'left' and not direction == 'right':
- direction = changeDirection
- if changeDirection == 'up' and not direction == 'down':
- direction = changeDirection
- if changeDirection == 'down' and not direction == 'up':
- direction = changeDirection
方向设置好了, 那么贪吃蛇蛇身变换怎么做啊? 很简单, 我们只需要根据方向变换一下坐标即可.
- # 根据方向移动蛇头的坐标
- if direction == 'right':
- snakePosition[0] += 20
- if direction == 'left':
- snakePosition[0] -= 20
- if direction == 'up':
- snakePosition[1] -= 20
- if direction == 'down':
- snakePosition[1] += 20
- # 增加蛇的长度
- snakeSegments.insert(0,list(snakePosition))
贪吃蛇游戏里面最重要的就是食物判断和死亡判断.
小编最近整理了一套 Python 学习教程, 有需要的小伙伴, 记得来小编的交流群: 556370268, 即可免费领取一套 Python 学习教程哦
image
首先是食物判断, 我们通过键盘按键来决定贪吃蛇的走向, 以便它能吃到树莓. 如何判断贪吃蛇有没有吃到树莓呢? 很简单, 如果贪吃蛇蛇头的位置和树莓的位置重合了, 也就是相同, 那么贪吃蛇就吃到树莓了, 否则没有. 同时, 一旦发生了树莓被吃的情况, 立刻重新随机生成一个新的树莓.
相关代码如下:
- # 判断是否吃掉了树莓
- if snakePosition[0] == raspberryPosition[0] and snakePosition[1] == raspberryPosition[1]:
- raspberrySpawned = 0
- else:
- snakeSegments.pop() #若没有吃掉树莓, 需将最后一单位的蛇身提出列表, 此处和蛇身移动时位置变换有关
- # 如果吃掉树莓, 则重新生成树莓
- if raspberrySpawned == 0:
- x = random.randrange(1,30) #和游戏界面大小相关
- y = random.randrange(1,23)
- raspberryPosition = [int(x*20),int(y*20)]
- raspberrySpawned = 1
- score += 1
死亡判断则分为两类情况, 一是触碰到了游戏界面的边界, 二是贪吃蛇触碰到了自己的身体. 一旦发生死亡, 则触发 gameover.
- # 判断是否死亡
- if snakePosition[0]> 600 or snakePosition[0] <0: #若超过左右边界, 触发 gameover
- gameOver(playSurface,score)
- if snakePosition[1]> 460 or snakePosition[1] <0: #若超过上下边界, 触发 gameover
- gameOver(playSurface,score)
- for snakeBody in snakeSegments[1:]: #若触碰到自己的身体, 触发 gameover
- if snakePosition[0] == snakeBody[0] and snakePosition[1] == snakeBody[1]:
- gameOver(playSurface,score)
贪吃蛇运动和吃掉树莓的过程中, 游戏界面需要不断更新. 同时, 我们设置了游戏速度.
- # 绘制 pygame 显示层
- playSurface.fill(blackColour) #蛇身为白色
- for position in snakeSegments:
- pygame.draw.rect(playSurface,whiteColour,Rect(position[0],position[1],20,20))
- pygame.draw.rect(playSurface,redColour,Rect(raspberryPosition[0], raspberryPosition[1],20,20))
- # 刷新 pygame 显示层
- pygame.display.flip()
- # 控制游戏速度
- fpsClock.tick(5)
至此, 我们就能完成一个贪吃蛇小游戏了. 赶紧去实验一下吧!
完整的代码如下:
- import pygame,sys,time,random
- from pygame.locals import *
- # 定义颜色变量
- redColour = pygame.Color(255,0,0)
- blackColour = pygame.Color(0,0,0)
- whiteColour = pygame.Color(255,255,255)
- greyColour = pygame.Color(150,150,150)
- def gameOver(playSurface,score):
- gameOverFont = pygame.font.SysFont('arial.ttf',54)
- gameOverSurf = gameOverFont.render('Game Over!', True, greyColour)
- gameOverRect = gameOverSurf.get_rect()
- gameOverRect.midtop = (300, 10)
- playSurface.blit(gameOverSurf, gameOverRect)
- scoreFont = pygame.font.SysFont('arial.ttf',54)
- scoreSurf = scoreFont.render('Score:'+str(score), True, greyColour)
- scoreRect = scoreSurf.get_rect()
- scoreRect.midtop = (300, 50)
- playSurface.blit(scoreSurf, scoreRect)
- pygame.display.flip()
- time.sleep(5)
- pygame.quit()
- sys.exit()
- def main():
- # 初始化 pygame
- pygame.init()
- fpsClock = pygame.time.Clock()
- # 创建 pygame 显示层
- playSurface = pygame.display.set_mode((600,460))
- pygame.display.set_caption('Snake Game')
- # 初始化变量
- snakePosition = [100,100] #贪吃蛇 蛇头的位置
- snakeSegments = [[100,100]] #贪吃蛇 蛇的身体, 初始为一个单位
- raspberryPosition = [300,300] #树莓的初始位置
- raspberrySpawned = 1 #树莓的个数为 1
- direction = 'right' #初始方向为右
- changeDirection = direction
- score = 0 #初始得分
- while True:
- # 检测例如按键等 pygame 事件
- for event in pygame.event.get():
- if event.type == QUIT:
- pygame.quit()
- sys.exit()
- elif event.type == KEYDOWN:
- # 判断键盘事件
- if event.key == K_RIGHT or event.key == ord('d'):
- changeDirection = 'right'
- if event.key == K_LEFT or event.key == ord('a'):
- changeDirection = 'left'
- if event.key == K_UP or event.key == ord('w'):
- changeDirection = 'up'
- if event.key == K_DOWN or event.key == ord('s'):
- changeDirection = 'down'
- if event.key == K_ESCAPE:
- pygame.event.post(pygame.event.Event(QUIT))
- # 判断是否输入了反方向
- if changeDirection == 'right' and not direction == 'left':
- direction = changeDirection
- if changeDirection == 'left' and not direction == 'right':
- direction = changeDirection
- if changeDirection == 'up' and not direction == 'down':
- direction = changeDirection
- if changeDirection == 'down' and not direction == 'up':
- direction = changeDirection
- # 根据方向移动蛇头的坐标
- if direction == 'right':
- snakePosition[0] += 20
- if direction == 'left':
- snakePosition[0] -= 20
- if direction == 'up':
- snakePosition[1] -= 20
- if direction == 'down':
- snakePosition[1] += 20
- # 增加蛇的长度
- snakeSegments.insert(0,list(snakePosition))
- # 判断是否吃掉了树莓
- if snakePosition[0] == raspberryPosition[0] and snakePosition[1] == raspberryPosition[1]:
- raspberrySpawned = 0
- else:
- snakeSegments.pop()
- # 如果吃掉树莓, 则重新生成树莓
- if raspberrySpawned == 0:
- x = random.randrange(1,30)
- y = random.randrange(1,23)
- raspberryPosition = [int(x*20),int(y*20)]
- raspberrySpawned = 1
- score += 1
- # 绘制 pygame 显示层
- playSurface.fill(blackColour)
- for position in snakeSegments:
- pygame.draw.rect(playSurface,whiteColour,Rect(position[0],position[1],20,20))
- pygame.draw.rect(playSurface,redColour,Rect(raspberryPosition[0], raspberryPosition[1],20,20))
- # 刷新 pygame 显示层
- pygame.display.flip()
- # 判断是否死亡
- if snakePosition[0]> 600 or snakePosition[0] <0:
- gameOver(playSurface,score)
- if snakePosition[1]> 460 or snakePosition[1] < 0:
- gameOver(playSurface,score)
- for snakeBody in snakeSegments[1:]:
- if snakePosition[0] == snakeBody[0] and snakePosition[1] == snakeBody[1]:
- gameOver(playSurface,score)
- # 控制游戏速度
- fpsClock.tick(5)
- if __name__ == "__main__":
来源: http://www.jianshu.com/p/56c069b7dd93