Скрипт умеет проигрывать свои звуковые файлы: wav, mp3 и ogg. Это не звуки Minecraft, их не нужно класть в ресурспак и как-то регистрировать: положил файл рядом со скриптом и позвал sound.play. Всё это живёт в глобале sound (он же audio).
Путь считается от папки со скриптами, так что достаточно имени файла. Можно дать и полный путь с диска, и ссылку: файл по ссылке клиент скачает к себе в кеш и заиграет, как только тот приедет. Скачанное остаётся в кеше, поэтому второй раз звук стартует сразу.
@command("beep")
def beep(ctx):
"""Проиграть звук"""
sound.play("beep.wav")
# Файл лежит в подпапке рядом со скриптом
sound.play("audio/hit.mp3")
# Ссылка: клиент скачает файл сам
sound.play("https://example.com/alert.ogg")Форматов три: wav, mp3 и ogg. Тип определяется по содержимому файла, а не по расширению, так что файл без расширения тоже заиграет.
Всё настраивается прямо в вызове. Громкость - доля от единицы, скорость - множитель (он меняет и высоту тона, как у пластинки), loop зацикливает звук, пока его не остановят.
sound.play("hit.wav", volume=0.4)
sound.play("hit.wav", volume=0.4, speed=1.25)
# Фоновая музыка: играет по кругу, пока скрипт загружен
music_loop = sound.loop("ambient.mp3", volume=0.2)
# Остановить
music_loop.stop()Громкость по умолчанию считается от ползунков звука в настройках игры: игрок убавил общий звук - твой звук тоже стал тише. Ползунок выбирается параметром category: master, music, players, blocks, ambient и остальные из настроек звука. Значение none отвязывает звук от игры совсем.
# Тише вместе с ползунком "Музыка"
sound.play("ambient.mp3", volume=0.5, category="music")
# Ползунки игры не учитываются вообще
sound.play("alert.wav", category="none")Любой вызов возвращает объект звука. Его можно сохранить и потом останавливать, ставить на паузу, крутить громкость и спрашивать, сколько уже отыграно.
track = sound.load("ambient.mp3", volume=0.3, loop=True)
m = Module("Ambient", "Other")
@events.on("module_toggled")
def toggled(event):
if event.getModule().getName() != "Ambient":
return
if m.isEnabled():
track.play()
else:
track.stop()
@events.on("tick")
def tick():
if track.playing:
# Плавно приглушаем к концу трека
left = track.duration - track.position
if left < 3:
track.volume(0.3 * left / 3)| Метод | Что делает |
|---|---|
play() / stop() | Запустить с начала, остановить |
pause() / resume() / toggle() | Пауза и продолжение с того же места |
volume(v) / volume() | Поставить громкость или узнать текущую |
speed(v) / speed() | Скорость и высота тона, от 0.25 до 4 |
loop(True) | Играть по кругу |
category(name) | Ползунок игры, от которого считается громкость |
on_end(fn) | Позвать fn, когда звук доиграет сам |
playing / paused | Звучит ли прямо сейчас, стоит ли на паузе |
position / duration | Сколько отыграно и сколько всего, в секундах |
path | Путь, с которым звук завели |
on_end срабатывает только на естественный конец: после stop() и после выгрузки скрипта колбэк не зовётся. У зацикленного звука его не будет вовсе.
intro = sound.load("intro.wav")
main = sound.load("main.mp3", loop=True)
intro.on_end(lambda: main.play())
intro.play()sound.play держит по одному звуку на файл: позвал второй раз - тот же звук начнётся заново. Для звука удара это как раз то, что нужно, а вот когда удары идут очередью и должны накладываться друг на друга, нужен sound.once: он заводит отдельный голос и убирает его сам, как только тот доиграет.
@events.on("attack")
def on_attack(event):
# Каждый удар слышно отдельно, даже если они идут подряд
sound.once("hit.wav", volume=0.5)| Вызов | Что делает |
|---|---|
sound.play(path, ...) | Проиграть с начала; один голос на файл |
sound.once(path, ...) | Отдельный голос: звуки накладываются друг на друга |
sound.loop(path, ...) | То же, что play(..., loop=True) |
sound.load(path, ...) | Подготовить звук, не запуская |
sound.stop(path) | Остановить звук этого файла |
sound.stop() / sound.stop_all() | Остановить все звуки скрипта |
sound.playing() | Сколько звуков скрипта звучит прямо сейчас |
Именованные параметры у всех вызовов одинаковые: volume, speed, loop, category, on_end, а у sound.play ещё и overlap=True - это то же самое, что once.
| Правило | Почему |
|---|---|
| Звуки глохнут вместе со скриптом | Выгрузка и перезагрузка скрипта останавливает всё, что он завёл. Зацикленная музыка не переживёт правку файла, и это правильно: выключить её было бы уже нечем |
| Длинные файлы играются с диска | Короткие остаются разобранными в памяти, поэтому звук клика или удара стартует мгновенно. Трек на несколько минут читается по мере проигрывания и памяти не занимает |
| Звук не привязан к позиции в мире | Он звучит ровно так, как записан в файле, без затухания по расстоянию и без панорамы. Нужен звук от точки в мире - считай громкость сам по расстоянию до неё |
| Файл нужен игроку, а не только тебе | Скрипт с звуком, которого нет у игрока, просто выдаст ошибку. Либо клади файл в архив рядом со скриптом, либо давай ссылку |