> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/sounds.md).

# 声音

了解如何向场景中添加声音。

声音是为玩家的操作和事件提供反馈的绝佳方式，背景音也可以为你的场景增加更多上下文，并提升玩家的沉浸感。

{% hint style="warning" %}
**📔 注意**: 请记住，声音只会被站在构成声音生成场景的地块内的玩家听到，即使他们本来处于可听范围内也是如此。玩家也可以在设置中选择关闭所有声音。
{% endhint %}

支持的音频格式取决于浏览器，但建议使用 *.mp3*.

*.wav* 文件也受支持，但通常不推荐，因为它们要大得多。

## 播放声音

播放声音的最简单方法是添加一个 **音频源** 组件，可视化地放在 [Creator Hub 中的场景编辑器](/creator/content-creator-zh/chang-jing-bian-ji-qi/ru-men/about-editor.md) 上，并将其设置为 **开始播放** 和 **循环**。参见 [添加组件](/creator/content-creator-zh/chang-jing-bian-ji-qi/gou-jian/components.md#add-components).

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-ae588633ad20c357cfcb71a63216e4b8e02802ae%2FAudioSource-component.png?alt=media\&token=266f32b9-95c4-4d4b-a7c0-bd84d50c2dfe)

你也可以通过 **操作**以无代码方式触发声音播放，参见 [让任意项目变为智能项目](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/make-any-item-smart.md).

要通过代码播放声音，请使用 `AudioSource.playSound` 函数。

```ts
// 创建实体
const sourceEntity = engine.addEntity()

// 播放声音
AudioSource.playSound(sourceEntity, 'assets/sounds/sound-effect.mp3')
```

声音文件必须位于项目文件夹内。在上面的示例中，音频文件位于一个 `assets/sounds` 文件夹中，该文件夹位于场景项目文件夹的根目录。

{% hint style="warning" %}
**📔 注意**：该 `AudioSource` 组件必须通过以下方式导入：

> `import { AudioSource } from "@dcl/sdk/ecs"`

参见 [导入](/creator/content-creator-zh/chang-jing-sdk7/ru-men/coding-scenes.md#imports) ，了解如何轻松处理这些内容。
{% endhint %}

该 `AudioSource.playSound()` 函数接受以下参数：

* `实体`: 要将声音应用到哪个实体。声音将从该实体的位置发出，这意味着玩家越接近它，声音就越大。
* `src`: 声音文件在项目中的位置。

{% hint style="info" %}
**💡 提示**: 为了更清晰，我们建议将声音文件单独放在场景中的一个 `assets/sounds` 文件夹内。
{% endhint %}

* `resetCursor`: *（可选）* 如果为 true，声音总是从头开始播放。否则，它会从当前光标位置继续。适用于暂停和继续播放。

播放声音的另一种方法是手动创建一个 `AudioSource` 组件到一个实体上。使用这种方法可以更好地控制声音，例如让它循环播放或设置音量。

```ts
// 创建实体
const sourceEntity = engine.addEntity()

// 创建 AudioSource 组件
AudioSource.create(sourceEntity, {
	audioClipUrl: 'sounds/sound-effect.mp3',
	loop: true,
	playing: true,
})
```

可以设置以下属性：

* `audioClipUrl`: 声音文件在项目中的位置。
* `playing`: 如果为 true，声音开始播放。你可以创建一个将 `playing` 设置为 false，然后在稍后某个时间再将其设置为 true 的声音。
* `volume`: *（可选）* 音频文件的音量。默认值为 1，即满音量。
* `pitch`: *（可选）* 调整声音的音高。默认值为 1，将其调低会使声音更低沉，将其调高会使声音更尖锐。

{% hint style="info" %}
**💡 提示**: 为了防止某个音效在游戏中变得过于重复，每次播放时随机加入一些轻微的音高变化会很有帮助。
{% endhint %}

* `currentTime`: *（可选）* 默认值为 0。设置此值可避免从音频文件的开头开始播放。

每个实体只能有一个 `AudioSource` 组件，它一次只能播放一个剪辑。这个限制可以通过在播放新声音时修改音频源，或通过包含多个不可见的子实体来轻松绕过，每个子实体都有自己的声音。

{% hint style="warning" %}
**📔 注意**: 声音会在每个玩家的本地实例中播放。除非其他附近玩家的本地场景也明确播放这些声音，否则他们不会听到相同的声音。
{% endhint %}

### 预加载声音

如果某个实体使用了声音，但在场景运行时不会立即播放，那么下载它可能需要一些时间。可以通过使用 `AssetLoad` 组件。

```ts
import { AssetLoad } from "@dcl/sdk/ecs"

AssetLoad.create(engine.RootEntity, {
  assets: [
    "assets/scene/bundle1/explosionSound.mp3",
  ],
})
```

更多信息，请查看 [预加载资源](/creator/content-creator-zh/chang-jing-sdk7/you-hua/pre-load-resources.md) 文档。

## 停止声音

要停止某个实体播放其声音，请使用 `AudioSource.stopSound()` 函数。你只需要指定实体，因为每个实体只有一个 `AudioSource` 组件，并且每个 `AudioSource` 组件一次只能播放一个文件。

```ts
AudioSource.stopSound(sourceEntity)
```

另一种停止声音的方法是将 `playing` 属性设为 false。

```ts
// 创建实体
const sourceEntity = engine.addEntity()

// 创建 AudioSource 组件
AudioSource.create(sourceEntity, {
	audioClipUrl: 'sounds/explosion.mp3',
	playing: true,
})

// 定义一个简单函数
function stopSound(entity: Entity) {
	// 获取音频源组件的可变版本
	const audioSource = AudioSource.getMutable(entity)

	// 修改其 playing 值
	audioSource.playing = false
}

// 调用函数
stopSound(sourceEntity)
```

## 检测声音何时结束

当一个非循环声音自己播放完毕时，引擎会将 `playing` 组件的 `AudioSource` 属性改回 *false*。你的场景代码可以读取这个值来知道声音何时结束，例如在它结束后立即串联播放另一个声音或执行另一个动作。

```ts
let wasPlaying = false

engine.addSystem(() => {
	const audio = AudioSource.get(sourceEntity)
	const isPlaying = audio.playing ?? false

	if (wasPlaying && !isPlaying) {
		console.log('sound finished playing')
		// 在这里响应：播放另一个声音、推进序列等。
	}

	wasPlaying = isPlaying
})
```

{% hint style="warning" %}
**📔 注意**: 当每帧轮询该组件时，请始终使用 `AudioSource.get()` (只读)。使用 `AudioSource.getMutable()` 会将该组件标记为每帧都发生了变化，从而造成不必要的同步工作。

该 `playing` 属性只会在声音自行结束时由引擎翻转。如果场景显式停止声音（通过 `AudioSource.stopSound()` 或通过设置 `playing` 为 *false*），那么这个变化来自你自己的代码，而且循环声音会一直播放直到被停止，因此它们不会自行翻转该属性。
{% endhint %}

或者，使用 `audioEventsSystem.registerAudioEventsEntity` 来定义一个函数，每次实体音频的播放状态变化时都会运行，就像 [视频事件](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/video-playing.md#video-events) 对于视频一样。该函数接收一个带有 `state` 字段的事件，使用 `MediaState` 枚举。

```ts
import { engine, AudioSource, audioEventsSystem, MediaState } from '@dcl/sdk/ecs'

// ... 使用 AudioSource 组件创建 sourceEntity ...

audioEventsSystem.registerAudioEventsEntity(sourceEntity, (audioEvent) => {
	switch (audioEvent.state) {
		case MediaState.MS_LOADING:
			console.log('audio event - sound is LOADING')
			break
		case MediaState.MS_READY:
			console.log('audio event - sound is READY (loaded, or finished playing)')
			break
		case MediaState.MS_PLAYING:
			console.log('audio event - sound started PLAYING')
			break
		case MediaState.MS_ERROR:
			console.log('audio event - sound ERROR (e.g. the file failed to load)')
			break
	}
})
```

从 `MS_PLAYING` 为 `MS_READY` 的转换表示声音停止播放。完整的 `MediaState` 枚举还包括 `MS_NONE`, `MS_LOADING`, `MS_PAUSED`, `MS_BUFFERING`, `MS_SEEKING` 和 `MS_ERROR`，以及每个事件都携带一个 `时间戳` ，表示状态变化发生的时间。你也可以随时使用 `audioEventsSystem.getAudioState(entity)`，取消注册回调请使用 `audioEventsSystem.removeAudioEventsEntity(entity)`，或使用 `audioEventsSystem.hasAudioEventsEntity(entity)`。同一系统也适用于带有 [`AudioStream`](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-streaming.md) 组件。

{% hint style="warning" %}
**📔 注意**：这些功能仅受桌面客户端支持。
{% endhint %}

## 循环播放

要让声音持续循环播放，请在开始播放之前将 `loop` 组件的 `AudioSource` 字段设为 *true* 。

```ts
// 创建实体
const sourceEntity = engine.addEntity()

// 创建 AudioSource 组件
AudioSource.create(sourceEntity, {
	audioClipUrl: 'sounds/sound-effect.mp3',
	playing: true,
	loop: true,
})
```

循环声音对于添加背景音乐或其他背景音特别有用。

## 设置音量

你可以设置 `volume` 组件的 `AudioSource` 组件来更改声音的音量。

音量以从 *0* 为 *1*.

```ts
// 创建实体
const sourceEntity = engine.addEntity()

// 创建 AudioSource 组件
AudioSource.create(sourceEntity, {
	audioClipUrl: 'sounds/sound-effect.mp3',
	playing: true,
	volume: 0.5,
})
```

{% hint style="warning" %}
**📔 注意**：当然，声音的音量也会受到玩家与音频源之间距离的影响。玩家走远时，音量会更低。
{% endhint %}

## 全局声音

默认情况下，来自 `AudioSource` 的所有声音都是有位置的。这意味着它们看起来像是从 `Transform` 组件的位置发出的，并且玩家走近时声音会更响。但你也可以将声音配置为全局声音，这样无论玩家站在哪里，音量都保持恒定。这非常适合用于背景音乐、通知音效和其他非定位声音。

{% hint style="warning" %}
**📔 注意**：全局声音是仅受 DCL 2.0 桌面客户端支持的功能。
{% endhint %}

要使声音成为全局声音，请将 `global` 属性设为 *true*.

```ts
AudioSource.create(sourceEntity, {
	audioClipUrl: 'sounds/music.mp3',
	playing: true,
	global: true,
})
```

## 播放声音片段

要播放较长音频文件中的某一段，请使用 `playSoundSegment()` 在 SDK Utils 库中。参见 [SDK7 Utils](https://github.com/decentraland/sdk7-utils).

你也可以通过显式设置 `currentTime` 属性在一个 `AudioSource` 组件上，然后等待一段时间后将其停止来实现。

## 音频流

参见 [音频流](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-streaming.md) 以了解如何从外部来源播放实时音频流。

## 音频分析

参见 [音频分析](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/audio-analysis.md) 以了解如何从一个 `AudioSource` 读取实时振幅和频率数据，并基于它驱动交互式视觉效果，例如随低音脉冲的立方体或类似均衡器的条形可视化。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/sounds.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
