目录
关于pygame:
Pygame是跨平台Python模块,专为电子游戏设计,包含图像、声音。建立在SDL基础上,允许实时电子游戏研发而无需被低级语言束缚。(百度百科)
关于SDL:
SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。
pygame的简单使用:
主要了解一下功能:
1.pygame的初始化和退出:
简单的代码演示:
import pygame
import time
def game():
print("游戏开始了")
# 等待2s
time.sleep(2)
print("游戏结束了")
def main():
# 使用pygame,需要初始化所有pygame模块
pygame.init()
# 调用游戏代码部分
game()
# 游戏退出时,卸载所有的pygame模块
pygame.quit()
if __name__ == "__main__":
main()
2.pygame中的坐标系:
pygame.Rect() :提供了很多方位信息
比如:
上面的长和宽对应的数字反过来了。
简单的代码演示:
def draw_rec():
# 4个参数分别为 x , y, 宽, 长
obj_position = pygame.Rect(50, 60, 100, 200)
print(obj_position)
obj_pos_list = list()
obj_pos_list.append(obj_position.x)
obj_pos_list.append(obj_position.y)
obj_pos_list.append(obj_position.height)
obj_pos_list.append(obj_position.width)
for info_pos in obj_pos_list:
print(info_pos)
3.绘制屏幕:(创建游戏窗口)
ygame
专门提供了一个 模块 pygame.display
用于创建、管理 游戏窗口
方法 | 说明 |
---|---|
pygame.display.set_mode() | 初始化游戏显示窗口 |
pygame.display.update() | 相当于刷新屏幕 |
set_mode
方法
set_mode(resolution=(0,0), flags=0, depth=0) -> Surface
-
作用 —— 创建游戏显示窗口
-
参数
-
resolution
指定屏幕的宽
和高
,默认创建的窗口大小和屏幕大小一致 -
flags
参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递 -
depth
参数表示颜色的位数,默认自动匹配
-
set_mode()方法的演示:
写了这个函数后,放在上面的game函数中,然后运行main函数:就会看到如下结果:
会出现一个pygame widows,尺寸的大小就是自己设置的参数。可以发现,这只是一个黑黑的窗口而已
为了是窗口能被我们清楚的看到,我在绘制完窗口后停留了20s,实际的应用中是将其设置为无限循环,然后在监听发生了什么时间之后
关闭窗口,也就是结束游戏
在创建好了窗口后,我们可以将我们的图片加载到窗口中
加载图像:
-
使用
pygame.image.load()
加载图像的数据 -
使用 游戏屏幕 对象,调用
blit
方法 将图像绘制到指定位置 -
调用
pygame.display.update()
方法更新整个屏幕的显示
绘制屏幕背景代码演示:
(需要图片等素材的朋友可以在下方留下邮箱)
首先在当前文件夹下准备好背景图片(图片的大小为480*700 ,所以我将创建的屏幕修改了)
代码部分有点模糊,我将代码在写一边:
def make_screen():
# 宽480 长700
screen = pygame.display.set_mode((480, 700))
# 加载图片 ,并将图片保存起来
bg = pygame.image.load("./images/background.png")
# 将加载的图片绘制在屏幕上, 第一个参数是需要加载的图片,第二个是元组 表示从哪个点开始加载。
screen.blit(bg, (0, 0))
# 最后在更新屏幕,这样才能显示图像
pygame.display.update()
time.sleep(20)
让游戏动起来:(游戏循环、游戏时钟)
实现原理:只要我们在足够短的时间内,更新足够多的图片,比如果,一个飞机它会向上移的效果。只要我们在1s中内绘制60张图片,每张图片使飞机的位置向上移动的一个像素,在人的视觉下就会产生动画的效果。(就是所谓的帧率啦)
那我们如何才能设置这个所谓的帧率呢?
pygame中提供了工具:
-
pygame.time.Clock
可以非常方便的设置屏幕绘制速度 —— 刷新帧率 -
要使用 时钟对象 需要两步:
-
1)在 游戏初始化 创建一个 时钟对象
-
2)在 游戏循环 中让时钟对象调用
tick(帧率)
方法
-
-
tick
方法会根据 上次被调用的时间,自动设置 游戏循环 中的延时
代码演示:
def test_frame_rate():
t_start = time.time()
clock = pygame.time.Clock()
a = 0
while True:
clock.tick(60)
a += 1
if a == 600:
break
t_over = time.time()
print("使用始终后所使用的时间为:", t_over-t_start)
t_start_next = time.time()
b = 0
while True:
b += 1
if b == 60000:
break
t_over_next = time.time()
print("正常时间为:", t_over_next-t_start_next)
测试结果为:(设置后就相当于, clock.tick(60)这哥们让cpu在1s中内经过它60次)
有了上面的基础。
我们可以做如下演示:
1.建一个屏幕
2.绘制背景图片
3.在背景下,绘制一个英雄飞机
4.在没有任何操作的情况下,让飞机向上移动
主要代码如下:
def make_screen():
# 宽480 长700
screen = pygame.display.set_mode((480, 700))
# 加载图片 ,并将图片保存起来
bg = pygame.image.load("./images/background.png")
# 将加载的图片绘制在屏幕上, 第一个参数是需要加载的图片,第二个是元组 表示从哪个点开始加载。
screen.blit(bg, (0, 0))
# 定义英雄的位置,并加载出英雄的位置
hero_position = pygame.Rect(180, 500, 102, 126)
hero_plane = pygame.image.load("./images/me1.png")
screen.blit(hero_plane, hero_position)
# 最后在更新屏幕,这样才能显示图像
pygame.display.update()
while True:
clock = pygame.time.Clock()
clock.tick(60)
# 如果位置到了屏幕的顶端, 就不能在上去了
if hero_position.y != 0:
# 修改英雄的位置
hero_position.y -= 1
# 在绘制背景
screen.blit(bg, (0, 0))
# 绘制更新后的英雄
screen.blit(hero_plane, hero_position)
# 更新屏幕
pygame.display.update()
如果只更新英雄位置,不更新背景位置会出现这样的现象:
如果下面先更新飞机,后更新背景:
飞机就会看不到。背景将飞机给覆盖掉了。
所以先更新背景,然后在背景的上面绘制飞机。
精灵图跟精灵组:
为了简化开发步骤,pygame
提供了两个类
-
pygame.sprite.Sprite
—— 存储 图像数据 image 和 位置 rect 的 对象 -
pygame.sprite.Group
换句话来理解精灵与精灵组,就差不多使类与对象的的关系。
创建需要的各种类,就是精灵组,比如敌人的飞机。然后有很多实例,就是精灵。将各个精灵添加到精灵组中。将他们一起更新,保存他们所有的位置信息。这样比较方便
精灵
-
在游戏开发中,通常把 显示图像的对象 叫做精灵
Sprite
-
精灵 需要 有 两个重要的属性
-
image
要显示的图像 -
rect
图像要显示在屏幕的位置
-
-
默认的
update()
方法什么事情也没做-
子类可以重写此方法,在每次刷新屏幕时,更新精灵位置
-
-
注意:
pygame.sprite.Sprite
并没有提供image
和rect
两个属性-
需要程序员从
pygame.sprite.Sprite
派生子类 -
并在 子类 的 初始化方法 中,设置
image
和rect
属性
-
精灵组
-
一个 精灵组 可以包含多个 精灵 对象
-
调用 精灵组 对象的
update()
方法-
可以 自动 调用 组内每一个精灵 的
update()
方法
-
-
调用 精灵组 对象的
draw(屏幕对象)
方法-
可以将 组内每一个精灵 的
image
绘制在rect
位置
-
代码演示:
首先派生精灵子类:
import pygame
class InSprites(pygame.sprite.Sprite):
def __init__(self, image_name, speed=1):
super().__init__()
# 加载图像
self.image = pygame.image.load(image_name)
# 设置尺寸
# image 的 get_rect() 方法,可以返回 pygame.Rect(0, 0, 图像宽, 图像高) 的对象
self.rect = self.image.get_rect()
# 记录速度
self.speed = speed
def update(self):
self.rect.y += self.speed
然后在使用这个精灵子类:
主要代码如下:
def make_screen():
# 宽480 长700
screen = pygame.display.set_mode((480, 700))
# 加载图片 ,并将图片保存起来
bg = pygame.image.load("./images/background.png")
# 将加载的图片绘制在屏幕上, 第一个参数是需要加载的图片,第二个是元组 表示从哪个点开始加载。
screen.blit(bg, (0, 0))
# 定义英雄的位置,并加载出英雄的位置
"""
hero_position = pygame.Rect(180, 500, 102, 126)
hero_plane = pygame.image.load("./images/me1.png")
screen.blit(hero_plane, hero_position)
"""
# 最后在更新屏幕,这样才能显示图像
pygame.display.update()
# 创建两个敌机精灵
enemy1 = note_sprites.InSprites("./images/enemy1.png", 2)
enemy2 = note_sprites.InSprites("./images/enemy2.png")
# 为了使出现的时候时候不重叠,将其中的一驾飞机的x改变
enemy1.rect.x = 200
# 将精灵加入精灵组
enemy_group = pygame.sprite.Group(enemy1, enemy2)
while True:
# 调用update方法,让精灵组中的所有精灵自动的调用update方法
enemy_group.update()
screen.blit(bg, (0, 0))
enemy_group.draw(screen)
pygame.display.update()
事件监听:
事件 event
-
就是游戏启动后,用户针对游戏所做的操作
-
例如:点击关闭按钮,点击鼠标,按下键盘...
监听
-
在 游戏循环 中,判断用户 具体的操作
只有 捕获 到用户具体的操作,才能有针对性的做出响应
代码实现
-
pygame
中通过pygame.event.get()
可以获得 用户当前所做动作 的 事件列表-
用户可以同一时间做很多事情
-
主要代码:
for event in pygame.event.get():
print(event) # 打印监听到的事件
# 判断用户是否点击了关闭按钮
if event.type == pygame.QUIT:
print("退出游戏...")
pygame.quit()
# 直接退出系统
exit()
在窗口上有一些鼠标上的移动, 或者其他动作都会被捕捉到
按下关闭,就会退出游戏