Движок Grim: логика аудиоредактора в визуальной новелле и интеграция FMOD

Привет! Сегодня поговорим о том, как устроена внутренняя логика аудио-событий и почему наш пайплайн работы со звуком больше напоминает интерфейс DAW (цифровой звуковой рабочей станции), чем типичный движок для новелл.

Концепция «Ивент»-лайнов и каретки

При проектировании системы событий мы решили адаптировать принцип работы многодорожечных редакторов вроде Reaper или Ableton. Происходящее в игре представлено как набор параллельных таймлайнов, по которым движется виртуальная каретка.

Вместо секунд каретка считывает «ивенты» на четырех основных слоях:

  1. Бэкграунд (смена фонов и освещения).
  2. Текст (вывод диалоговых строк).
  3. Доп. спрайты (управление появлением и прозрачностью персонажей).
  4. Звук (триггеры аудиособытий).

Как только каретка пересекает определенную точку на ивент-лайне, движок

Интеграция FMOD и адаптивность

Для работы с аудио мы используем FMOD. Несмотря на то, что движок кастомный, работа со звуковыми эффектами (Gain, Fade) происходит не через голый код, а через интерфейс FMOD, который по логике управления и наличию регуляторов сильно напоминает стандартные DAW.

Основная техническая сложность здесь заключается в адаптивности. В отличие от линейного трека в аудиоредакторе, автоматизация в игре должна учитывать динамику сцены. Звук проектируется с учетом того, что длина пауз или скорость чтения текста у игроков могут отличаться.

Типы звуков и диктатура словарей

Все звуки в Grim мы делим на две категории:

  • Фоновый ambience: Шум улицы, гул ламп, голоса. Они работают в циклическом режиме.
  • Событийные звуки (SFX): Конкретные триггеры внутри сцены — вздох, удар по столу или щелчок плеера.

Пока у движка нет визуального редактора для наполнения сцен, все связи настраиваются программно через словари в скриптах (например, intro.gd). Метод prepareSounds() регистрирует ресурсы, а словарь snd_play_lines_start определяет, на какой строке текста должен сработать триггер.

Система Parts: привязка к символам

Одной привязки к строкам часто недостаточно. Чтобы звук сработал в конкретный момент реплики (например, на 22-й букве, где персонаж делает паузу), используется parts.

codePython

flash_in_parts_end = {

"policeman": { 41 : [22] }, # На 41-й строке, при выводе 22-й буквы сработает звук

}

Эта система значительно упрощает взаимодействие со вторым типом звуков (SFX). Технически это выглядит как прохождение каретки через чекпоинты внутри текстового массива, что позволяет синхронизировать аудио с визуальным выводом букв.

Мы задали пару вопросов по технической части Роме — саунд-дизайнеру проекта

Вопрос:
Сложно ли возиться с Gain и Fade в связке с движком? Насколько это вообще кропотливая настройка?
Рома:
Работа в нём сильно напоминает DAW (я всё делаю в Ableton), поэтому с «крутилками» проблем нет. Единственное — вся автоматизация должна делаться с учётом адаптивности, нужно просто думать немного в другую сторону.

Godot
Godot

Вопрос:
Насколько реально помогает система «parts» (привязка звука к конкретным буквам) в твоей работе?
Рома:
Эта штука просто упрощает взаимодействие со событийными звуками — условными вздохами или ударами по столу. Это простая и понятная настройка триггеров, которая позволяет быстро «подшить» звук к нужному моменту в диалоге.

Ableton
Ableton

Итоги

Использование логики аудиоредактора позволяет нам гибко настраивать сцены, хотя это и требует ручного внесения данных в словари. Скоро мы расскажем подробнее о процессе создания музыки для Grim, а пока — оценить работу движка и звука можно в веб-фрагменте главы Лизы.

Веб-фрагмент: https://thunderdum.github.io/thunderdum/
Grim в Steam: https://store.steampowered.com/app/3606000/Grim/

1
1
2 комментария