Python实战练习_贪吃蛇 (pygame的初次使用)
2019-09-15 18:23 鲁尧尧 阅读(2379) 评论(2) 编辑 收藏 举报正如标题所写的那样,我将一步步的完成本次实战练习——贪吃蛇。废话不多说,感兴趣的伙伴可以一同挑战一下。
首先说明本次实战中我的配备:
开发环境:python 3.7;
开发工具:pycharm2019.2.2;
开发模块:pygame;
首先在本次开发中,我们要借用一下pygame模块,那么问题来了,什么是pygame模块?有什么用?
pygame 是包含图像、声音建立在SDL基础上,允许实时电子游戏研发而无需被低级语言(如机器语言和汇编语言)束缚。
基于这样一个设想,所有需要的游戏功能和理念都(主要是图像方面)都完全简化为游戏逻辑本身,所有的资源结构都可以由高级语言提供,如Python。
我个人理解 pygame是一个简化2d游戏开发的开发模块。
本次开发的第一步便是装载pygame,具体方法如下
1.通过在python文件中 打开命令提示 输入对应代码
2.pycharm软件 可以通过设置内,添加新模块
确保安装完成可以在命令提示符中打开python 输入 import pygame检测 如下所示
有需要的话,可以通过留言,我在下一期博客中专门做一个pygame安装教程。
接下来便是我们的开发之旅:
首先展示一下我们的效果图,由一个个大小为20*20的方块儿组成的贪吃蛇游戏
1.调用python开发环境,包括pygame、sys、random。
# python 运行时的环境
import pygame, sys, random
2.调用pygame相关常量、还有配置颜色。
# 这个模块包含所有pygame所使用的常量 from pygame.locals import * # 定义颜色变量 # 目标方块儿红颜色 redColor = pygame.Color(255, 0, 0) # 背景颜色为黑色 blackColor = pygame.Color(0, 0, 0) # 蛇颜色为白色 whiteColor = pygame.Color(255, 255, 255)
3.定义游戏结束的函数 主要包含两部分操作,第一部分为pygame结束,第二部分为sys结束。
# 定义游戏结束
def gameOver():
pygame.quit()
sys.exit()
4.有了前面的铺垫,我们可以正式开始设计我们的游戏,我将游戏内容存放到main函数中。
4.1初始化pygame,设定变量来控制蛇的速度,然后制作一个界面,界面的大小为640*480,界面标题为贪吃蛇。
其中界面大小是必须设定的,贪吃蛇游戏的规则之一便是不能触及边界,但界面的标题是可以不写的,界面标题默认为python文件名
特别注意pygame.display.set_mode()函数中需要插入为两项序列而不是整数型 所以参数应为(640, 480)
具体代码如下
def main(): # 初始化pygame pygame.init() # 定义一个变量 控制速度 fpsClock = pygame.time.Clock() # 创建一个窗口界面,界面大小为640*480 playSurface = pygame.display.set_mode((640, 480))
# 界面标题为“贪吃蛇” 可不写,默认为python文件名 pygame.display.set_caption('贪吃蛇')
4.2设定目标方块
目标方块是由计算机随机生成的,但在那之前需要我们手动设定一个初值,同时设定一个target_flag来判断目标方块是否被贪吃蛇 “吃” 掉
# 初始化目标方块的位置 targetPosition = [300, 300] # 目标方块标记 判断贪吃蛇是否吃掉目标方块 1为没吃掉 0为吃掉 targetFlag = 1
4.3设定贪吃蛇的相关属性
初始化蛇需要注意什么?首先蛇的位置,其次蛇的长度,最后便是蛇的方向。那么一步步来实现
我们可以将蛇看做两部分组成组成,蛇头和蛇身。蛇身只要不断跟随蛇头便可,蛇头需要用来判断贪吃蛇的前进方向、是否结束游戏、是否 “吃” 掉目标方块儿等等
我们设定蛇头以(100, 100)为基准,蛇为水平方向放置,并且向右前进,所以蛇身的第一部分 应等于蛇头的’“Y”值,而“X”应当减去一个方块儿的位置,也就是减少20,贪吃蛇第一块应当是(80, 100)
设定存在方向的变量direction,初始方向向右,也需要设定改变方向的变量changedirection,令changedirection == direction
所写代码如下
# 初始化贪吃蛇的位置 (100,100)为基准 # 初始化贪吃蛇长度 列表中有几个元素 就有几个身体 snake_head = [100, 100] snake_body = [[80, 100], [60, 100]] # 初始化方向 默认为右 direction = 'right' # 定义一个认为控制的方向的变量 changedirection = direction
4.4需要贪吃蛇动起来
特别说明 pygame的所有事件全都在一个实时循环中
由于操作比较简单,鼠标操作的便只有一个,点击右上角的叉叉关闭游戏,但键盘上的操作相对比较多 包括↑↓←→,控制蛇的移动,esc退出游戏
所以首先要判断发生的事件类型是点击QUIT ,又或者是KEYDOWN
QUIT不必说,游戏结束之前上面也有描述 pygame.quit() 与sys.exit()
KEYDOWN 就需要判断是上下左右的哪一个,发生按键要使得蛇的移动方向发生改变,所以changedirection 需要发生变动,更改为按键方向。
# pygame 所有事件全部放到一个实时循环中 while True: # 从队列中获取事件 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: if event.key == K_RIGHT: changedirection = 'right' if event.key == K_LEFT: changedirection = 'left' if event.key == K_UP: changedirection = 'up' if event.key == K_DOWN: changedirection = 'down' if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT))
蛇的移动方向由direction决定,按键改变的是changedirection,所以我们需要将changedirection的值赋予direction
众所周知,贪吃蛇是不可以走回头路的,也就是说当贪吃蛇向右移动,按左键是没哟效果的
所以在将changedirection的值赋予direction 之前 还需要判断两个值是否相反
# 确定方向 if changedirection == 'left' and not direction == 'right': direction = changedirection if changedirection == 'right' and not direction == 'left': direction = changedirection if changedirection == 'up' and not direction == 'down': direction = changedirection if changedirection == 'down' and not direction == 'up': direction = changedirection
4.5贪吃蛇转弯
就像上文提到的那样,蛇身是跟着蛇头运动,所以转弯实际上是改变蛇头的位置。
将蛇身与蛇头分开来写相对来说这时候比较占优势,只要改变蛇头snake_head的位置信息就可以。
并不是说蛇头和蛇身必须分开写,也可以放在一起,我们只需要多写一步 提取蛇的第一个方块信息就可以了
那么问题来了,怎么改变蛇头位置信息才能达到转弯的效果?
我们以蛇在向右移动,这时按↓键为例
蛇头这时候应当向下移动一个方块的位置,也就是说这时候蛇头的“X”不发生改变,“Y”值增加一个方块的数值,也就是20
同理可得蛇头向上等操作的方法,注意snake_head是一个数组 ,snake_head[0]即为“X” snake_head[1]即为“Y”
代码如下
# 根据方向移动蛇头 if direction == 'right': snake_head[0] += 20 if direction == 'left': snake_head[0] -= 20 if direction == 'up': snake_head[1] -= 20 if direction == 'down': snake_head[1] += 20
4.5贪吃蛇吃方块
贪吃蛇游戏的目的便是控制贪吃蛇“吃”掉方块儿,那么怎样来实现呢?
首先蛇的嘴巴长在蛇头上,所以蛇吃掉方块需要用到蛇头的位置信息。
其次目标方块儿存放在指定位置,所以当蛇头的位置信息等于目标方块儿的位置信息即可
位置信息包含x与y,所以当蛇头x=目标方块儿x,并且蛇头y=目标方块儿y时,我们便认定贪吃蛇吃了方块
之前设定判断目标方块的状态变量 targetflag便起到作用,1表示没吃,0表示吃了,所以targetflag从1变成了0
# 如果贪吃蛇位置和目标方块位置重合 if snake_head[0] == targetPosition[0] and snake_head[1] == targetPosition[1]: targetFlag = 0 else: snake_body.pop()
4.6重新生成新的目标方块
当判断目标方块儿被吃了,也就是说targetflag=0时,系统需要重新生成一个新的目标方块。
目标方块的设定相对来说比较简单,只需要生成一个新的位置信息并将targetflag=1即可。
目标方块将会出现在一个随机的位置,所以我们在这里需要引入一个随机数,这也是为什么刚开始开发游戏时,需要import random
由于一个方块的大小为20*20,游戏界面为640*480,所以x的取值范围只有(20/20, 640/20)即为(1, 32)
同理可得y的取值范围应当是(1,24) 所以随机生成的目标方块儿位置信息应当为(x*20, y*20)
输入的位置信息应当为整数类型,所以还需要加强转,代码如下
if targetFlag == 0: x = random.randrange(1, 32) y = random.randrange(1, 24) targetPosition = [int(x * 20), int(y * 20)] targetFlag = 1
5.界面生成
写到这里,游戏的规则基本完成,接下来我们需要“画”出我们的界面
首先给自己的游戏界面填充为黑色,借用playSurface.fill()函数,将黑色的参数传入
之后就是画我们的贪吃蛇,用for循环画每一部分的身子,利用pygame中draw所带的Rect函数来绘画方块 rect函数需要传四个参数
第一个为surface,需要制定一个surface编辑区域
第二个为color,即绘画的颜色,这个很好理解
第三个为rect,rect为绘画矩形,需要提供矩形的位置,长度,宽度
第四个为width,这并不代表宽度,而是特指线条的粗细, width=0实心,width=1空心 ,一般可以不传入,默认为0
然后便是画目标方块,原理如上所示,但不需要用到for循环,毕竟就一个目标方块儿
最后开启实时更新界面
# 填充背景颜色 playSurface.fill(blackColor) for position in snake_body: # rect函数内 # 第一个参数surface 指定一个surface编辑区 # 第二个参数color 指定颜色 # 第三个参数rect 返回一个矩形包含位置信息(x,y),(width,height) # 第四个参数width 表示线条的粗细 width=0 实心 width=1 空心 # 画蛇 pygame.draw.rect(playSurface, whiteColor, Rect(position[0], position[1], 20, 20)) # 画目标方块儿 pygame.draw.rect(playSurface, redColor, Rect(targetPosition[0], targetPosition[1], 20, 20)) # 更新显示到屏幕 pygame.display.flip()
6.游戏结束条件
当贪吃蛇撞击到边界时便会触发游戏结束,也就是蛇头的位置超过了预定的640*480的界面,这时候游戏结束
# 判断游戏结束 if snake_head[0] > 620 or snake_head[0] < 0: gameOver() if snake_head[1] > 460 or snake_head[1] < 0: gameOver()
7.调控难度
调控难度主要是更改贪吃蛇的速度,之前有设定贪吃蛇速度的变量,这时候我们只要加以修改即可,个人比较手残,开三挡即可,有兴趣的小伙伴可以尝试下更高的难度
# 控制游戏速度 fpsClock.tick(3)
8.开启游戏,启动main函数
# 启动入口 main函数 if __name__ == '__main__': main()
至此就开发完成了一个简单的像素贪吃蛇,下面便是游戏最终效果
由于种种原因,最后有些地方没来得及改进,所以也算给诸位留下一些难题。
过段时间我会重新更新更加完善、更加丰富的贪吃蛇项目
改进方案:
1.可以加入分数体系,在每次吃到目标方块儿后分数加一,最终在结束后呈现给玩家
2.贪吃蛇游戏结束条件:蛇头碰到自己身体,游戏结束未实现
3.界面过于简单,可以制作一个简单的游戏开始界面,或者在游戏结束后创建一个排名榜,重来一次等
4.部分代码跨度较大 显得冗长,建议精简重新构建框架
最后显示源代码,以供各位参考
# python 运行时的环境 import pygame, sys, random # 这个模块包含所有pygame所使用的常量 from pygame.locals import * # 定义颜色变量 # 目标方块儿红颜色 redColor = pygame.Color(255, 0, 0) # 背景颜色为黑色 blackColor = pygame.Color(0, 0, 0) # 蛇颜色为白色 whiteColor = pygame.Color(255, 255, 255) # 定义游戏结束 def gameOver(): pygame.quit() sys.exit() # 定义main函数 定义入口函数 def main(): # 初始化pygame pygame.init() # 定义一个变量 控制速度 fpsClock = pygame.time.Clock() # 创建一个窗口界面 playSurface = pygame.display.set_mode((640, 480)) pygame.display.set_caption('贪吃蛇') # 初始化目标方块的位置 targetPosition = [300, 300] # 目标方块标记 判断贪吃蛇是否吃掉目标方块 1为没吃掉 0为吃掉 targetFlag = 1 # 初始化贪吃蛇的位置 (100,100)为基准 # 初始化贪吃蛇长度 列表中有几个元素 就有几个身体 snake_head = [100, 100] snake_body = [[80, 100], [60, 100]] # 初始化方向 默认为右 direction = 'right' # 定义一个认为控制的方向的变量 changedirection = direction # pygame 所有事件全部放到一个实时循环中 while True: # 从队列中获取事件 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: if event.key == K_RIGHT: changedirection = 'right' if event.key == K_LEFT: changedirection = 'left' if event.key == K_UP: changedirection = 'up' if event.key == K_DOWN: changedirection = 'down' if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT)) # 确定方向 if changedirection == 'left' and not direction == 'right': direction = changedirection if changedirection == 'right' and not direction == 'left': direction = changedirection if changedirection == 'up' and not direction == 'down': direction = changedirection if changedirection == 'down' and not direction == 'up': direction = changedirection # 根据方向移动蛇头 if direction == 'right': snake_head[0] += 20 if direction == 'left': snake_head[0] -= 20 if direction == 'up': snake_head[1] -= 20 if direction == 'down': snake_head[1] += 20 # 增加蛇的长度 snake_body.insert(0, list(snake_head)) # 如果贪吃蛇位置和目标方块位置重合 if snake_head[0] == targetPosition[0] and snake_head[1] == targetPosition[1]: targetFlag = 0 else: snake_body.pop() if targetFlag == 0: x = random.randrange(1, 32) y = random.randrange(1, 24) targetPosition = [int(x * 20), int(y * 20)] targetFlag = 1 # 填充背景颜色 playSurface.fill(blackColor) for position in snake_body: # rect函数内 # 第一个参数surface 指定一个surface编辑区 # 第二个参数color 指定颜色 # 第三个参数rect 返回一个矩形包含位置信息(x,y),(width,height) # 第四个参数width 表示线条的粗细 width=0 实心 width=1 空心 # 画蛇 pygame.draw.rect(playSurface, whiteColor, Rect(position[0], position[1], 20, 20)) # 画目标方块儿 pygame.draw.rect(playSurface, redColor, Rect(targetPosition[0], targetPosition[1], 20, 20)) # 更新显示到屏幕 pygame.display.flip() # 判断游戏结束 if snake_head[0] > 620 or snake_head[0] < 0: gameOver() if snake_head[1] > 460 or snake_head[1] < 0: gameOver() # 控制游戏速度 fpsClock.tick(3) # 启动入口 main函数 if __name__ == '__main__': main()