强化学习Agent系列(一)——PyGame游戏编程,Python 贪吃蛇制作实战教学

简介: 本文是关于使用Pygame库开发Python贪吃蛇游戏的实战教学,介绍了Pygame的基本使用、窗口初始化、事件处理、键盘控制移动、以及实现游戏逻辑和对象交互的方法。

强化学习Agent系列(一)——PyGame游戏编程,Python 贪吃蛇制作实战教学

文章目录

  • 强化学习Agent系列(一)——PyGame游戏编程,Python 贪吃蛇制作实战教学
  • 一、前言
    • 1、pygame介绍
    • 2、 安装Pygame
    • 3. Pygame常用模块
  • 二、pygame 入门
    • 1、窗口初始化与事件初认识
    • 2、创建绿色方块并键盘移动
    • 3、控制绿色方块吃掉红色果子
    • 4、控制绿色方块吃掉红色果子,身体长度加一节
  • 三、pygame初级

一、前言

大家好,未来的开发者们请上座
随着人工智能的发展,强化学习基本会再次来到人们眼前,遂想制作一下相关的教程。强化学习第一步基本离不开虚拟环境的搭建,下面用大家耳熟能详的贪吃蛇游戏为基础,制作一个Agent,完成对这个游戏的绝杀。
万里长城第一步:用python开发贪吃蛇游戏

1、pygame介绍

用Python进行游戏开发的首选模块就是PyGame。
pygame 是一个流行的跨平台Python模块,专为电子游戏设计,包含图像、声音等,创建在SDL(Simple DirectMedia Layer)基础上,允许实时电子游戏研发而不会被低级语言,如C语言或是更低级的汇编语言束缚。基于这样一个设想,所有需要的游戏功能和理念(主要是图像方面)都完全简化为游戏逻辑本身,所有的资源结构都可以由高级语言(如Python)提供。它提供了一套丰富的功能,使得游戏开发者可以轻松地创建图形、动画、音效和游戏逻辑。

以下是 pygame 的一些关键特性
注:不需要特地去记,一开始只需要知道pygame有哪些关键特性,哪些功能他可以实现即可。

  1. 显示
    pygame 提供了一种简单的方式来创建和管理游戏窗口以及渲染图形。
    它支持多种图像格式,包括 BMP、JPG、PNG、GIF 等。
  2. 事件
    pygame 有一个事件系统,可以处理键盘、鼠标、游戏手柄等输入设备的事件。
    开发者可以轻松地查询和响应用户的交互。
  3. 图形
    pygame 提供了基本的2D图形绘制功能,包括线条、形状、图像渲染等。
    它也支持图像的变换,如缩放、旋转和翻转。
  4. 音效和音乐
    pygame 可以播放音效和音乐文件,支持多种音频格式。
    它提供了音量控制、播放控制等基本的音频操作。
  5. 精灵
    pygame 的精灵(Sprite)系统可以帮助管理游戏中的对象。
    精灵类可以用来表示游戏中的每一个元素,如角色、物品等。
  6. 时钟
    pygame 的时钟(Clock)功能可以帮助控制游戏的帧率,确保游戏以均匀的速度运行。
  7. 碰撞检测
    pygame 提供了简单的碰撞检测功能,可以检测两个元素是否相互接触或重叠。
  8. 字体和文本
    pygame 支持字体渲染,可以在游戏中显示文本。
  9. 跨平台
    pygame 可以运行在多种操作系统上,包括 Windows、Mac OS X 和 Linux。
    安装 pygame 通常很简单,只需使用 pip 命令即可:

2、 安装Pygame

pip install pygame

一旦安装了 pygame,你就可以开始创建游戏窗口、加载图像、处理用户输入和创建游戏逻辑了。pygame 的社区活跃,有大量的教程和文档可供学习,这使得即使是编程新手也能够开始他们的游戏开发之旅。

3. Pygame常用模块

Pygame做游戏开发的优势在于不需要过多地考虑底层相关的内容,可以把工作中心放在游戏逻辑上。例如,PyGame中集成了很多和底层相关的模块,如访问显示设备、管理事件、使用字体等。

Pygame常用模块如下:

模块名 功能
pygame.display 访问显示设备。
pygame.draw 绘制形状、线和点。
pygame.event 管理事件。
pygame.font 使用字体。
pygame.image 加载和存储图片。
pygame.key 读取键盘按键。
pygame.mixer 声音。
pygame.mouse 鼠标。
pygame.movie 播放视频。
pygame.music 播放音乐。
pygame.rect 管理矩形区域。
pygame.sndarray 操作声音数据。
pygame.sprite 操作移动图像。
pygame.surface 管理图像和屏幕。
pygame.surfarray 管理点阵图像数据。
pygame.time 管理时间和帧信息。
pygame.transform 缩放和移动图像。

二、pygame 入门

1、窗口初始化与事件初认识

使用Pygame的display模块和event模块创建一个PyGame窗口,代码结构主要分三部分:

  1. 模块导入
  2. pygame窗口初始化
  3. 游戏主体

初始化涉及到的pygame与sys函数:

模块名 功能
pygame.init() 初始化所有的pygame模块,使用其他模块之前基本一定要调用init方法
pygame.display.set_mode() 初始化窗口的宽高,并返回游戏屏幕(后续对象都需要画到游戏屏幕上)
pygame.display.set_caption() 初始化窗口的名字
pygame.event.get() 键盘、鼠标、手柄 事件响应
pygame.QUIT 点击窗口右上角红X的事件
sys.exit() 程序退出
pygame.quit() 程序终止前调用,卸载所有pygame模块
# -*- coding: utf-8 -*-
# 一、模块导入
import sys         # 导入sys模块
import pygame       # 导入pygame模块

# 二、pygame窗口初始化
pygame.init()                           # 初始化pygame
size = width, height = 320, 240         # 设置窗口尺寸
screen = pygame.display.set_mode(size)  # 显示窗口
# 设置标题
pygame.display.set_caption('窗口初始化测试')

# 三、游戏主体
# 执行死循环,确保窗口一直显示,同时监听关闭按钮事件
while True:
    # 检查事件
    for event in pygame.event.get():    # 遍历所有事件
        if event.type == pygame.QUIT:     # 如果单击关闭按钮
            pygame.quit()       # 卸载所有pygame模块
            sys.exit()          # 终止当前程序

运行结果如下:
在这里插入图片描述
这样子你就创建了一个窗口,点击关闭按钮,程序捕捉到pygame.QUIT事件,pygame.quit()卸载完pygame模块后,运行 sys.exit() 退出程序。

这样子就开始了基于pygame制作游戏的第一步。窗口初始化

2、创建绿色方块并键盘移动

涉及到游戏基本就离不开控制角色移动,遂就将其当做第二课
运行结果如下:
在这里插入图片描述

该课程涉及到的pygame函数(不重复上一课学习到的了):

模块名 功能
pygame.time.Clock() 创建时钟对象,用于控制屏幕绘制速度 – 刷新频率
clock.tick(60) 时钟对象(一定要放在整个游戏循环最后,不然会起不到稳定控制游戏刷新速度的效果),设置频率为60。如果你的游戏逻辑和渲染非常快,tick 方法将会使程序暂停,以保持 60 FPS 的速度,如果速度慢于60则不会等待
pygame.key.get_pressed() 获取当前全部键盘key的状态,没按下的按钮值为False,按下的按钮值为True
screen.fill() 快捷填充背景色
pygame.draw.rect() 绘制矩阵(游戏屏幕,颜色,矩阵(x,y,width,height),width(矩阵粗细,没有则填充整个矩阵))
pygame.display.update() 更新屏幕画面

注:额外知识点补充游戏中的坐标系:

在这里插入图片描述
具体的逻辑代码如下
使用Pygame的创建绿色方块并键盘移动,代码结构主要分三部分:

  1. 模块导入
  2. pygame窗口初始化
  3. 游戏主体
    3. 1 游戏内对象初始化
    3. 2 监听按键、鼠标事件并设置事件内容,修改方块位置
    3. 3 依据方块的位置宽高,重新渲染画面和方块
# -*- coding: utf-8 -*-
# 一、模块导入
import sys         # 导入sys模块
import pygame       # 导入pygame模块

# 二、pygame窗口初始化
pygame.init()                           # 初始化pygame
size = width, height = 320, 240         # 设置窗口尺寸
screen = pygame.display.set_mode(size)  # 显示窗口
# 设置标题
pygame.display.set_caption('创建绿色方块并键盘移动')

# 三、游戏主体
# 执行死循环,确保窗口一直显示,同时监听关闭按钮事件

## 3.1 游戏内对象初始化
# 设置矩阵的属性
rect_color = (0, 255, 0)  # 绿色
rect_len = 20  # 矩阵的边长
rect_pos = [width // 2, height // 2]  # 矩阵的初始位置
rect_speed = [2, 2]  # 矩阵的速度

# 定义时钟对象
clock = pygame.time.Clock()

while True:
    # 3.2 监听按键、鼠标事件并设置事件内容,修改方块的值
    # 检查事件
    for event in pygame.event.get():    # 遍历所有事件
        if event.type == pygame.QUIT:     # 如果单击关闭按钮
            pygame.quit()       # 卸载所有pygame模块
            sys.exit()          # 终止当前程序

    # 检查按键,并对上下左右每一个按键,绑定事件
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        rect_pos[0] -= rect_speed[0]
    if keys[pygame.K_RIGHT]:
        rect_pos[0] += rect_speed[0]
    if keys[pygame.K_UP]:
        rect_pos[1] -= rect_speed[1]
    if keys[pygame.K_DOWN]:
        rect_pos[1] += rect_speed[1]

    # 3.3 依据方块的位置宽高,重新渲染画面和方块
    #确保方块不会移出屏幕
    rect_pos[0]=max(0,min(width-rect_len,rect_pos[0]))
    rect_pos[1]=max(0,min(height-rect_len,rect_pos[1]))

    # 填充背景色(每次用黑色的背景覆盖掉旧有的画面)
    screen.fill((0,0,0))

    #画矩阵
    pygame.draw.rect(screen,rect_color,(*rect_pos,rect_len,rect_len))

    # 更新屏幕
    pygame.display.update()

    # 控制游戏刷新速度
    clock.tick(60)

上述代码中,添加了键盘事件检测。pygame.key.get_pressed()能够获取键盘状态,查询目标按钮的状态并添加相应的事件,如:

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        rect_pos[0] -= rect_speed[0]
    if keys[pygame.K_RIGHT]:
        rect_pos[0] += rect_speed[0]
    if keys[pygame.K_UP]:
        rect_pos[1] -= rect_speed[1]
    if keys[pygame.K_DOWN]:
        rect_pos[1] += rect_speed[1]

如果按下left,则rect的x值减少,按下right,则rect的x值增加。如果按下up,则y值减少,按下down,y值增加。具体对应关系可参考上面的pygame中的游戏坐标系进行理解

3、控制绿色方块吃掉红色果子

游戏基本一定会涉及到游戏内物体的交互,一个游戏的玩法核心就是交互,在设计游戏玩法的时候,各位帅哥美女们可以参考下面,设计一下交互规则。

创建交互规则如下:

  • 1、玩家控制绿色方块移动
  • 2、如果地图中没有红色果子,在地图任意位置,随机生成一个果子
  • 3、绿色方块的位置与红色果子位置一致时,红色果子刷新位置

具体的逻辑代码如下
初始化随机生成一个果子的位置,并渲染出来
当二者左上角的位置距离<8 px的时候,果子刷新位置

请添加图片描述
该课程涉及到的pygame函数(不重复上一课学习到的了):

模块名 功能
random.randint(0, 30) 随机从0到30这31个数抽一个数
np.linalg.norm(3,4)= 5 求一个向量的长度,与sqrt(pow(x, 2) + pow(y, 2))等价
*迭代对象(比如程序中的:*foodPosition) 列表解包,比如:将foodPosition拆成零散的变量,而不是之前的元组

额外补充知识:
在这里插入图片描述

具体代码如下:

# -*- coding: utf-8 -*-
# 一、模块导入
import sys  # 导入sys模块
import pygame  # 导入pygame模块
import random  # 导入random模块
import numpy as np
# 二、pygame窗口初始化
pygame.init()  # 初始化pygame
size = width, height = 320, 240  # 设置窗口尺寸
screen = pygame.display.set_mode(size)  # 显示窗口
# 设置标题
pygame.display.set_caption('3、控制绿色方块吃掉红色果子')

# 三、游戏主体
# 执行死循环,确保窗口一直显示,同时监听关闭按钮事件

## 3.1 游戏内对象初始化
# 设置矩阵的属性
rect_color = (0, 255, 0)  # 绿色
rect_len = 20  # 矩阵的边长
rect_pos = [width // 2, height // 2]  # 矩阵的初始位置
rect_speed = [2, 2]  # 矩阵的速度

# 设置果子的初始属性
food_color = (255,0,0 )  # 果子颜色:红色
food_len = 15           # 果子大小:15像素
foodPosition = (random.randint(0, width - 30) , random.randint(0, height - 30) ) # 果子的初始位置

# 定义时钟对象
clock = pygame.time.Clock()

while True:
    # 3.2 监听按键、鼠标事件并设置事件内容,修改方块的值
    # 检查事件
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭按钮
            pygame.quit()  # 卸载所有pygame模块
            sys.exit()  # 终止当前程序

    # 检查按键,并对上下左右每一个按键,绑定事件
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        rect_pos[0] -= rect_speed[0]
    if keys[pygame.K_RIGHT]:
        rect_pos[0] += rect_speed[0]
    if keys[pygame.K_UP]:
        rect_pos[1] -= rect_speed[1]
    if keys[pygame.K_DOWN]:
        rect_pos[1] += rect_speed[1]

    if np.linalg.norm((rect_pos[0]-foodPosition[0],rect_pos[1]-foodPosition[1]))<8:
        foodPosition = (random.randint(0, width - 30) , random.randint(0, height - 30) ) # 果子的初始位置
    # 3.3 依据方块的位置宽高,重新渲染画面和方块
    # 确保方块不会移出屏幕
    rect_pos[0] = max(0, min(width - rect_len, rect_pos[0]))
    rect_pos[1] = max(0, min(height - rect_len, rect_pos[1]))

    # 填充背景色(每次用黑色的背景覆盖掉旧有的画面)
    screen.fill((0, 0, 0))

    # 画果子
    pygame.draw.rect(screen, food_color, (*foodPosition, food_len, food_len))

    # 画矩阵
    pygame.draw.rect(screen, rect_color, (*rect_pos, rect_len, rect_len))

    # 更新屏幕
    pygame.display.update()

    # 控制游戏刷新速度
    clock.tick(60)

4、控制绿色方块吃掉红色果子,身体长度加一节

定义游戏名字:贪吃蛇
创建交互规则如下:

  • 1、玩家控制绿色蛇移动
  • 2、如果地图中没有红色果子,在地图任意位置,随机生成一个果子
  • 3、绿色方块的位置与红色果子位置一致时,蛇身长度长一节
  • 4、绿色方块的位置与红色果子位置一致时,红色果子刷新位置

翻译成代码逻辑:

初始化随机生成一个果子的位置,并渲染出来
蛇吃果子代码逻辑:当二者重叠超过百分之七十时候,果子刷新位置
蛇移动代码原理:每次在监听键盘,如果有移动操作导致头部发生改变,那么在新的位置绘制一个矩形,并插入蛇的身体列表开头做为新的头部。
如果这一步没有吃到果子则弹出尾巴,有就不弹出。
在这里插入图片描述

该课程涉及到的pygame函数(不重复上一课学习到的了):

模块名 功能
pygame.Rect(x,y,width,height) 生成pygame中的Rect对象(后面碰撞检测会用到)
rect1.clip(rect2) 求两个Rect对象的重叠矩阵

代码逻辑如下:

# -*- coding: utf-8 -*-
# 一、模块导入
import sys  # 导入sys模块
import pygame  # 导入pygame模块
import random  # 导入random模块
import numpy as np

# 二、pygame窗口初始化
pygame.init()  # 初始化pygame
size = width, height = 320, 240  # 设置窗口尺寸
screen = pygame.display.set_mode(size)  # 显示窗口
# 设置标题
pygame.display.set_caption('3、控制绿色方块吃掉红色果子')

# 三、游戏主体
# 执行死循环,确保窗口一直显示,同时监听关闭按钮事件

## 3.1 游戏内对象初始化
# 设置矩阵的属性
rect_color = (0, 255, 0)  # 绿色
rect_len = 20  # 矩阵的边长
snake_len = 3
body0 = pygame.Rect(width // 2, height // 2, rect_len, rect_len)  # 矩形
rect_snake_body = [body0]  # 矩阵的初始位置

rect_speed = [2, 2]  # 矩阵的速度

# 设置果子的初始属性
food_color = (255, 0, 0)  # 果子颜色:红色
food_len = 15  # 果子大小:15像素
foodPosition = (random.randint(0, width - 30), random.randint(0, height - 30))  # 果子的初始位置
food_body = pygame.Rect(*foodPosition, food_len, food_len)

# 定义时钟对象
clock = pygame.time.Clock()

while True:
    # 3.2 监听按键、鼠标事件并设置事件内容,修改方块的值
    # 检查事件
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭按钮
            pygame.quit()  # 卸载所有pygame模块
            sys.exit()  # 终止当前程序

    rect_pos = [rect_snake_body[0].x, rect_snake_body[0].y]
    # 检查按键,并对上下左右每一个按键,绑定事件
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        rect_pos[0] -= rect_speed[0]
    if keys[pygame.K_RIGHT]:
        rect_pos[0] += rect_speed[0]
    if keys[pygame.K_UP]:
        rect_pos[1] -= rect_speed[1]
    if keys[pygame.K_DOWN]:
        rect_pos[1] += rect_speed[1]

    # 3.3 根据上一步的数值变化进行,二次处理处理功能:1、不会移出屏幕。2、吃掉果子。3、蛇身移动
    # 1、确保蛇不会移出屏幕
    rect_pos[0] = max(0, min(width - rect_len, rect_pos[0]))
    rect_pos[1] = max(0, min(height - rect_len, rect_pos[1]))

    # 2、吃掉果子逻辑
    overRect = food_body.clip(rect_snake_body[0])
    if overRect.width * overRect.height >= food_body.width * food_body.height * 0.7:
        foodPosition = food_body.x, food_body.y = random.randint(0, width - 30), random.randint(0,height - 30)  # 果子的随机位置
        snake_len += 1  # 蛇的身长加1
    # 3、移动
    if rect_pos[0] != rect_snake_body[0].x or rect_pos[1] != rect_snake_body[0].y:
        newHead = pygame.Rect(*rect_pos, rect_len, rect_len)
        rect_snake_body.insert(0, newHead)
        if len(rect_snake_body) >= snake_len:
            rect_snake_body.pop()

    # 3.4 渲染
    # 填充背景色(每次用黑色的背景覆盖掉旧有的画面)
    screen.fill((0, 0, 0))
    # 画果子
    pygame.draw.rect(screen, food_color, food_body)
    # 倒序画蛇身
    for i in range(len(rect_snake_body)):
        # 画矩阵
        p=rect_snake_body[len(rect_snake_body)-i-1]
        pygame.draw.rect(screen, rect_color, p)
        pygame.draw.rect(screen, (200,200,200), p,1)
    # 更新屏幕
    pygame.display.update()

    # 控制游戏刷新速度
    clock.tick(60)

三、pygame初级

经过前面的学习,想必各位帅哥美女对怎么用pygame写交互逻辑有了一些初步的认知。现在让我们学习一下:1、图片导入。2、文本。3、游戏结束和重新开始。4、空格游戏暂停

初级的博客在个人博客里可以搜到,后续看反响,如果还行整理成视频在b站发布。

中级的话就是工程开发,将以上的全部,按照工程标准分多个文件开发。后面也会提到

相关文章
|
24天前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
24天前
|
小程序 开发者 Python
探索Python编程:从基础到实战
本文将引导你走进Python编程的世界,从基础语法开始,逐步深入到实战项目。我们将一起探讨如何在编程中发挥创意,解决问题,并分享一些实用的技巧和心得。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的参考。让我们一起开启Python编程的探索之旅吧!
45 10
|
1月前
|
机器学习/深度学习 人工智能 算法
强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用
本文探讨了强化学习在游戏AI中的应用,从基本原理、优势、应用场景到具体实现方法,以及Python在其中的作用,通过案例分析展示了其潜力,并讨论了面临的挑战及未来发展趋势。强化学习正为游戏AI带来新的可能性。
107 4
|
1月前
|
算法 Unix 数据库
Python编程入门:从基础到实战
本篇文章将带你进入Python编程的奇妙世界。我们将从最基础的概念开始,逐步深入,最后通过一个实际的项目案例,让你真正体验到Python编程的乐趣和实用性。无论你是编程新手,还是有一定基础的开发者,这篇文章都将为你提供有价值的信息和知识。让我们一起探索Python的世界吧!
|
1月前
|
并行计算 调度 开发者
探索Python中的异步编程:从基础到实战
在Python的世界里,异步编程是一种让程序运行更加高效、响应更快的技术。本文不仅会介绍异步编程的基本概念和原理,还将通过具体代码示例展示如何在Python中实现异步操作。无论你是初学者还是有经验的开发者,都能从中获益,了解如何运用这一技术优化你的项目。
|
1月前
|
数据处理 Python
探索Python中的异步编程:从基础到实战
在Python的世界中,“速度”不仅是赛车手的追求。本文将带你领略Python异步编程的魅力,从原理到实践,我们不单单是看代码,更通过实例感受它的威力。你将学会如何用更少的服务器资源做更多的事,就像是在厨房里同时烹饪多道菜而不让任何一道烧焦。准备好了吗?让我们开始这场技术烹饪之旅。
|
1月前
|
机器学习/深度学习 数据采集 数据可视化
Python数据科学实战:从Pandas到机器学习
Python数据科学实战:从Pandas到机器学习
|
1月前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从基础到实战
【10月更文挑战第36天】本文将带你走进Python的世界,从基础语法出发,逐步深入到实际项目应用。我们将一起探索Python的简洁与强大,通过实例学习如何运用Python解决问题。无论你是编程新手还是希望扩展技能的老手,这篇文章都将为你提供有价值的指导和灵感。让我们一起开启Python编程之旅,用代码书写想法,创造可能。
|
1月前
|
机器学习/深度学习 数据采集 人工智能
机器学习入门:Python与scikit-learn实战
机器学习入门:Python与scikit-learn实战
60 0
|
1月前
|
数据采集 存储 数据处理
探索Python中的异步编程:从基础到实战
【10月更文挑战第39天】在编程世界中,时间就是效率的代名词。Python的异步编程特性,如同给程序穿上了一双翅膀,让它们在执行任务时飞得更高、更快。本文将带你领略Python异步编程的魅力,从理解其背后的原理到掌握实际应用的技巧,我们不仅会讨论理论基础,还会通过实际代码示例,展示如何利用这些知识来提升你的程序性能。准备好让你的Python代码“起飞”了吗?让我们开始这场异步编程的旅程!
40 0