> 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/kai-shi-shi-yong/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)

你也可以通过以下方式以无代码的方式触发声音播放 **操作**，见 [让任意项目变为智能项目](/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` 组件的 *真* 。

```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` 属性设为 *真*.

```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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
