目录:
1)游戏的初始化和退出
2)游戏中的坐标系
3)创建游戏主窗口
4)图像绘制
5) 关于动画实现的原理
6)游戏的事件监听
7)pygame中提供的高级类精灵和精灵组
8)背景交替滚动
9)定时器
10)针对键盘按键捕获的两种方式
11)音乐导入
12)pygame中提供的两种精灵碰撞检测方法
`
使用pygame创建图形窗口
·
1)游戏的初始化和退出
●要使用pygame
提供的所有功能之前,需要调用init
方法
●在游戏结束前需要调用一下quit
方法
方法 | 说明 |
---|---|
pygame.init() | 导入并初始化所有pygame模块,使用其他模块前,必须先调用iinit方法 |
pygame.quit() | 卸载所有pygame模块,在游戏结束之前调用 |
·
2)游戏中的坐标系
●原点在左上角 (0,0)
●x轴水平方向向右,逐渐增加
●y轴垂直方向向下,逐渐增加
如图:
● 在游戏中,所有可见的元素都是以矩形区域来描述位置的
● 要描述一个矩形区域有四个要素: (x, y) (width, height)
(x,y)是物体坐标,(width, height)是物体像素大小
●pygame 专门提供了一个类pygame.Rect
用于描述矩形区域
● pygame.Rect是一个比较特殊的类,内部只是封装了一些数字计算
●不执行pygame. init()方法同样能够直接使用
实例:
·
3)创建游戏主窗口
● pygame
专门提供了一个模块pygame.display
用于创建、管理游戏窗口
方法 | 说明 |
---|---|
pygame.display.set_mode() | 初始化游戏显示窗口 |
pygame.display.update() | 刷新屏幕内容,稍后使用 |
·
set_mode()
方法
set_ mode( resolution=(0,0),flags=0, depth=0) -> Surface(名字随意)
●作用- -创建游戏显示窗口
●参数
。resolution
指定屏幕的宽和高,默认创建的窗口大小和屏幕大小-致
。flags
参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递
。depth
参数表示颜色的位数,默认自动匹配
● 返回值Surface
(名字随意)对象是内存中的屏幕数据对象,可以理解为游戏的屏幕,游戏的元素都需要被绘制到游戏的屏幕上
实例:
`
●在开发时,可能会需要使用固定的数值,例如屏幕的高度是700
●这个时候,建议不要直接使用固定数值,而应该使用常量
●在开发时,为了保证代码的可维护性,尽量不要使用魔法数字
当实验需求发生变化时,只需要修改常量的值就可,不需要在一个一个去找数值更改
常量的命名方式:
所有字母都使用大写,单词与单词之间使用下划线连接
·
4)图像绘制
● 使用图像时,会将图像文件从磁盘中加载到内存
那么要在创建的窗口中按照指定要求显示图片,则需要三个步骤:
1.使用pygame.image.load()
加载图像的数据
2.使用游戏屏幕对象,调用blit
方法将图像绘制到指定位置
3.调用pygame.display.update()
方法更新整个屏幕的显示
注:如果不调用
pygame.display.update()
方法,则运行程序后图片并不会显示出来,在所有图像绘制完成后可放在最后统一更新
实例:
·
5) 关于动画实现的原理
●跟电影的原理类似,游戏中的动画效果,本质上是快速的在屏幕上绘制图像
。电影是将多张静止的电影胶片连续、快速的播放,产生连贯的视觉效果!
●一般在电脑上每秒绘制60次,就能够达到非常连续高品质的动画效果
。每次绘制的结果被称为帧Frame
在每次调用
pygame.display.update()
方法产生的结果为一帧,也就是说需要每秒钟调用60次pygame.display.update()
方法,就可以达到高品质动画效果
·
如何实现每秒60帧??
●pygame专门提供了一个类pygame.time.Clock
可以非常方便的设置屏幕绘制速度- -刷新帧率
●要使用时钟对象需要两步:
1)在游戏初始化创建一个时钟对象
2)在游戏循环中让时钟对象调用tick(帧率)
方法
●tick
方法会根据.上次被调用的时间, 自动设置游戏循环中的延时
实现方法:
# 创建时钟对象
clock = pygame.time.Clock()
while True:
# 在游戏循环内部调用tick方法,里面传入想要的帧数
clock.tick(60)
·
动画实现案例:飞机向上飞行
例 :
·
6)游戏的事件监听
事件event
●游戏启动后,用户针对游戏所做的操作
●例如:点击关闭按钮,点击鼠标,按下键盘…
监听
●在游戏循环中,判断用户具体的操作
●只有捕获到用户具体的操作,才能有针对性的做出响应
代码实现:
●pygame提供事件监听的方法为pygame.event.get()
●pygame.event.get()
的返回类型是一个列表
●列表里存放的是所有用户通过鼠标或者键盘对游戏进行的操作
·
事件监听代码模板:
# 事件监听
for event in pygame.event.get():
# 判断事件类型是否是游戏退出
if event.typr = pygame.QUIT:
exit()
·
7)pygame中提供的高级类精灵和精灵组
图像加载、位置变化、绘制图像都需要程序员编写代码分别处理,为了简化代码,避免过多类似重复的代码,pygame提供了精灵和精灵组类
·
心得: 其根本就是,将需要创建的多个执行相同动作的元素通过精灵类统一规划到一起,再通过精灵组统一执行每个元素的动作并绘制到屏幕上,将多次重复的代码缩减成一次代码。
·
● pygame.sprite.Sprite
—— 存储图像数据image
和位置rect
的对象
● pygame.sprite.Group
注:在开发时,如果子类的父类不是Object类,则需要通过
super(),__init__()
来调用父类的初始化方法,因为父类中的初始化方法中封装了许多属性,在继承父类后只有通过手动调用父类的初始化方法,才能在子类的初始化方法中使用父类初始化方法封装的属性
·
职责
●精灵
。封装图像image
、位置rect
。提供update()
方法,根据游戏需求,更新位置rect
# 定义对象的属性
self.image = pygame.image.load(image)
# 得到图片的坐标和宽高像素
self.rect = self.image.get_rect()
●精灵组
。包含多个精灵对象
。update
方法,让精灵组中的所有精灵调用update
方法更新位置
。draw(游戏窗口对象)
方法,在游戏窗口
上绘制精灵组中的所有精灵
实例:
精灵类planeSprites:
import pygame
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 调用父类的初始化方法
super().__init__()
# 定义对象的属性
self.image = pygame.image.load(image)
# 得到图片的坐标和宽高像素
self.rect = self.image.get_rect()
# 定义图片的运行速度
self.speed = speed
def update(self, *args):
# 使飞机斜着飞行
self.rect.x += self.speed
self.rect.y += self.speed
# 杀死精灵,节约内存
self.kill()
主程序中:
import pygame
from plane_sprites import planeSprites
pygame.init()
# 创建敌机1,敌机2
enemy1 = planeSprites("./飞机大战素材/敌机.png")
enemy2 = planeSprites("./飞机大战素材/敌机.png")
# 在精灵组中加入敌机1
enemy_group = pygame.sprite.Group(enemy1, enemy2)
while True:
# 调用精灵组的update方法
enemy_group.update()
# 将精灵组中的敌机绘制到屏幕上
enemy_group.draw(screen)
# ***一定记得更新视图,否则不会显示出任何图像
pygame.display.update()
pygame.quit()
·
8)背景交替滚动
俗称跑步机模式
在飞机大战中游戏背景不断变化产生向上飞行的视觉效果
实现原理:
实际上是两张尺寸与屏幕一样大小的背景图片向下移动,等第一张图片刚移除出屏幕后立马改变坐标移动到第二张图片之后
代码实现:
精灵类
import pygame
from plane_main import SCREEN_RECT
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 调用父类的初始化方法
super().__init__()
# 定义对象的属性
self.image = pygame.image.load(image)
# 得到图片的坐标和宽高像素
self.rect = self.image.get_rect()
# 定义图片的运行速度
self.speed = speed
def update(self, *args):
# 使精灵向下移动
self.rect.y += self.speed
# 当父类update更新方法已经无法满足某一精灵类的条件则可以创建心得精灵子类
class background(planeSprites):
def __init__(self, is_single=False):
super().__init__("./飞机大战素材/游戏背景.jpg")
if is_single:
#将第二张图片放在第一张图片的上面
self.rect.y = - self.rect.height
def update(self, *args):
# 调用父类更新方法
super().update()
if self.rect.y == SCREEN_RECT.height:
self.rect.y = - self.rect.height
主方法:
import pygame
from plane_sprites import *
pygame.init()
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
class main(object):
def __init__(self):
# 创建游戏屏幕
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 创建游戏时钟
self.clock = pygame.time.Clock()
# 创建游戏精灵组
self.__create_spirits()
# 精灵创建
def __create_spirits(self):
bg1 = background()
bg2 = background(True)
self.backGroup = pygame.sprite.Group(bg1, bg2)
# 精灵更新处理
def __update_spirits(self):
self.backGroup.update()
self.backGroup.draw(self.screen)
·
9)定时器
●在 pygame中可以使用pygame.time.set.timer()
来添加定时器
●所谓定时器,就是每隔一段时间,去执行些动作
set_timer(eventid, milliseconds) -> None
●set_timer
可以创建一个事件
●可以在游戏循环的事件监听方法中捕获到该事件
● 第1个参数事件代号需要基于常量pygame. USEREVENT
来指定
USEREVENT 是一个整数,再增加的事件可以使用USEREVENT + 1指定,依次类推…
●第2个参数是事件触发间隔的毫秒值
定时器事件的监听
●通过pygame.event.get()
可以获取当前时刻所有的事件列表
●遍历列表并且判断event.type
是否等于eventid
, 如果相等,表示定时器事件发生
实现方法:
# 创建敌机的定时器,每隔1000ms发出一个事件
pygame.time.set_timer(pygameUSEREVENT, 3000)
# 事件监听
for event in pygame.event.get():
if event.type == pygameUSEREVENT:
pass
实例(敌机随机飞进屏幕中):
精灵类
import random
import pygame
# 指定屏幕格式大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
CREATE_EVVENTID = pygame.USEREVENT
class planeSprites(pygame.sprite.Sprite):
def __init__(self, image, speed=1):
# 调用父类的初始化方法
super().__init__()
# 定义对象的属性
self.image = pygame.image.load(image)
# 得到图片的坐标和宽高像素
self.rect = self.image.get_rect()
# 定义图片的运行速度
self.speed = speed
# 创建敌机的定时器,每隔1000ms发出一个事件
pygame.time.set_timer(CREATE_EVVENTID, 3000)
class enemy(planeSprites):
"""敌机精灵"""
def __init__(self):
super().__init__("./飞机大战素材/敌机.png")
self.rect.bottom = 0
# 飞机速度从1—3中任取
self.speed = random.randint(1, 3)
max_x = SCREEN_RECT.width - self.rect.width
# 飞机的位置从0-屏幕右边任取
self.rect.x = random.randint(0, max_x)
def update(self, *args):
super().update()
# 判断精灵飞出屏幕后杀死精灵
if self.rect.y >= SCREEN_RECT.height:
self.kill()
主方法:
import pygame
from plane_sprites import *
pygame.init()
# 精灵创建
def __create_spirits(self):
self.enemyGroup = pygame.sprite.Group()
# 事件监听处理
def __event_handler(self):
for event in pygame.event.get():
# 判断事件类型是否是定时器给出的
if event.type == CREATE_EVVENTID:
# 新增精灵
oneEnemy = enemy()
# 向精灵组中添加精灵
self.enemyGroup.add(oneEnemy)
# 精灵更新处理
def __update_spirits(self):
self.enemyGroup.update()
self.enemyGroup.draw(self.screen)
·
10)针对键盘按键捕获的两种方式
●第一种方式判断event.type == pygame.KEYDOWN
实现代码:
if event.type == pygame. KEYDOWN and event.key == pygame.K RIGHT:
print("向右移动...")
`
●第二种方式(按住方向键不放可持续移动)
1.首先使用pygame. key.get_ pressed()
返回所有按键元组
2.通过键盘常量,判断元组中某一个键是否被按下——如果被按下,对应数值为1
实现代码:
变量 = pygame.key.get_pressed()
if 变量[pygame.K_RIGHT]:
print("向右移动")
·
● 两种方式的区别
第一种方式
event.type
用户必须抬起按键才算一次按键事件(利用列表也可实现持续向某一方向移动,具体见)
第二种方式 用户可按键不放,能够实现持续向某一个方向移动
·
11)音乐导入
#导入音乐
pygame.mixer.init()
def background_music_load():
global hero_fire_music # 导入函数外部变量
pygame.mixer.music.load("./music/PlaneWarsBackgroundMusic.mp3")#游戏背景音乐
pygame.mixer.music.set_volume(0.3)#设置音量(0-1)
pygame.mixer.music.play(-1)#循环播放
hero_fire_music = pygame.mixer.Sound("./music/hero_fire.wav")#飞机开火音乐
hero_fire_music.set_volume(0.2)#设置音量(0-1)
·
12)pygame中提供的两种精灵碰撞检测方法
·
pygame.sprite.groupcolide()
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_ dict
group1
和group2
都是一个精灵组
dokill1
和dokill2
都是布尔类型
`
当把dokill1
设置为True
后,精灵组1和精灵组2碰撞时精灵组1会自动销毁
当把dokill2
设置为True
后,精灵组1和精灵组2碰撞时精灵组2会自动销毁
·
pygame.sprite.spritecollide()
●判断某个精灵和指定精灵组中的精灵的碰撞
spritecollide(sprite, group, dokill, collided = None) -> Sprite_ list
●如果将dokill
设置为True
,则指定精灵组中发生碰撞的精灵将被自动移除
● collided
参数是用于计算碰捶的回调函数
。如果没有指定,则每个精灵必须有一一个rect
属性
●返回精灵组中跟精灵发生碰撞的精灵列表
注:这里是返回一个列表
代码实现:
enemies = pygame.sprite.spritecollide(self.hero, self.enemyGroup, True)
if len(enemies) > 0:
print("游戏结束,飞机受到损坏")
pygame.quit()
exit()