一、pygame的安装
pygame 是一个Python模块,专为电子游戏设计
官方网站: https://www.pygame.org
1.安装pygame
# 在windows的命令行或是linux的命令行执行均可
pip3 install pygame
2.验证
python -m pygame.examples.aliens
二、pygame快速入门
项目准备:
1.新建飞机大战项目
2.新建一个hym_01_pygame入门.py
3.导入游戏素材图片
游戏的第一印象:
1.把一些静止的图像绘制到游戏窗口中
2.根据用户的交互或其他情况,移动这些图像,产生动画效果
3.根据图像之间是否发生重叠,判断敌机是否被摧毁等其他情况
01.使用pygame创建图形窗口
1.理解游戏中的坐标系
坐标系:原点在左上角 ( 0 , 0 );x轴水平方向向右,逐渐增加;y轴垂直方向向下,逐渐增加;
● 在游戏中,所有可见的元素都是以矩形区域来描述位置的;
● 要描述一个矩形区域有4个要素:(x,y) (width,height)
● pygame专门提供了一个类 pygame.Rect 用于 描述矩形区域
Rect(x,y,width,height) #描述矩形区域
坐标原点: (x,y)
宽度:width 高度:height
注意: size 返回的是一个元组 (width,height)
案例演练:
1.定义hero_rect矩形 描述 英雄的位置和大小
2.输出英雄的坐标原点(x和y)
3.输出英雄的尺寸(宽度 和 高度)
import pygame
hero_rect = pygame.Rect(100,500,120,125)
print("英雄的原点为(%d,%d)" %(hero_rect.x,hero_rect.y))
print("英雄的尺寸:宽为%d 高为%d" %(hero_rect.width,hero_rect.height))
print("英雄的尺寸:宽为%d 高为%d" %(hero_rect.size))
print(hero_rect.size)
2.创建游戏主窗口
pygame专门提供了一个模块 pygame.display 用于创建、管理游戏窗口
pygame.display.set_mode() #初始化游戏显示窗口
pygame.dispaly.update() #刷新屏幕内容显示,稍后使用
set_mode方法:
set_mode(resolution=(0,0),flags=0,depth=0) #创建游戏显示窗口
参数解释:
resolution:指定屏幕的宽和高,默认创建的窗口大小和屏幕大小一致
flags:参数指定屏幕的附加选项,例如:是否全屏等,默认不需要传递
depth:参数表示颜色的位数,默认自动匹配
注意:必须使用变量记录set_mode方法的返回结果,因为后续所有的图像绘制都基于这个返回结果
3.简单的游戏循环
为了做到游戏程序启动后,不会立即退出,通常会在游戏程序中增加一个游戏循环;所谓游戏循环就是一个无限循环
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高);注意:此窗口的大小是依据游戏的背景图片而设定的
screen=pygame.display.set_mode((350,573))
# 游戏循环
while True:
pass
# 退出pygame
pygame.quit()
02.图像绘制
在游戏中,能够看到的元素大多都是图像;图像文件初始是保存在磁盘上的,如果需要使用,首先需要被加载到内存
要在屏幕上看到某一个图像的内容,需要以下三个步骤:
1.使用 pygame.image.load() :加载图像的数据
2.使用 游戏屏幕 对象,调用 blit 方法:将图像绘制到指定位置
3.调用 pygame.display.update() 方法:更新整个屏幕的显示
代码演练:
(1).绘制背景图像
1.加载 background.png 创建背景
2.将背景绘制在屏幕的 (0,0) 位置
3.调用屏幕更新显示背景图像
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
## 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像 blit(图像,位置);
screen.blit(bg,(0,0))
# 3.更新屏幕显示
pygame.display.update()
# 游戏循环
while True:
pass
# 退出pygame
pygame.quit()
(2).绘制英雄图像
1.加载me1.png 创建英雄飞机
2.将英雄飞机绘制在屏幕的(200,500)位置
3.调用屏幕更新显示飞机图像
透明图像:(可以用ps制作)
png格式的图像是支持透明的,在绘制图像时,透明区域不会显示任何内容,但如果下方已经有内容,会透过透明区域显示出来
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 3.更新屏幕显示
pygame.display.update()
## 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 3.更新屏幕显示
pygame.display.update()
# 游戏循环
while True:
pass
# 退出pygame
pygame.quit()
update方法:
可以在screen对象完成所有blit方法之后,调用一次display.update方法,同样可以在屏幕上看到最终的绘制结果
● 使用display.set_mode()方法创建的screen对象时一个内存中的屏幕数据对象,可以理解为油画的画布;
● screen.blit方法可以在画布上绘制很多的图像,例如:英雄、敌机、子弹等,这些图像有可能会彼此重叠或覆盖;
● display.update()会将画布的最终结果绘制在屏幕上,这样可以提高屏幕绘制效率,增加游戏的流畅度;
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
## 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 游戏循环
while True:
pass
# 退出pygame
pygame.quit()
03.游戏循环和游戏时钟
现在英雄飞机已经被绘制到屏幕上,那么如何让飞机移动呢?
1.游戏中的动画实现原理
● 跟电影的原理类似,游戏中的动画效果,本质上是快速的在屏幕上绘制图像;
● 一般在电脑上每秒绘制60次,就能够到达非常连续高品质的动画效果,每次绘制的结果被称为帧;
2.游戏循环
游戏的两个组成部分:
游戏循环的作用:
(1).保证游戏不会直接退出
(2).变化图像位置---动画效果
● 每隔 1/60 秒 移动以下所有图像的位置
● 调用 pygame.display.update() 更新屏幕显示
(3).检测用户交互---按键、鼠标等.....
3.游戏时钟
pygame专门提供了一个类 pygame.time.clock 可以非常方便的设置屏幕绘制速度---刷新帧率;
要使用时钟对象,需要两步:
1).在游戏初始化创建一个时钟对象
2).在游戏循环中让时钟对象调用 tick(帧率) 方法
tick方法会根据上次被调用的时间,自动设置游戏循环中的延时
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
## 创建时钟对象
clock = pygame.time.Clock()
## 游戏循环:意味着游戏的正式开始!
## 无限循环执行的太快,要想达到良好动画效果,只需每秒执行60次即可
i = 0
while True:
# 指定循环体内部的代码执行的频率;每秒执行60次
clock.tick(60)
# 输出i只是为了测试
print(i)
i += 1
# 退出pygame
pygame.quit()
4.英雄的简单动画实现
需求:
1.在游戏初始化定义一个 pygame.Rect 的变量记录英雄的初始位置
2.在游戏循环中每次让英雄的 y-1(向上移动)
3.y<=0 将英雄移到屏幕的底部
注意:每一次调用 update() 方法之前,需要把所有的游戏图像都重新绘制一遍,且应该最先绘制背景图像;
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()
# 1.定义rect记录飞机的初始位置 (x,y,宽,高)
hero_rect = pygame.Rect(140,450,80,78)
# 游戏循环:意味着游戏的正式开始!
while True:
# 指定循环体内部的代码执行的频率;之所以将频率设置为1,只是为了观察图像变换
clock.tick(1)
# 2.修改飞机的位置
hero_rect.y -= 30
# 3.调用blit方法绘制图像
# 绘制背景图像,防止出现飞机影像!!!
screen.blit(bg, (0, 0))
# 绘制英雄图像
screen.blit(hero,hero_rect)
# 4.调用update方法更新显示
pygame.display.update()
# 退出pygame
pygame.quit()
改进:让飞机周而复始的循环飞行,即当飞机的头部飞到屏幕顶部时,让飞机回到屏幕底部继续向上飞行;
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()
# 1.定义rect记录飞机的初始位置 (x,y,width,height)
hero_rect = pygame.Rect(140,450,80,78)
# 游戏循环:意味着游戏的正式开始!
while True:
# 指定循环体内部的代码执行的频率;
clock.tick(1)
# 2.修改飞机的位置
hero_rect.y -= 1
## 判断飞机的位置;573为背景图像的高度
if hero_rect.y <=0:
hero_rect.y = 573
# 3.调用blit方法绘制图像
# 绘制背景图像,防止出现飞机影像!!!
screen.blit(bg, (0, 0))
# 绘制英雄图像
screen.blit(hero,hero_rect)
# 4.调用update方法更新显示
pygame.display.update()
# 退出pygame
pygame.quit()
如果你想实现当飞机的尾部飞到屏幕顶部时,让飞机回到屏幕底部继续向上飞行;有以下两种方式:
if hero_rect.y <= -450:
hero_rect.y = 573
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 573
5.在游戏循环中中的监听事件
事件:就是游戏启动后,用户针对游戏所作的操作;例如:点击关闭按钮,点击鼠标,按上下键等...
监听:在游戏循环中,判断用户具体的操作;只有捕获到用户具体的此操作才能针对性的做出响应;
代码实现:
pygame 中通过 pygame.event.get() 可以获得 用户当前所作的动作的时间列表;用户可以在同一时间做很多事情
# 捕获事件
event_list = pygame.event.get()
# 添加判断;仅当用户对游戏有操作时才输出事件列表
if len(event_list) > 0:
print(event_list)
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()
# 1.定义rect记录飞机的初始位置 (x,y,width,height)
hero_rect = pygame.Rect(140,450,80,78)
# 游戏循环:意味着游戏的正式开始!
while True:
# 指定循环体内部的代码执行的频率;
clock.tick(1)
## 捕获事件
event_list = pygame.event.get()
# 添加判断;仅当用户对游戏有操作时才输出事件列表
if len(event_list) > 0:
print(event_list)
# 2.修改飞机的位置
hero_rect.y -= 40
# 判断飞机的位置
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 573
# 3.调用blit方法绘制图像
# 绘制背景图像,防止出现飞机影像!!!
screen.blit(bg, (0, 0))
# 绘制英雄图像
screen.blit(hero,hero_rect)
# 4.调用update方法更新显示
pygame.display.update()
# 退出pygame
pygame.quit()
当你对游戏界面执行操作时,事件便会捕获到操作,但不会执行;比如鼠标点击关闭按钮,事件便会捕获到Qiut,但不会退出。
捕获并执行退出事件:
# 监听退出事件
# 遍历捕获的所有事件,pygame.event.get():捕获事件,数据类型为列表;
for event in pygame.event.get():
# 判断事件类型是否为退出事件
if event.type == pygame.QUIT:
print("游戏退出...")
# 卸载所有模块,退出pygame
pygame.quit()
# 退出系统,即终止当前正在执行的程序
exit()
import pygame
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()
# 1.定义rect记录飞机的初始位置 (x,y,width,height)
hero_rect = pygame.Rect(140,450,80,78)
# 游戏循环:意味着游戏的正式开始!
while True:
# 指定循环体内部的代码执行的频率;
clock.tick(1)
## 监听退出事件
# 遍历捕获的所有事件,pygame.event.get():捕获事件,数据类型为列表;
for event in pygame.event.get():
# 判断事件类型是否为退出事件
if event.type == pygame.QUIT:
print("游戏退出...")
# 卸载所有模块,退出pygame
pygame.quit()
# 退出系统,即终止当前正在执行的程序
exit()
# 2.修改飞机的位置
hero_rect.y -= 40
# 判断飞机的位置
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 573
# 3.调用blit方法绘制图像
# 绘制背景图像,防止出现飞机影像!!!
screen.blit(bg, (0, 0))
# 绘制英雄图像
screen.blit(hero,hero_rect)
# 4.调用update方法更新显示
pygame.display.update()
# 退出pygame
pygame.quit()
测试发现,当鼠标点击游戏界面的关闭按钮时,游戏退出。
04.精灵和精灵组
1.基本概念
在刚完成的案例中,我们了解到,游戏的一般步骤。首先,在游戏初始化时加载图像;其次,需要在游戏循环中,针对每一张图像,修改图像位置并重新绘制图像。假设我们的游戏需要处理100张图像,意味着游戏循环内部的代码就会变得非常繁琐。
为了简化开发步骤,pygame提供了两个类:
● pygame.sprite.Sprite (精灵) 存储图像数据 image 和 位置 rect 的对象
● pygame.sprite.Group (精灵组) 包含多个精灵的对象
2.派生精灵子类
明确步骤:
1.新建 plane_sprites.py 文件
2.定义 GameSprite 继承自 pygame.sprite.Sprite( pygame.模块.类)
注意:
(1).如果一个类的父类不是 object
(2).在重写初始化方法时,一定要先 super() 一下父类的 _init_ 方法
(3).保证父类中实现的 _init_ 代码能够被正常执行
属性:
● image精灵图形,使用 image_name 加载
● rect 精灵大小,默认使用图像大小
● speed 精灵移动速度,默认为1
方法:
● update 每次更新屏幕时在游戏循环内调用,让精灵的 self,rect.y += self.speed
提示:
● image 的 get_rect() 方法,可以返回 pygame.Rect(0,0,宽,高) 的对象
import pygame
## 导入plane_sprites文件中的所有模块
from plane_sprites import *
# 初始化pygame
pygame.init()
# 创建游戏的窗口 350 * 573(宽,高)
screen=pygame.display.set_mode((350,573))
# 绘制背景图像
# 1.加载图像数据
bg = pygame.image.load("./images/background.png")
# 2.绘制图像
screen.blit(bg,(0,0))
# 绘制英雄图像
# 1.加载图像数据
hero = pygame.image.load("./images/me1.png")
# 2.绘制图像
screen.blit(hero,(140,450))
# 在所有绘制工作完成之后,统一调用update方法:更新屏幕显示
pygame.display.update()
# 创建时钟对象
clock = pygame.time.Clock()
# 1.定义rect记录飞机的初始位置 (x,y,width,height)
hero_rect = pygame.Rect(140,450,80,78)
## 创建敌机的精灵
enemy = GameSprite("./images/enemy1.png")
enemy1 = GameSprite("./images/enemy1.png",2)
## 创建敌机的精灵组
enemy_group = pygame.sprite.Group(enemy,enemy1)
# 游戏循环:意味着游戏的正式开始!
while True:
# 指定循环体内部的代码执行的频率;
clock.tick(1)
# 监听退出事件
# 遍历捕获的所有事件,pygame.event.get():捕获事件,数据类型为列表;
for event in pygame.event.get():
# 判断事件类型是否为退出事件
if event.type == pygame.QUIT:
print("游戏退出...")
# 卸载所有模块,退出pygame
pygame.quit()
# 退出系统,即终止当前正在执行的程序
exit()
# 2.修改飞机的位置
hero_rect.y -= 40
# 判断飞机的位置
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 573
# 3.调用blit方法绘制图像
# 绘制背景图像,防止出现飞机影像!!!
screen.blit(bg, (0, 0))
# 绘制英雄图像
screen.blit(hero,hero_rect)
## 精灵组调用两个方法
# update:让组中的所有精灵更新位置
enemy_group.update()
# draw:在screen上绘制所有的精灵
enemy_group.draw(screen)
# 4.调用update方法更新显示
pygame.display.update()
# 退出pygame
pygame.quit()