Python pygame(GUI编程)模块最完整教程(6)

上一篇文章:https://blog.csdn.net/qq_48979387/article/details/129219749

17 游戏手柄

参考资料:

https://pyga.me/docs/ref/joystick.html

17.1 游戏手柄结构

如图是一个游戏手柄(XBox 360 Controller),是一种外接输入设备。不同的游戏手柄包含的按键功能不同,按键发送的事件也不同。大多数游戏手柄包含几个部分:轴(axis)、球(ball)、按钮(button)、帽子(hat),数量各有不同。

Python pygame(GUI编程)模块最完整教程(6)_第1张图片

轴是一个具有调节数值功能的组件,数值范围在-1.0到1.0之间,0表示轴在中间值。轴有时候只能调节三个值:-1,0,1。

球是一个具有自由改变方向功能的组件,有时候被用于替代鼠标。球可以朝向任何一个平面上的方向。有一些电脑的键盘上有一个圆形的按钮,可以往不同方向按压它来操纵鼠标,这个按钮的功能就和球类似。

按钮是一个可以按下松开的组件。

帽子是一个控制上下左右四个方向的组件,类似于方向键。

17.2 载入游戏手柄

pg.joystick模块用于管理游戏手柄。接入同一个设备的游戏手柄可能有多个,首先需要将它们全部导入进来。每个游戏手柄都由一个Joystick对象进行管理。

joysticks = [pg.joystick.Joystick(x) for x in range(pg.joystick.get_count())]

每个Joystick对象都有一个用于标识的id,范围是0到pygame.joystick.get_count() - 1。

17.3 游戏手柄事件

游戏手柄支持一些事件:JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN, JOYBUTTONUP, JOYHATMOTION。

JOYAXISMOTION

游戏手柄的轴移动

instance_id(游戏手柄标识符), axis, value

JOYBALLMOTION

游戏手柄的球移动

instance_id, ball, rel(相对移动距离(x, y))

JOYHATMOTION

游戏手柄的帽子移动

instance_id, hat, value

JOYBUTTONUP

游戏手柄按钮松开

instance_id, button

JOYBUTTONDOWN

游戏手柄按钮按下

instance_id, button

JOYDEVICEADDED

连接到新的游戏手柄

device_index

JOYDEVICEREMOVED

游戏手柄断开连接

instance_id

17.4 使用游戏手柄的示例

此代码来自pygame.examples,有兴趣的读者可以自行研究。

import pygame

pygame.init()


# 这是一个简单的类,用于把文字显示到屏幕上。
# 它与joysticks无关,只是为了输出一些信息。
class TextPrint:
    def __init__(self):
        self.reset()
        self.font = pygame.font.Font(None, 25)

    def tprint(self, screen, text):
        text_bitmap = self.font.render(text, True, (0, 0, 0))
        screen.blit(text_bitmap, (self.x, self.y))
        self.y += self.line_height

    def reset(self):
        self.x = 10
        self.y = 10
        self.line_height = 15

    def indent(self):
        self.x += 10

    def unindent(self):
        self.x -= 10


def main():
    # 设置窗口尺寸,并设置标题
    screen = pygame.display.set_mode((500, 700))
    pygame.display.set_caption("Joystick example")

    # 用于控制屏幕的刷新速度
    clock = pygame.time.Clock()

    # 准备打印
    text_print = TextPrint()

    # 这个字典可以保持原样,
    # 因为pygame将为程序开始时连接的每个操纵杆生成一个
    # pygame.JOYDEVICEADDED事件。
    joysticks = {}

    done = False
    while not done:
        # 处理事件
        # 可能的游戏手柄事件:JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN,
        # JOYBUTTONUP, JOYHATMOTION, JOYDEVICEADDED, JOYDEVICEREMOVED
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True  # 退出循环

            if event.type == pygame.JOYBUTTONDOWN:
                print("Joystick button pressed.")
                if event.button == 0:
                    joystick = joysticks[event.instance_id]
                    if joystick.rumble(0, 0.7, 500):
                        print(f"Rumble effect played on joystick {event.instance_id}")

            if event.type == pygame.JOYBUTTONUP:
                print("Joystick button released.")

            # 处理游戏手柄的热插拔
            if event.type == pygame.JOYDEVICEADDED:
                # 该事件将在程序启动每个操纵杆时生成,无需手动创建即可填充列表。
                joy = pygame.joystick.Joystick(event.device_index)
                joysticks[joy.get_instance_id()] = joy
                print(f"Joystick {joy.get_instance_id()} connencted")

            if event.type == pygame.JOYDEVICEREMOVED:
                del joysticks[event.instance_id]
                print(f"Joystick {event.instance_id} disconnected")

        # 清除屏幕为白色
        screen.fill((255, 255, 255))
        text_print.reset()

        # 获取游戏手柄的数量
        joystick_count = pygame.joystick.get_count()

        text_print.tprint(screen, f"Number of joysticks: {joystick_count}")
        text_print.indent()

        # 遍历所有的游戏手柄
        for joystick in joysticks.values():
            jid = joystick.get_instance_id()

            text_print.tprint(screen, f"Joystick {jid}")
            text_print.indent()

            # 从操作系统中获取控制器/操纵杆的名称
            name = joystick.get_name()
            text_print.tprint(screen, f"Joystick name: {name}")

            guid = joystick.get_guid()
            text_print.tprint(screen, f"GUID: {guid}")

            power_level = joystick.get_power_level()
            text_print.tprint(screen, f"Joystick's power level: {power_level}")

            # 通常轴是成对运行的,一个是上/下,另一个是左/右。触发器算作轴。
            axes = joystick.get_numaxes()
            text_print.tprint(screen, f"Number of axes: {axes}")
            text_print.indent()

            for i in range(axes):
                axis = joystick.get_axis(i)
                text_print.tprint(screen, f"Axis {i} value: {axis:>6.3f}")
            text_print.unindent()

            buttons = joystick.get_numbuttons()
            text_print.tprint(screen, f"Number of buttons: {buttons}")
            text_print.indent()

            for i in range(buttons):
                button = joystick.get_button(i)
                text_print.tprint(screen, f"Button {i:>2} value: {button}")
            text_print.unindent()

            hats = joystick.get_numhats()
            text_print.tprint(screen, f"Number of hats: {hats}")
            text_print.indent()

            # 帽子的位置。方向要么全有要么全无,而不是像get_axis()那样的浮点数。
            # Position是一个由int值(x, y)组成的元组。
            for i in range(hats):
                hat = joystick.get_hat(i)
                text_print.tprint(screen, f"Hat {i} value: {str(hat)}")
            text_print.unindent()

            text_print.unindent()

        # 刷新屏幕
        pygame.display.flip()

        # 控制30帧每秒
        clock.tick(30)


if __name__ == "__main__":
    main()
    pygame.quit()
Python pygame(GUI编程)模块最完整教程(6)_第2张图片

17.5 joystick模块索引-游戏手柄

get_count() -> count

返回连接的游戏手柄数量

Joystick(id) -> Joystick

游戏手柄对象。

Joystick.get_instance_id() -> int

返回游戏手柄的标识符

Joystick.get_power_level() -> str

返回游戏手柄的电量情况,可能的返回值有:empty, low, medium, full, wired, max, unknown(字符串)

Joystick.get_name() -> string

返回游戏手柄的系统名称

Joystick.get_numaxes() -> int

返回游戏手柄“轴”的数量

Joystick.get_axis(axis_number) -> float

根据指定的轴返回它的值,范围在-1到1之间。0表示轴位于中间。

Joystick.get_numballs() -> int

返回游戏手柄“球”的数量

Joystick.get_ball(ball_number) -> x, y

根据指定的球返回它的值,x, y表示球相对移动的位置。

Joystick.get_numbuttons() -> int

返回游戏手柄“按钮”的数量

Joystick.get_button(button) -> bool

根据指定的按钮返回它的值,表示是否按下按钮。

Joystick.get_numhats() -> int

返回游戏手柄“帽子”的数量

Joystick.get_hat(hat_number) -> x, y

根据指定的帽子返回它的值。(0,0)表示居中。-1表示左或下,1表示右或上,所以(- 1,0)表示左;(1,0)表示右;(0,1)表示向上;(1,1)表示右上角;等等。

rumble(low_frequency, high_frequency, duration) -> bool

使游戏手柄振动。duration表示持续的时间,单位为ms

stop_rumble() -> None

停止振动。

18 摄像头

参考资料:https://pyga.me/docs/ref/camera.html

18.1 从摄像头获取图片

pg.camera.Camera对象用于管理摄像头。在使用camera前,首先需要导入pg.camera模块。camera虽然是pygame的一个子模块,但是并不是pygame中一个属性,需要额外进行导入,并且还需要额外地进行初始化。

下面的例子打印出当前系统中所有的摄像头:

import pygame as pg
from pygame import camera

camera.init()
cameras = camera.list_cameras() #获取摄像头列表
print(cameras)

list_cameras返回系统中所有摄像头的名称。如果系统没有摄像头返回[0]。

下面的示例中,从摄像头获取的图片将被显示在pygame窗口上。

import pygame as pg
from pygame import camera

pg.init()
screen = pg.display.set_mode()

camera.init()
cameras = camera.list_cameras() #获取摄像头列表

if cameras[0] != 0: #如果列表中只有0表示没有摄像头,载入为0的摄像头不会报错但是无法运行
    current_camera = camera.Camera(cameras[0]) #载入摄像头
else:
    print("没有摄像头")
    exit()

current_camera.start() #开始使用摄像头

while True:
    screen.fill((0, 0, 0))

    im = current_camera.get_image() #获取摄像头图像(只有开始使用摄像头后才能获取,否则报错)
    screen.blit(im, (0, 0))

    for event in pg.event.get():
        if event.type == pg.QUIT:
            current_camera.stop() #停止使用摄像头
            pg.quit()

    pg.display.flip()

18.2 camera模块索引-摄像头

init(backend = None) -> None

初始化摄像头模块。

list_cameras() -> [cameras]

返回一系列摄像头名称列表(如果没有摄像头返回[0])

Camera(device, (width, height), format) -> Camera

摄像头对象

Camera.start() -> None

开启摄像头(如果需要通过摄像头获取图片,开启是必需的)

Camera.stop() -> None

关闭摄像头

Camera.set_controls(hflip = bool, vflip = bool, brightness) -> (hflip = bool, vflip = bool, brightness)

设置摄像头是否进行水平翻转、垂直翻转,brightness表示设置亮度。部分摄像头可能不支持其中部分的功能。

Camera.get_controls() -> (hflip = bool, vflip = bool, brightness)

获取摄像头的水平翻转、垂直翻转、亮度。不支持的摄像头将返回默认值(0, 0, 0)

Camera.get_size() -> (width, height)

获取摄像头拍摄的图像大小

Camera.query_image() -> bool

判断摄像头是否已经准备好了图像(拍摄需要时间)

Camera.get_image(Surface = None) -> Surface

从摄像头拍摄一张图片,并返回这张图片的表面对象。如果指定Surface,则将该Surface替换为拍摄的图片以节省计算时间。

Camera.get_raw() -> bytes

从摄像头拍摄一张图片,并返回原始码

19 系统

参考资料:https://pyga.me/docs/ref/system.html

19.1 存储游戏数据

大部分的游戏都需要存储玩家信息。常用的存储方式有:存储到服务器(暂不介绍)或存储到本机。

将游戏信息存储到本机的原理很简单,只需在玩家首次进入游戏时创建一个文件,之后就可以对这个文件进行读写。这个存档文件的格式可以自行选择,如*.txt,*.json,*.p文件,常用于存储游戏信息。

将游戏数据文件存储在当前游戏文件夹中也是一个比较好的选择,而且玩家在卸载游戏时数据只需要把整个文件夹删除,同时游戏数据文件会连带着一起被卸载。但如果想要保留数据,使玩家重装游戏时存档不变,那么就需要把数据存储到一个特定的地方,独立于游戏文件夹。这个用于专门存储应用数据的文件夹在不同系统上位于不同的位置,如Windows上,这个路径默认位于C:\Users\Administrator\AppData\Roaming\

pg.system模块提供了一些针对当前系统的操作。pg.system.get_pref_path(org, app)方法返回分配好的应用数据文件夹。org表示游戏作者,app表示游戏名称(用于区分不同的应用数据)。例如:

>>> path = pg.system.get_pref_path("my_company", "app_name") #返回一个路径
>>> print(path)
C:\Users\Administrator\AppData\Roaming\my_company\app_name\

get_pref_path函数将系统应用数据文件夹与公司名、应用名组合起来,形成一个路径。如果该路径的文件夹不存在,将会新建一个。

19.2 获取系统区域设置

系统区域设置指的是一个系统的位置及语言信息,如位置:中国;语言:中文这些设置。

pg.system.get_pref_locales函数返回一个列表,包含多个字典,每个字典都含有键"language"和"country",表示语言,以及这个语言所属的国家。返回的列表按语言的首选项集降序排列。

>>> pg.system.get_pref_locales()
[{'language': 'zh', 'country': 'CN'}, {'language': 'en', 'country': 'US'}]

比如在我的系统上,位于第一个字典中的zh(中文)是第一选择;但如果没有中文,那下一个选项是en(英语)。这些语言的顺序排列是可以在系统设置中进行更改的。

为什么要有语言首选项的设定呢?
假如有一个应用,只支持中文和英文。有一位用户安装了该应用,这位用户最擅长法语,只会一点英语。在这位用户的语言排列中有法语-英语的顺序。当用户打开应用时,应用检测到了他的首选语言是法语,但这个应用并不支持法语,于是只能退而求其次选择位于第二首选的英语。
这样,就使得语言的设置更加人性化。

如果希望游戏支持多语言,那么可以通过这个方法确定当前系统使用的语言。

此外还需要注意,这个函数比较耗时,所以应该在游戏开始之前提前加载好并且将语言数据储存起来。避免循环加载。

在pygame运行时,如果检测到用户更改了当前的系统区域设置,会生成一个事件LOCALECHANGED。

20 剪贴板

参考资料:https://pyga.me/docs/ref/scrap.html

20.1 获取剪贴板中的文本

pg.scrap.get_text()方法返回剪贴板中刚刚复制的文本。

如果想要知道剪贴板中是否有文本,则应使用pg.scrap.has_text()方法,这个方法将返回一个布尔值。

20.2 复制文本到剪贴板

pg.scrap.put_text(text)用于将text字符串复制到剪贴板。

>>> pg.scrap.put_text("Hello, pygame world!") #复制
>>> pg.scrap.get_text()
'Hello, pygame world!'
>>> pg.scrap.has_text()
True

下一篇文章

制作中……有问题请联系作者

停更一段时间,作者正在弄游戏引擎

你可能感兴趣的:(Python,pygame,python)