Лирика
Часто в 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. Нашёл баг блога. При сохранении в черновики обязательно наличие
Меток, при этом сами Метки
не сохраняются и приходится их писать по новой.