• Python实战练习_贪吃蛇 (pygame的初次使用)


    正如标题所写的那样,我将一步步的完成本次实战练习——贪吃蛇。废话不多说,感兴趣的伙伴可以一同挑战一下。

    首先说明本次实战中我的配备:

    开发环境: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()
  • 相关阅读:
    Python基础笔记
    Oracle PL/SQL学习之Hello World(0)
    编程开发之--Oracle数据库--存储过程在out参数中使用光标(3)
    编程开发之--Oracle数据库--存储过程和存储函数(2)
    编程开发之--Oracle数据库--存储过程和存储函数(1)
    火车票售票系统
    MySQL 字段内容区分大小写
    json_encode($b, JSON_FORCE_OBJECT) 可以强制转换成对象
    Sublime Text3配置
    springboot-配置多个数据源
  • 原文地址:https://www.cnblogs.com/lyy135146/p/11523670.html
Copyright © 2020-2023  润新知