声响#

本页将通过介绍声音的基本知识来帮助您入门。

除了每个部分的概念之外,还可能有指向示例代码和文档的链接。

  1. 为什么听起来很重要?

  2. 声音基础知识

  3. 流加载还是静态加载?

  4. 高级回放控制

  5. 跨平台兼容性

  6. 其他音响库 (适用于高级用户)

我没耐心了!

想要跳到示例代码的用户应参考以下内容:

  1. 声音演示

  2. 声速演示

  3. 音乐控制演示

  4. Platformer Tutorial - Step 9 - Adding Sound

为什么听起来很重要?#

声音可以帮助玩家理解他们所看到的。

例如,你有没有遇到过这样的常见问题?

  • 你从来不知道的危险就在那里

  • 反应出乎意料或不合时宜的角色

  • 看似相似但却大相径庭的物品或能力

  • 不清楚的警告或确认对话框

你为此付出了多大的代价?几分钟?整个比赛过程?更重要的是,你有什么感觉?你可能不想继续玩下去了。

你可以用声音来防止这样的时刻。在上面的每个例子中,正确的音频可以提供玩家感觉游戏公平所需的信息。

声音基础知识#

加载声音#

在播放声音之前,您需要将其数据加载到内存中。

Arcade提供了两种方法来实现这一点。两者都接受相同的参数并返回一个 arcade.Sound 举个例子。

最简单的方法是使用 arcade.load_sound()

import arcade

# You can pass strings containing a built-in resource handle,
hurt_sound = arcade.load_sound(":resources:sounds/hurt1.wav")
# a pathlib.Path,
pathlib_sound = arcade.load_sound(Path("imaginary\\windows\\path\\file.wav"))
# or an ordinary string describing a path.
string_path_sound = arcade.load_sound("imaginary/mac/style/path.wav")

如果您喜欢更面向对象的样式,您可以创建 Sound 实例直接:

from arcade import Sound  # You can also use arcade.Sound directly

# Although Sound accepts the same arguments as load_sound,
# only the built-in resource handle is shown here.
hurt_sound = Sound(":resources:sounds/hurt1.wav")

请参阅以下内容以了解更多信息:

  1. 内置资源

  2. pathlib

  3. 流加载还是静态加载?

播放声音#

有两种简单的方法可以玩 Sound 对象。

一种是打电话给 Sound.play 直接:

self.hurt_player = hurt_sound.play()

另一种方法是传递一个 Sound 实例作为的第一个参数 arcade.play_sound()

# Important: this *must* be a Sound instance, not a path or string!
self.hurt_player = arcade.play_sound(hurt_sound)

两者都返回一个 pyglet.media.player.Player 。如果您希望能够停止或更改 Sound 的数据。

arcade.Sound vs pyglet's Player#

这是一个非常重要的区别:

  • 一个 arcade.Sound 是内存中音频数据的来源

  • 开始播放音频数据会返回一个新的侏儒 Player 它控制特定的回放

假设您在一个游戏中有两个非玩家角色(NPC),这两个角色都扮演相同的选择 Sound 数据。由于他们是世界上独立的角色,他们对数据的回放必须是独立的。为了做到这一点,每个全国人大都将保留这只侏儒 Player 当他们开始播放声音时返回。

例如,NPC可能足够接近用户的角色,以交谈、攻击或执行其他需要播放不同声音的动作。您将按如下方式处理此操作:

  1. 利用即将到来的NPC的侏儒 Player 停止其当前播放的步骤

  2. 如果NPC开始播放不同的声音,则存储返回的侏儒 Player

当危险的鼻咽癌或其他危险可能看不见的时候,这一点尤其重要。让无形的危险发挥声音是最容易和最受欢迎的方式之一,让他们的游戏感觉平衡,公平和有趣。

请参阅以下内容以了解更多信息:

  1. 为什么听起来很重要?

  2. 声音演示

停止的声音#

Arade的助手函数是停止播放的最简单方法。要使用它们,请执行以下操作:

  1. 执行以下操作之一:

    • 传递存储的侏儒 Playerarcade.stop_sound()

      arcade.stop_sound(self.current_playback)
      
    • 传递存储的侏儒 Player 对着声音的 stop() 方法:

      self.hurt_sound.stop(self.current_playback)
      
  2. 清除对播放器的任何引用,以释放其内存:

    # For each object, Python tracks how many other objects use it. If
    # nothing else uses an object, it will be marked as garbage which
    # Python can delete automatically to free memory.
    self.current_playback = None
    

请参阅以下内容以了解更多信息:

流加载还是静态加载?#

最好的 [1] 格式

解压缩

最佳用途

False (默认)

.wav

整个文件

2+重叠播放,简短、重复、不可预测

True

.mp3

预测数据

一次复制一个文件(&F),很长,不间断

默认情况下,arcade会将每个声音的完整内容解压到内存中。

这是大多数游戏音效的最佳选择。它被称为“静态” [2] 音频,因为数据永远不会改变。

另一种选择是流媒体。通过传递来启用它 True 通过 streaming keyword argument 当你 load a sound **

# Both loading approaches accept the streaming keyword.
classical_music_track = arcade.load_sound(":resources:music/1918.mp3", streaming=True)
funky_music_track = arcade.Sound(":resources:music/funkyrobot.mp3", streaming=True)

有关交互示例,请参阅 音乐控制演示

以下副标题将详细解释每一种选择。

静态声音适用于速度#

静态声音可以通过在游戏前预加载数据来帮助您的游戏流畅运行。

这是因为磁盘访问是计算机所能做的最慢的事情之一。在游戏过程中等待声音加载可能会使游戏运行缓慢或卡顿。防止这种情况的最好方法是提前加载您的声音数据。常用的方法包括:

  • 装载屏幕

  • 小层间“房间”

  • 多线程(最好由有经验的程序员使用)

除非音乐是游戏的核心部分,否则您应该避免将完全解压缩的音乐专辑存储在RAM中。每一分钟解压缩的CD音质音频使用略高于10MB的RAM。这会迅速增加,如果计算机完全填满RAM,则可能会减慢或冻结计算机。

对于音乐和长背景音频,您应该强烈考虑 streaming 而不是来自压缩文件。

何时使用静态声音#

如果音频文件满足以下一个或多个条件,您可能希望将其作为静态音频加载:

  • 你需要快速启动播放以响应游戏的需要。

  • 可以同时播放两个或多个声音的“副本”。

  • 您将不可预知地跳到文件中的不同时间。

  • 您将无法预测地重新开始播放。

  • 您需要自动循环播放。

  • 该文件是一个很短的剪辑。

流媒体节省内存#

文件中的音频流媒体与在线视频流媒体非常相似。

两者都通过在任何给定时间只将文件的一部分保存到内存中来节省内存。即使在最近速度最慢的硬件上,这通常也会在以下情况下起作用:

  • 一次只能流传输一个媒体源。

  • 您不需要将其与其他任何内容紧密同步。

何时播放流媒体#

使用流媒体的最好方法是只在需要的时候使用它。

高级用户可能能够一次处理多个曲目的流传输。然而,同步和中断的问题将随着所涉及的音轨的数量和质量而增加。

如果你不确定,那就避免流媒体,除非你对以下所有问题都表示肯定:

  1. 这个 Sound 一次最多只能播放一次。

  2. 这份文件足够长,值得一试。

  3. 寻找(跳到不同的部分)将不会频繁。

    • 理想情况下,您永远不会突然寻求或重新开始播放。

    • 如果你真的在寻找,理想情况下,跳跃距离足够近,可以落在同一块或下一块。

请参阅以下内容以了解更多信息:

流媒体可能会导致冻结#

不满足上述要求可能会导致缓冲问题。

对文件进行良好的压缩可以有所帮助,但不能完全克服它。每次跳过当前加载的数据需要读取并解压缩替换数据。

在最糟糕的情况下,频繁跳过将意味着不断缓冲而不是播放。尽管视频流媒体网站可能会降低质量,但您的游戏将面临结巴或冻结的风险。

处理此问题的最好方法是仅在必要时使用流。

高级回放控制#

Arade的函数用于 停止的声音 是传递的侏儒周围的方便包装纸 Player

您可以更改播放 Sound 通过以下方式提高数据的精确度:

  • 使用其属性和方法 Player 回放结束前的任何时间

  • 当传递与玩家属性相同(或相似)名称的关键字参数时 playing the sound

通过播放器对象停止#

最简单的高级控制形式是暂停和恢复播放。

暂停#

没有Stop方法。相反,可以调用 Player.pause() 方法:

# Assume this is inside an Enemy class subclassing arcade.Sprite
self.current_player.pause()

永久停止#

暂停播放器后,您可以永久停止播放:

  1. 呼叫玩家的 delete() 方法:

    # Permanently deletes the operating system half of this playback.
    self.current_player.delete()
    

    This specific playback is now permanently over, but you can start new ones.

  2. 确保所有对球员的引用都被替换为 None

    # Python will delete the pyglet Player once there are 0 references to it
    self.current_player = None
    

有关引用和自动删除的更深入的解释,请浏览 garbage collection 。阅读此页面的摘要部分应该足以开始使用。

改变播放的各个方面#

改变播放的方法比停止更多。有些则更具定性。它们中的许多都可以应用于新的和正在进行的声音数据回放,但方式不同。

通过播放器对象更改正在进行的回放#

Player.pause() 是更改正在进行的回放的各个方面的众多方法和属性成员之一。在这里不可能涵盖所有这些问题,特别是考虑到 positional audio

相反,下表总结了拱廊环境中最有用的几个成员。上标链接了有关潜在问题的信息,例如属性之间的名称差异和arcade函数的等效关键字参数。

Player 成员

类型

默认

目的

pause()

方法

不适用

可以继续暂停播放。

play()

方法

不适用

恢复暂停的播放。

seek()

方法

不适用

跳到已传递的 float 时间戳,以音频开始后的秒数为单位。

volume

float 物业

1.0

应用于原始音频音量的比例因子。必须介于 0.0 (无声)和 1.0 (全音量)。

loop

bool 物业

False

播放结束后是否自动重启播放。 [3]

pitch [4]

float 物业

1.0

播放声音数据的速度;也影响音调。

通过关键字参数配置新回放#

Arade用于播放声音的助手函数也接受用于配置回放的关键字参数。如上所述,这些关键字的名称与上的属性名称相似或相同 Player 。请参阅以下内容以了解更多信息:

跨平台兼容性#

以下各节介绍了实现兼容性的最简单方法。

如果需要,您可以尝试其他选项。请注意,要做到这一点,需要处理影响音频兼容性的许多因素:

  1. 可以加载的格式

  2. 播放所支持的功能

  3. 前两项的硬件、软件和设置限制

  4. 项目需求与上述各项之间的相互作用

最可靠的格式和功能#

对于大多数用户来说,格式化的最佳方法是:

只要用户有工作正常的音频硬件和驱动程序,以下基本功能就应该起作用:

  1. 加载声音 来自Wave文件的音效

  2. 播放声音 and 停止的声音

  3. Adjusting playback volume and speed of playback

高级功能或其子集可能不会,尤其是 positional audio 。要了解更多信息,请参阅本页面的其余部分和 pyglet's guide to supported media types

为什么选择16位PCM Wave来实现效果?#

将音效存储为16位PCM .wav 确保所有用户都可以加载它们:

  1. 小矮人 has built-in in support for this format

  2. Some platforms can only play 16-bit audio

如果您想要使用,文件也必须是单声道而不是立体声 positional audio

接受这些限制通常是值得的,尤其是作为初学者。

为什么选择MP3来播放音乐和环境音乐?#

  1. 几乎每个可以运行街机的系统都有一个受支持的MP3解码器。

  2. MP3文件比每分钟相当于Wave的音频文件小得多,这有多种好处。

请参阅以下内容以了解更多信息:

转换音频格式#

如果你有不同格式的很棒的声音,也不用担心。

有多种免费、可靠、开源的工具可以用来转换现有的音频。其中最著名的两个总结如下。

工具的名称和链接

难易

摘要

Audacity

初学者 [5]

用于编辑声音的免费图形用户界面应用程序

FFmpeg _‘S命令行工具

进阶

磁带库附带功能强大的媒体转换工具

这些工具的大多数版本应该处理以下常见任务:

  • 将音频文件从一种编码格式转换为另一种编码格式

  • 将立体声转换为单声道以与配合使用 positional audio

要将FFmpeg与Arade集成为解码器,必须使用FFmpeg版本4.x、5.x或6.x。请参见 纵深加载 了解更多信息。

纵深加载#

Arade可以通过三种方式通过Piglet读取音频数据:

  1. 内置的侏儒 .wav 加载功能

  2. 特定于平台的组件或几乎通用的库

  3. 受支持的跨平台媒体库,如PyOgg或 FFmpeg

要通过FFmpeg加载,您必须安装FFmpeg 4.x、5.x或6.x。这是由pyglet强加的要求。看见 pyglet's notes on installing FFmpeg 了解更多信息。

日常用法#

实际上,Wave得到了普遍的支持,MP3几乎也是如此。 [6]

将自己限制在这些格式中通常是值得的,因为这样做可以提高兼容性。优势包括:

  1. 下载和安装规模更小,因为依赖项更少

  2. 避免在PyInstaller和Nuitka中常见的二进制依赖关系问题

  3. 安装和加载速度更快,尤其是在低速驱动器上使用MP3时

在游戏拥堵期间,这些好处变得更加重要。

后端决定播放功能#

与格式一样,您可以通过仅使用功能之间的最低公分母来最大化兼容性。限制最严格的后端是:

  • Mac唯一的后端,仅限16位音频的OpenAL版本

  • 在Linux上的PulseAudio,它缺乏对常见功能的支持,如 positional audio

在Linux上,处理PulseAudio后端限制的最好方法是 install OpenAL 。它通常已经作为其他包的依赖项安装了。

后端之间的其他差异没有那么明显。通常,它们将是诸如支持的特定位置特征和同时发出的声音的最大数量之类的东西。

请参阅以下内容以了解更多信息:

选择音频后端#

默认情况下,Arcade将按以下顺序尝试侏儒音频后端,直到找到加载的后端:

  1. "openal"

  2. "xaudio2"

  3. "directsound"

  4. "pulse"

  5. "silent"

您可以通过 ARCADE_SOUND_BACKENDS environment variable 。以下规则适用于其值:

  1. 它必须是逗号分隔的字符串

  2. 每个名称必须是由Piglet支持的音频后端

  3. 空格无关紧要,将被忽略

例如,您可能需要在特定系统上测试OpenAL。本例首先尝试OpenAL,然后放弃使用后备。

ARCADE_SOUND_BACKENDS="openal,silent" python mygame.py

请参阅以下内容以了解更多信息:

其他音响库#

高级用户可能有理由使用其他库来处理声音。

使用Pyglet#

用于音频处理的最明显的外部库是pyglet:

  • 它保证在Arcade的声音支持支持的任何地方都能工作。

  • 它提供了比Arcade更好的媒体控制

  • 您可能已经将其部分内容直接用于 高级回放控制

请注意 arcade.Sound %s source 属性保存一个 pyglet.media.Source 。这意味着您可以从干净地使用arcade的资源和声音加载开始,并根据需要加载侏儒功能。

关于位置音频的注解#

位置音频是一组功能,可以根据游戏中的距离自动调整物理扬声器的声道音量。

尽管侏儒通过其 Player ,Arcade目前不提供集成。您将不得不自己完成设置工作。

如果你已经有一些使用Python的经验,下面的链接序列应该可以作为尝试位置音频的入门读物:

  1. 为什么选择16位PCM Wave来实现效果?

  2. 后端决定播放功能

  3. Pyglet的媒体指南的以下部分:

    1. Controlling playback

    2. Positional audio

  4. pyglet.media.player.Player 的完整文档

外部类库#

一些用户报告说,使用 PyGame CESDL2 来处理声音。这些库和其他库可能也适用于您。您将需要进行实验,因为这不是官方支持的。