среда, 28 января 2015 г.

Объёмный звук

Лирика
Часто в 2D играх не заморачиваются над объёмным звуком. И зря. Когда звук имеет своё место, то игра начинает выглядеть совершенно по другому. В ней начинает чувствоваться объём. Вот ракета взорвалась где-то слева, вот справа слышны шаги врага. И это уже не обязательно видеть, вы это слышите. А если звучащее событие происходит где-то за экраном вы можете планировать свои действия в зависимости от звуков. Это очень здорого. Как этого добиться?

Теория
По настоящему объёмный звук нам, увы, не доступен. Но имея 2 колонки и регулятор громкости можно сделать много. Чем дальше звук от центра камеры — тем от тише. Чем левее — тем громче звучит левая колонка и тем тише — правая. В AS3 мы можем управлять громкостью (volume) и панорамой (pan) звучания. Воспользовавшись этим у нас получается следующее.

Код
public class Sfx3D {
  // модификатор громкости
  static public const VOL_MOD:Number = 0.8;
  // модификатор панорамы
  static public const PAN_MOD:Number = 2.5;
  // размер области от центра, в которой будет звук
  static public var size:Point = new Point(1, 1);
  // центр экрана с учётом игровой камеры
  static public var center:Point = new Point(1, 1);

  static public function play3D(snd:Sound, x:Number, y:Number):SoundChannel {
    if(snd == null) return null;
    // горизонтальный коэффициент
    var dist_x:Number = ((x - center.x) / size.x);
    // вертикальный коэффициент
    var dist_y:Number = ((y - center.y) / size.y);
    // горизонтальная громкость
    var vol_x:Number = (1 - Math.abs(dist_x * VOL_MOD));
    // вертикальная громкость
    var vol_y:Number = (1 - Math.abs(dist_y * VOL_MOD));
    // финальная громкость
    var vol:Number = Math.min(1, Math.max(0, Math.min(vol_x, vol_y)));
    // в простейшем случае звуки короткие и не меняют свою позицию, обновлять её
    // не надо и можно вообще не проигрывать звук, если громкость == 0
    if (vol <= 0) return null;
    // панорама
    var pan:Number = dist_x * PAN_MOD;
    pan = Math.min(1, Math.max( -1, pan));
    // и, наконец, можно играть звук
    var st:SoundTransform = new SoundTransform(vol, pan);
    return snd.play(0, 0, st);
  }
}

Используем так:
// ...ПРИ ИНИЦИАЛИЗВЦИИ ИГРЫ...
// половина экрана - область от центра до края экрана
Sfx3D.size.x = SCREEN_WIDTH * 0.5;
// по горизонтали
Sfx3D.size.y = SCREEN_HEIGHT * 0.5;
// тут можно умножать, скажем, на 0.7, чтобы виртуально увеличить экран,
// чтобы панорама рассчитывалась по другому, экспериментируйте. По сути
// это модификатор размера экрана (:

// ...ПРИ ОБНОВЛЕНИИ КАМЕРЫ...
// где CAMERA_X - это центр экрана по горизонтали
Sfx3D.center.x = CAMERA_X;
// где CAMERA_Y - это центр экрана по вертикали
Sfx3D.center.y = CAMERA_Y;
// ...ПРОИГРЫВАЕМ ЗВУК...
// SOUND - ранее созданный звук, POS_X и POS_Y - координаты звука на плоскости
Sfx3D.play3D(SOUND, POS_X, POS_Y);


Модификаторы.
Модификатор PAN_MOD позволяет немного усилить объём. Скажем, если у нас получается pan = 0.1, то не натренированное ухо может и не заметить, что звук несколько правее центра. Применяя модификатор у нас получается значение 0.25, что воспринимается несколько лучше. При этом pan всё равно обрезается от -1 до 1.
VOL_MOD позволят звучать звукам за пределами экрана. Подбирая разные коэффициенты можно добиться нужного эффекта для разных размеров экрана.

P.S. Нашёл баг блога. При сохранении в черновики обязательно наличие Меток, при этом сами Метки не сохраняются и приходится их писать по новой.

Комментариев нет:

Отправить комментарий