> 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()
Transform.create(sourceEntity, { position: Vector3.create(8, 1, 8) })

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

{% hint style="warning" %}
**📔 注意**: 每个带有 `AudioSource` 的实体也需要一个 `Transform`，包括全局声音。没有它，什么都不会播放，也不会记录任何错误，这使得这个问题很难被发现。在场景编辑器中放置的物品始终都有一个 `Transform`，所以这只会影响你在代码中创建的实体。
{% endhint %}

声音文件必须位于项目文件夹内。在上面的示例中，音频文件位于一个 `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()` 函数接受以下参数：

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

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

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

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

```ts
// 创建实体
const sourceEntity = engine.addEntity()
Transform.create(sourceEntity, { position: Vector3.create(8, 1, 8) })

// 创建 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('声音播放结束')
		// 在这里响应：播放另一个声音、推进序列等。
	}

	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('音频事件 - 声音正在加载')
			break
		case MediaState.MS_READY:
			console.log('音频事件 - 声音已就绪（已加载，或播放结束）')
			break
		case MediaState.MS_PLAYING:
			console.log('音频事件 - 声音已开始播放')
			break
		case MediaState.MS_ERROR:
			console.log('音频事件 - 声音错误（例如文件加载失败）')
			break
	}
})
```

从 `MS_PLAYING` 或将 `到` MS\_READY `MediaState` 的转换表示声音已停止播放。完整的 `还包括`, `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,
	全局：true，
})
```

全局声音仍然需要一个 `Transform` 在其实体上，尽管它的位置不再影响玩家听到的内容。任何位置都可以。

## 播放一段声音

要播放较长音频文件中的一段，请使用 `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.
