Python游戏开发(二)

pygame屏幕与事件

pygame屏幕绘制机制

指的是控制游戏的屏幕变化的机制。

pygame绘制机制简介

使用pygame.display来控制游戏的屏幕,在pygame游戏中只有一个屏幕,只有关闭一个屏幕才能使用另一个屏幕。
屏幕使用的是笛卡尔坐标系。左上角为(0,0 )。
通常而言,屏幕控制都有以下的若干需求:

  1. 游戏全屏
  2. 游戏屏幕大小可调节
  3. 游戏屏幕无边框
  4. 更改游戏标题栏内容
  5. 更改游戏图标

pygame提供了三组屏幕控制的函数:

  1. 屏幕模式和尺寸的控制
    pygame.display.set_mode() 设置屏幕的相关模式
    pygame.display.info() 生成屏幕的信息
  2. 窗口标题和图标
    pygame.display.set_caption() 设置标题信息
    pygame.display.set_icon() 设置图标信息
    pygame.display.get_caption() 获得图标
  3. 窗口感知和刷新
    pygame.display.get_active()
    pygame.display.flip()
    pygame.display.update()

pygame甚至还支持openGL和硬件加速,但一般来说不会用到。

pygame游戏屏幕尺寸和模式设置

  1. 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可能出现屏幕分辨率不协调的情况。

  1. pygame.display.Info()
    这个函数用来产生一个VideoInfo对象,这个对象用来存储当前的屏幕参数信息。
    如果在set_mode()之前调用,则显示当前系统的参数。
    其中有两个重要的参数:
    .current_w:游戏窗体的宽
    .current_h:游戏窗体的高

  2. 如果窗口大小改变:
    会产生一个pygame.VIDEORESIZE,通过event.size元组返回了新的窗口的大小。
    可以用event.size[0], event.size[1]分别获得改变后的窗口大小

pygame的窗口标题和图标设置

  1. pygame.set_caption(title, icontitle=NONE)
    title设置窗口标题
    icontitle设置窗口图标标题,有些系统不支持这一设置所以一般不设置。

  2. pygame.get_caption()
    返回一个元组类型,其中第一个元素为title第二个元素为icontitle。
    该函数可以增加游戏情节,通过交互是的游戏的标题发生变化。

  3. pygame.set_icon(surface)
    surface对象即之前获取小球图像的图标的对象。
    可以设置图标。
    注意需要在屏幕创建前设置好。

pygame窗口感知和刷新功能

  1. pygame.display.get_active()
    当窗口在系统中未被图标化(最小化到状态栏)则返回True,反之则返回False。
    通过感应游戏是否被最小化来改变游戏的逻辑。

  2. pygame.display.flip()
    会将整个窗口重新绘制

  3. pygame.display.update()
    只重绘窗口中有变化的部分。

pygame事件处理机制

在游戏中,事件的处理是很重要的,它能响应用户的输入。
能够操作键盘以及鼠标等各种外设。

pygame事件处理机制

游戏响应外部的输入(如鼠标、键盘等等),以及在游戏运行中,一些情节的触发也可以通过事件系统进行实现。游戏本身也可以产生一些事件来实现游戏剧情的推进。
逻辑上,pygame有一个叫事件队列的结构,可以缓存pygame接受的所有事件,之后逐一取出事件来操作。
本质上数据是一种数据结构,pygame.even.EventType只有属性,没有方法。
用户也可以定义新的事件类型。
pygame主要包含六大类事件:鼠标、键盘、游戏手柄、系统、窗口以及用户定义事件。
pygame还有事件处理机制来对事件队列进行规范处理。

pygame键盘事件类型与使用

pygame支持两种键盘事件,分别是键盘按下事件pygame.event.KEYDOWN和键盘释放事件pygame.event.KEYUP(只在按下的情况下会触发)。

  1. 当键盘按下时事件会返回三个属性:
    event..key 键盘值
    event.unicode 键盘值对应的unicode但是可能会随系统而变化。
    event.mod 按键修饰符组合值
  2. 而键盘释放事件不返回unicode属性。
  3. 按键的常量名称
    基本上就是pygame.K_a...也即下划线后跟按键名称。
    注意字母是小写的,大写字母的输入需要通过按键修饰符来实现。
  4. 按键的修饰符
    修饰符:按键事件发生时,除了按键以外,其他修饰符按键的状态。
    event.mod是一个按键修饰符的或运算组合值。
    例如:KMOD_LSHIFT, KMOD_LCTRL, KMOD_LALT...
    event.mod = KMOD_LSHIFT | KMOD_LALT

鼠标事件以及类型的基本使用

  1. pygame.event.MOUSEMOTION
    该事件表示鼠标移动,只要鼠标在移动就会产生这个事件。
    总共有三个返回值
    event.pos 返回(X,Y)即鼠标此时的位置,相对于源点即左上角
    event.rel 返回(X,Y)即鼠标相对于上一个事件运动的距离
    event.buttons 返回(a, b, c)即鼠标此时三个键的状态。如果鼠标处于按下状态对应位置值为1,否则为0
  2. pygame.event.MOUSEBUTTONUP
    该事件表示鼠标的键释放的事件。
    共有两个返回值
    event.pos
    event.button 返回表示鼠标释放键的编号,左键为1,右键为3。
  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. 处理事件函数
    (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个事件,一旦超过了队列存储的容量,新的事件只会被丢弃掉,所以一定要进行处理或者清除,同时做好事件队列的管理也非常重要
  2. 事件队列操作函数
    (1)pygame.event.set_blocked(type or typelist)
    用于设置哪个或哪些事件类型不允许进入事件队列。
    (2)pygame.event.set_allowed(type or typelist)
    用于设置哪个或哪些事件类型允许进入事件队列
    (3)pygame.event.get_blocked(type)
    用于判断某个事件类型是否被事件队列禁止,是返回True,否则False
  3. 生成事件函数
    可以用于生成事件并将产生的事件放到事件队列中。
    (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游戏开发入门》课程第三周的内容。
非常感谢嵩天老师及其团队给我们带来这样优质的课程。

上一篇:21.5.25 制作人物移动脚本


下一篇:JQuery 高级 复学 ->(个人学习记录笔记)