声明

本教程中一些例子使用了酒石酸大大中的女仆模组中的代码内容,只在做出解释,侵删。

添加声音

注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ModSounds {
public static final DeferredRegister<SoundEvent> SOUND_EVENT = DeferredRegister.create(Registries.SOUND_EVENT, FlansMod.MOD_ID);

public static final Supplier<SoundEvent> ATTACK1 = registerSound("item.sv371_1_attack1");

private static Supplier<SoundEvent> registerSound(String name) {
return SOUND_EVENT.register(name, () -> SoundEvent.createFixedRangeEvent(new ResourceLocation(FlansMod.MOD_ID, name), 16.0F));
}

public static void register(IEventBus eventBus){
SOUND_EVENT.register(eventBus);
}

}

声音文件

1
2
3
4
5
6
7
8
9
10
11
├───assets
│ └───flansmod
│ ├───models
│ │ └───item
│ ├───sounds
│ │ └───item
│ └───textures
│ ├───block
│ ├───entity
│ └───item

其中sounds文件是存声音的。

声音json

这里是sounds.json的介绍文档

sounds.json – Minecraft Wiki (fandom.com)

-

The root Object.

根对象。

-

 *Sound Event*


声音事件:声音事件。名称通常按类别分隔(例如 `entity.enderman.stare` )。下表列出了所有默认声音事件。 (要获得与 `minecraft` 不同的命名空间,该文件必须位于不同的命名空间下;此处不进行定义。)

-  **replace**:真true/假false。仅在资源包中使用。如果声音中列出的声音应替换此声音事件的默认 Sounds.json 中列出的声音,则为 True。如果列出的声音应添加到默认声音列表中,则为 False。选修的。如果未定义,则默认为“false”。
-  **subtitle**: 如果在游戏中启用了显示字幕,则翻译为声音的字幕。接受格式化代码并在游戏中正确显示它们。选修的。
-  sounds:此声音事件使用的声音文件。当触发此声音事件时,会随机选择所列出的声音之一来播放。选修的。
  -  “namespace/sounds”文件夹中声音文件的路径(不包括 .ogg 文件扩展名)。使用正斜杠。命名空间默认为 `minecraft` 但可以通过在前面添加命名空间并用 `:` 分隔来更改。
  - 
    一个声音文件。仅当声音需要额外的字符串时才使用此对象。
    -  **name**: “namespace/sounds”文件夹中该声音文件的路径(不包括 .ogg 文件扩展名)。命名空间默认为 `minecraft` 但可以通过在前面添加命名空间并用 `:` 分隔来更改。使用正斜杠而不是反斜杠。可能是另一个声音事件的名称(根据“type”的值)。请注意,声音文件必须有一个通道(单声道)。
    -  **volume**:音量:播放该声音的音量。值是 0.0 到 1.0 之间的小数。如果未定义,则默认为 1.0。
    -  **pitch**:音高:以指定值播放音高。如果未定义,则默认为 1.0,但可以选择更高和更低的值。
    -  **weight**: 权重:触发该声音事件时,该声音被选择播放的几率。默认为 1。示例:在值中输入 2 就像在名称中输入两次一样。只接受整数。
    -  **stream**: true/false. 真/假。如果该声音应从其文件中流式传输,则为 true。对于持续时间超过几秒的声音,建议将其设置为“true”以避免滞后。用于“音乐”和“录音”类别中的所有声音(音符块声音除外),因为(几乎)所有属于这些类别的声音都超过一分钟长。选修的。如果未定义,则默认为“false”。将其设置为 false 允许同时运行更多的声音实例,而将其设置为 true 则仅允许同时运行 4 个(该类型的)实例。
    - **attenuation_distance**:attenuation_distance:根据距离修改声音衰减率。由门户、信标和管道使用。默认为 16。
    -  **preload**: true/false.预加载:真/假。如果应在加载包时而不是播放声音时加载此声音,则为 true。由水下环境使用。默认为“假”。
    -  **type**:有两个值:“sound”和“event”; “sound”导致“name”的值被解释为文件的名称,而“event”导致“name”的值被解释为已定义事件的名称。如果未定义,则默认为“声音”。

sounds.json 位于 modid文件夹下和model等是同一级目录

flansmod 是modid

1
2
3
4
5
6
7
8
9
10
11
12
{
"item.sv371_1_attack1": {
"category": "voice",
"subtitle": "subtitle.flansmod.item.sv371_1_attack1",
"sounds": [
{
"name": "flansmod:item/sv371_1_attack1",
"stream": "true"
}
]
}
}

使用声音

Level 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

// ...
/**
* 在指定位置播放声音。服务器端会向所有附近玩家广播声音,除了指定的玩家。
* 客户端端仅当指定的玩家是客户端玩家时播放声音。这个方法旨在从两边运行代码时被调用。
* 客户端本地播放,服务器端为其他所有人播放。
*
* @param pEntity 指定的实体,如果是玩家实例,则不会向该玩家播放声音
* @param pPos 声音播放的位置
* @param pSound 要播放的声音事件
* @param pCategory 声音来源类别
* @param pVolume 声音的音量
* @param pPitch 声音的音调
*/
public void playSound(@Nullable Entity pEntity, BlockPos pPos, SoundEvent pSound, SoundSource pCategory, float pVolume, float pPitch) {
this.playSound(pEntity instanceof Player player ? player : null, pPos, pSound, pCategory, pVolume, pPitch);
}
// ...
/**
* 在指定位置播放有种子值的声音。这允许通过种子值来生成变化的声音,例如用于随机的环境效果。
*
* @param pPlayer 指定的玩家,如果是客户端玩家,则在该客户端播放声音
* @param pX 声音播放的X坐标
* @param pY 声音播放的Y坐标
* @param pZ 声音播放的Z坐标
* @param pSound 要播放的声音事件
* @param pCategory 声音来源类别
* @param pVolume 声音的音量
* @param pPitch 声音的音调
* @param pSeed 用于生成声音的随机种子值
*/
public abstract void playSeededSound(
@Nullable Player pPlayer,
double pX,
double pY,
double pZ,
Holder<SoundEvent> pSound,
SoundSource pCategory,
float pVolume,
float pPitch,
long pSeed
);
// ...
/**
* 在实体的位置播放本地声音,即仅在该实体所在的客户端播放。
*
* @param pEntity 播放声音的实体
* @param pSound 要播放的声音事件
* @param pCategory 声音来源类别
* @param pVolume 声音的音量
* @param pPitch 声音的音调
*/
public void playLocalSound(Entity pEntity, SoundEvent pSound, SoundSource pCategory, float pVolume, float pPitch) {
// 实现细节
}
// ...

SoundSource类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* SoundSource 枚举定义了不同的声音来源类别,用于在游戏中播放和管理声音。
* 每个声音来源类别都有其特定的用途和配置,可以在音量、音调和其他音频设置上进行调整。
*/
public enum SoundSource {
/**
* 主音量控制,影响所有声音。
*/
MASTER("master"),
/**
* 音乐音量控制,仅影响音乐相关的声音。
*/
MUSIC("music"),
/**
* 唱片音量控制,仅影响唱片机播放的声音。
*/
RECORDS("record"),
/**
* 天气音量控制,仅影响天气相关的声音,如雨声、雷声等。
*/
WEATHER("weather"),
/**
* 方块音量控制,仅影响方块交互产生的声音,如脚步声、方块放置和破坏声等。
*/
BLOCKS("block"),
/**
* 敌对生物音量控制,仅影响敌对生物产生的声音,如怪物咆哮声等。
*/
HOSTILE("hostile"),
/**
* 中立生物音量控制,仅影响中立生物产生的声音,如动物叫声等。
*/
NEUTRAL("neutral"),
/**
* 玩家音量控制,仅影响玩家产生的声音,如玩家移动、跳跃和攻击声等。
*/
PLAYERS("player"),
/**
* 环境音量控制,仅影响环境声音,如森林中的鸟鸣声等。
*/
AMBIENT("ambient"),
/**
* 语音音量控制,仅影响语音聊天和其他玩家语音产生的声音。
*/
VOICE("voice");

/**
* 枚举值的名称,通常用于配置文件或与音频系统交互。
*/
private final String name;

/**
* 构造一个新的SoundSource枚举值。
*
* @param pName 枚举值的名称
*/
private SoundSource(String pName) {
this.name = pName;
}

/**
* 获取SoundSource枚举值的名称。
*
* @return 枚举值的名称
*/
public String getName() {
return this.name;
}

}

使用各个类提供的方法

例如Player下面的playerSound方法

1
2
3
4
@Override
public void playSound(SoundEvent pSound, float pVolume, float pPitch) {
this.level().playSound(this, this.getX(), this.getY(), this.getZ(), pSound, this.getSoundSource(), pVolume, pPitch);
}

例如

1
2
3
4
5
6
7
8
9
10
// player 类中的
playerIn.playSound(effect.getSoundEffect().get(),1f,1f);


// Entity 类中的
this.playSound(InitSounds.BOX_OPEN.get(), 3.0f, 1.0f);

// 直接调用level的playersound方法
player.level.playSound(null, player.blockPosition(), InitSounds.COMPASS_POINT.get(), SoundSource.PLAYERS, 0.8f, 1.5f);