pygame屏幕与事件
pygame屏幕绘制机制
指的是控制游戏的屏幕变化的机制。
pygame绘制机制简介
使用pygame.display来控制游戏的屏幕,在pygame游戏中只有一个屏幕,只有关闭一个屏幕才能使用另一个屏幕。
屏幕使用的是笛卡尔坐标系。左上角为(0,0 )。
通常而言,屏幕控制都有以下的若干需求:
- 游戏全屏
- 游戏屏幕大小可调节
- 游戏屏幕无边框
- 更改游戏标题栏内容
- 更改游戏图标
pygame提供了三组屏幕控制的函数:
- 屏幕模式和尺寸的控制
pygame.display.set_mode() 设置屏幕的相关模式
pygame.display.info() 生成屏幕的信息 - 窗口标题和图标
pygame.display.set_caption() 设置标题信息
pygame.display.set_icon() 设置图标信息
pygame.display.get_caption() 获得图标 - 窗口感知和刷新
pygame.display.get_active()
pygame.display.flip()
pygame.display.update()
pygame甚至还支持openGL和硬件加速,但一般来说不会用到。
pygame游戏屏幕尺寸和模式设置
- pygame.display.set_mode( r=(0, 0), flags = 0)
r 是屏幕游戏的分辨率,采用(width,height)的方式输入
flags用来控制显示类型,可以通过 “|” 组合使用,常用标记如下:
标记 | 说明 |
---|---|
pygame.RESIZABLE | 窗口大小可调 |
pygame.NOFRAME | 窗口无边框 |
pygame.FULLSCREEN | 窗口全屏 |
对于pygame.RESIZABLE可能出现窗口扩大而游戏图像仍局限在原本大小的情况;
对于pygame.NOFRAMW可能出现没有退出键,无法退出的情况;
对于pyagme.FULLSCREEN可能出现屏幕分辨率不协调的情况。
-
pygame.display.Info()
这个函数用来产生一个VideoInfo对象,这个对象用来存储当前的屏幕参数信息。
如果在set_mode()之前调用,则显示当前系统的参数。
其中有两个重要的参数:
.current_w:游戏窗体的宽
.current_h:游戏窗体的高 -
如果窗口大小改变:
会产生一个pygame.VIDEORESIZE,通过event.size元组返回了新的窗口的大小。
可以用event.size[0], event.size[1]分别获得改变后的窗口大小
pygame的窗口标题和图标设置
-
pygame.set_caption(title, icontitle=NONE)
title设置窗口标题
icontitle设置窗口图标标题,有些系统不支持这一设置所以一般不设置。 -
pygame.get_caption()
返回一个元组类型,其中第一个元素为title第二个元素为icontitle。
该函数可以增加游戏情节,通过交互是的游戏的标题发生变化。 -
pygame.set_icon(surface)
surface对象即之前获取小球图像的图标的对象。
可以设置图标。
注意需要在屏幕创建前设置好。
pygame窗口感知和刷新功能
-
pygame.display.get_active()
当窗口在系统中未被图标化(最小化到状态栏)则返回True,反之则返回False。
通过感应游戏是否被最小化来改变游戏的逻辑。 -
pygame.display.flip()
会将整个窗口重新绘制 -
pygame.display.update()
只重绘窗口中有变化的部分。
pygame事件处理机制
在游戏中,事件的处理是很重要的,它能响应用户的输入。
能够操作键盘以及鼠标等各种外设。
pygame事件处理机制
游戏响应外部的输入(如鼠标、键盘等等),以及在游戏运行中,一些情节的触发也可以通过事件系统进行实现。游戏本身也可以产生一些事件来实现游戏剧情的推进。
逻辑上,pygame有一个叫事件队列的结构,可以缓存pygame接受的所有事件,之后逐一取出事件来操作。
本质上数据是一种数据结构,pygame.even.EventType只有属性,没有方法。
用户也可以定义新的事件类型。
pygame主要包含六大类事件:鼠标、键盘、游戏手柄、系统、窗口以及用户定义事件。
pygame还有事件处理机制来对事件队列进行规范处理。
pygame键盘事件类型与使用
pygame支持两种键盘事件,分别是键盘按下事件pygame.event.KEYDOWN和键盘释放事件pygame.event.KEYUP(只在按下的情况下会触发)。
- 当键盘按下时事件会返回三个属性:
event..key 键盘值
event.unicode 键盘值对应的unicode但是可能会随系统而变化。
event.mod 按键修饰符组合值 - 而键盘释放事件不返回unicode属性。
- 按键的常量名称
基本上就是pygame.K_a...也即下划线后跟按键名称。
注意字母是小写的,大写字母的输入需要通过按键修饰符来实现。 - 按键的修饰符
修饰符:按键事件发生时,除了按键以外,其他修饰符按键的状态。
event.mod是一个按键修饰符的或运算组合值。
例如:KMOD_LSHIFT, KMOD_LCTRL, KMOD_LALT...
event.mod = KMOD_LSHIFT | KMOD_LALT
鼠标事件以及类型的基本使用
- pygame.event.MOUSEMOTION
该事件表示鼠标移动,只要鼠标在移动就会产生这个事件。
总共有三个返回值
event.pos 返回(X,Y)即鼠标此时的位置,相对于源点即左上角
event.rel 返回(X,Y)即鼠标相对于上一个事件运动的距离
event.buttons 返回(a, b, c)即鼠标此时三个键的状态。如果鼠标处于按下状态对应位置值为1,否则为0 - pygame.event.MOUSEBUTTONUP
该事件表示鼠标的键释放的事件。
共有两个返回值
event.pos
event.button 返回表示鼠标释放键的编号,左键为1,右键为3。 - pygame.event.MOUSEBUTTONDOWN
event.pos
event.button
壁球小游戏鼠标型
通过鼠标左键拜访壁球;
按下鼠标左键时,壁球随鼠标移动,释放鼠标时,壁球自己移动。
import sys, pygame
pygame.init()
size = width, height = (600, 400)
speed = [1, 1]
black = 0, 0, 0
fps = 300
still = False
icon = pygame.image.load("滑稽球1.jpg")
pygame.display.set_icon(icon)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("壁球小游戏鼠标版")
ball = pygame.image.load("滑稽球1.jpg")
ballrect = ball.get_rect()
fclock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
speed[0] = speed[0] if speed[0] == 0 else (abs(speed[0]) - 1) * int(speed[0] / abs(speed[0]))
elif event.key == pygame.K_RIGHT:
speed[0] = speed[0] + 1 if speed[0] > 0 else speed[0] - 1
elif event.key == pygame.K_UP:
speed[1] = speed[1] + 1 if speed[1] > 0 else speed[1] - 1
elif event.key == pygame.K_DOWN:
speed[1] = speed[1] if speed[1] == 0 else (abs(speed[1]) - 1) * int(speed[1] / abs(speed[1]))
elif event.key == pygame.K_ESCAPE:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
still = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
still = False
ballrect = ballrect.move(event.pos[0] - ballrect.left, event.pos[1] - ballrect.top)
elif event.type == pygame.MOUSEMOTION:
if event.buttons[0] == 1:
ballrect = ballrect.move(event.pos[0] - ballrect.left, event.pos[1] - ballrect.top)
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
if ballrect.right > width and ballrect.right + speed[0] > ballrect.right:
# 因为对于鼠标的控制而言,我们是设置的鼠标位置为矩形框的左上角,所以只考虑右下方突破边界的情况
speed[0] = -speed[0]
elif ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
if ballrect.bottom > height and ballrect.bottom + speed[1] > ballrect.bottom:
speed[1] = -speed[1]
if pygame.display.get_active():
if not still:
ballrect = ballrect.move(speed[0], speed[1])
screen.fill(black)
screen.blit(ball, ballrect)
pygame.display.update()
fclock.tick(fps)
但是可以注意到:小球移动到下边缘和右边缘(鼠标对应的时ballrect对象的左上角),则小球无法成功反弹,因为当小球处在边缘时会频繁取反,导致小球无法逃离边缘。当引入鼠标处理时,鼠标具有灵活性,要有对应的处理机制。
pygame事件处理函数
- 处理事件函数
(1) pygame.event.get()
用于从事件队列中获取一系列事件并删除,其中,同时也可以添加类型参数,用于获取某一类或者某些类的函数:pygame.event.get(type/typelist)
(2)pygame.event.poll()
用于从事件队列中获取一个事件,获取完即删除。
若事件队列为空,则返回:event.NOEVENT事件。
(3)pygame.event.clear()
类似于get()函数,只是区别于get函数它并不对事件进行处理,只是对时间进行删除。
同时可以增加参数,用于删除某一类或某些类的事件:
pygame.event.clear(type)
pygame.event.clear(typelist)
队列只能储存128个事件,一旦超过了队列存储的容量,新的事件只会被丢弃掉,所以一定要进行处理或者清除,同时做好事件队列的管理也非常重要 - 事件队列操作函数
(1)pygame.event.set_blocked(type or typelist)
用于设置哪个或哪些事件类型不允许进入事件队列。
(2)pygame.event.set_allowed(type or typelist)
用于设置哪个或哪些事件类型允许进入事件队列
(3)pygame.event.get_blocked(type)
用于判断某个事件类型是否被事件队列禁止,是返回True,否则False - 生成事件函数
可以用于生成事件并将产生的事件放到事件队列中。
(1)pygame.event.post(Event)
产生一个事件,并将其放入事件队列之中;
一般用于产生用户自定义类型的事件(event.USEREVENT)
也可用于放置系统事件,如鼠标/键盘相关事件,给定参数
(2)pygame.event.Event(type, dict)
创建一个给定类型的事件;
事件的属性用字典类型的键值对模式来表示;
如果创建的是已有类型的事件,需要保证属性一致。
import sys, pygame
pygame.init()
size = width, height = (600, 400)
screen = pygame.display.set_mode(size)
fps = 1
num = 1
fclock = pygame.time.Clock()
while True:
uevent = pygame.event.Event(pygame.KEYDOWN, {"unicode": "123", "key":pygame.K_SPACE, "mod":pygame.KMOD_ALT})
pygame.event.post(uevent)
num = num + 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.unicode == "":
print("[KEYDOWN {}]".format(num), "#", event.key, event.mod)
else:
print("[KEYDOWN {}]".format(num), event.unicode, event.key, event.mod)
pygame.display.update()
fclock.tick(fps)
以上内容来自北京理工大学嵩天老师及其团队的《Python游戏开发入门》课程第三周的内容。
非常感谢嵩天老师及其团队给我们带来这样优质的课程。