Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
сообщить о нарушении
Текущая страница: 13 (всего у книги 35 страниц) [доступный отрывок для чтения: 13 страниц]
Тоновая последовательность – это набор звуков, воспроизводимых в определенном порядке. Такие последовательности очень часто применяются при создании игр. Используя последовательности тонов, вы можете программировать музыку, а это не такая простая задача. Ниже приведены основные шаги, которые необходимо выполнить, чтобы воспроизвести звуковую последовательность средствами MIDP 2.0 Media API:
1. создать проигрыватель;
2. реализовать проигрыватель;
3. получить тональное управление проигрывателя;
4. установить тональную последовательность;
5. использовать проигрыватель для воспроизведения последовательности;
6. закрыть проигрыватель.
Создается впечатление, что это не такая уж простая задача, но не все так плохо. Самая хитрая часть кода – это создание структуры данных, представляющей тоновую последовательность. После того как последовательность создана, ее установка и воспроизведение выполняются парой строк.
Тоновая последовательность хранится внутри массива типа byte, каждый байт массива имеет свое особое значение. Как только вы научитесь создавать такие массивы, размещая информацию в нужных местах, вы увидите, что это не так уж и сложно. Чтобы задать тоновую последовательность как массив типа byte, необходимо использовать ряд констант, определенных в интерфейсе ToneControl. Ниже приведен список наиболее важных констант:
► VERSION – версия тоновой последовательности (обычно равно 1 для новой последовательности);
► TEMPO – темп тоновой последовательности (скорость воспроизведения);
► BLOCK_START – начальный блок тонов;
► BLOCK_END – конец блока тонов;
► PLAY_BLOCK – воспроизводимые ноты, включая блоки.
Блок в тоновой последовательности – это фрагмент тоновой последовательности. Например, если у вас есть музыкальный фрагмент, который повторяется несколько раз во время звучания музыки, то вы можете поместить его ноты в блок, а затем, вместо того чтобы записывать ноты вновь, просто сослаться на блок нот. Константа PLAY_BLOCK ставится в том месте, где следует воспроизвести блок. Вы можете указать отдельные ноты или их последовательность, используя константу PLAY_BLOCK.
Я понимаю, что это рассуждение, вероятно, не так легко воспринять, поскольку сложно представить, как константа может символизировать блок тонов. Поэтому давайте рассмотрим пример. Ниже приведен код тоновой последовательности песни, которая, вероятно, вам знакома:
byte[] marylambSequence = {
ToneControl.VERSION, 1,
ToneControl.Tempo, 30,
ToneControl.BLOCK_START, 0, //Секция А песни
E4, 8, D4, 8, C4, 8, D4, 8,
E4, 8, E4, 8, E4, 8, rest, 8,
ToneControl.BLOCK_END, 0,
ToneControl.PLAY_BLOCK, 0, //Этот код воспроизводит секцию А
D4, 8, D4, 8, D4, 8, rest, 8 //Воспроизвести секцию В
E4, 8, G4, 8, G4, 8, rest, 8,
ToneControl.PLAY_BLOCK, 0, //Воспроизвести секцию А снова
D4, 8, D4, 8, E4, 8, D4, 8, C4, 8 //воспроизвести секцию С
};
Как видно, версия последовательности равна 1, а темп – 30. Темп измеряется количеством ударов в минуту, но когда вы задаете темп байтовым значением, вы должны разделить значение бита на 4. В данном случае темп равен 120 ударам в минуту.
Константа BLOCK_START открывает блок «А». Обозначение «А» ничего особенного не значит, оно просто выделяет фрагмент тональной последовательности. В примере программируется песня «Mary Had a Little Lamb» («У Мэри был маленький ягненок»), а фрагменты нот воспроизводятся в следующем порядке: A-B-A-C. Иначе говоря, блок «А» воспроизводится дважды: один раз в начале, а затем после фрагмента B. Поскольку фрагменты B и C не повторяются, то нет необходимости выделять их в отдельные блоки.
Каждая нота в последовательности определяется парой значений, которые задают высоту и длительность звука. Например, в блоке А нота Е4 имеет длительность 8, что соответствует одной восьмой. В таблице 8.3 приведены значения наиболее часто используемых длительностей.
Таблица 8.3. Длительности нот и соответствующие им значения
Чтобы лучше разобраться с последовательностью нот, взгляните на рис. 8.2, на котором представлены ноты и их соответствие тоновым данным.
Рис. 8.2. Песню «Mary Had a Little Lamb» можно запрограммировать тоновой последовательностью
Вернемся к тоновой последовательности для этой песни. Я не объяснил, как используется переменная rest. Эта переменная используется для установления паузы в последовательности. Константа SILENCE означает тишину в тоновой последовательности. Ниже приведено объявление переменной rest:
byte rest = ToneControl.SILENCE;
После того как вы задали тоновую последовательность массивом типа byte, вы можете воспроизвести рингтон. Сначала необходимо создать проигрыватель, который сможет воспроизвести тоновую последовательность. Вот как можно это сделать:
Player tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
Константа TONE_DEVICE_LOCATOR говорит о том, что вы создаете проигрыватель для воспроизведения тонов. Как только вы создали проигрыватель, необходимо зарезервировать для него ресурсы:
tonePlayer.realize()
Чтобы установить последовательность на воспроизведение, необходимо получить доступ к управлению тонами проигрывателя. Все, что для этого нужно, – вызвать метод getControl():
ToneControl toneControl =(ToneControl)tonePlayer.getControl(«ToneControl»);
Получив тоновый контроль, смело вызывайте метод setSequence(), чтобы задать воспроизводимую последовательность. При этом понадобится передать созданный ранее массив типа byte:
toneControl.setSequence(marylambSequence);
И, наконец, чтобы воспроизвести последовательность, необходимо вызвать метод start():
tonePlayer.start();
Чтобы удостовериться, что при закрытии мидлета воспроизведение остановится, необходимо закрыть проигрыватель. Для этого необходимо вызвать метод close():
tonePlayer.close();
Важно отметить, что большинство методов для работы с медиа-данными могут вызывать исключения, а следовательно, их стоит помещать в конструкцию try-catch. Ниже приведен пример того, как можно создать проигрыватель и воспроизвести последовательность тонов:
try {
Player tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
tonePlayer.realize();
ToneControl.toneControl = (ToneControl)toneControl.getControl("ToneControl");
toneControl.setSequence(marylambSequence);
tonePlayer.start();
}
catch (IOException ioe) {
}
catch (MediaException me) {
}
Хотя в MIDP 2.0 Media API, несомненно, больше возможностей работы с тонами, я думаю, что стоит пока остановиться и посмотреть, как это можно применить в реальном мидлете. Читайте дальше, и вы узнаете, как добавить космическую музыку в игру UFO.
Создание программы UFO 3Если вы вспомните, то в программе UFO, которую мы создавали в предыдущих главах, вы управляете летающим объектом, чтобы он не столкнулся с астероидами.
В этой программе много потенциальных возможностей для применения тонов и звуковых последовательностей. Отдельные звуки целесообразно использовать для сопровождения движения НЛО и столкновения с астероидами, в то время как тоновую последовательность можно использовать для воспроизведения музыки. Итак, мы выделили три типа звуков, которые будем внедрять в программу UFO 3:
► звук, сообщающий о нажатии клавиши;
► звук, сообщающий о столкновении НЛО с астероидом;
► тоновая последовательность, используемая в качестве музыки.
В следующем разделе будет подробно рассмотрен код, выполняющий это.
Как вы узнали ранее, чтобы воспроизвести тон, нужен совсем небольшой код. Пример UFO 3 использует такой код для воспроизведения звука при нажатии на одну из клавиш со стрелками. Наиболее подходящий тон для сопровождения движения – это G4, нота G той же октавы, что и C4. Ниже приведен код, определяющий переменную G4, а затем воспроизводящий ее:
byte G4 = (byte)(ToneControl.C4 + 7);
try {
Manager.playTone(G4, 100, 50);
}
catch (Exception e) {
}
Звук перемещения НЛО воспроизводится в течение 100 миллисекунд (1/10 секунды), громкость составляет 50 %. Тон, сообщающий о столкновении, воспроизводится аналогично:
try {
Manager.playTone(ToneControl.C4 – 12, 500, 100);
}
catch (Exception e) {
}
В случае взрыва воспроизводится звук C3, который расположен на одну октаву ниже, чем средний C (C4). Вместо того чтобы создавать переменную C3, достаточно верно указать смещение относительно ноты C4. Звук взрыва воспроизводится в течение 500 миллисекунд с громкостью 100 %. Это необходимо, потому что более низкий звук сложнее услышать.
Код, воспроизводящий отдельные тоны, находится в методе update() класса UFOCanvas мидлета UFO 3. Этот класс также содержит код, который отвечает за воспроизведение тоновой последовательности в мидлете. В листинге 8.2 приведен код нового и улучшенного метода update().
Листинг 8.2. Метод update() класса UFOCanvas, который воспроизводит тоны мидлета UFO 3
private void update() {
// случайное воспроизведение звуков
if (rand.nextInt() % 500 == 0)
playTune();
// обработка пользовательского ввода для управления НЛО
byte G4 = (byte)(ToneControl.C4 + 7); //Тон G4 определен относительно тона C(C4)
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
// воспроизвести звук, означающий перемещение
try {
Manager.playTone(G4, 100, 50); //Воспроизведение тона G4 на громкости 50% в течение 1/10 секунды в ответ на нажатие клавиши
}
catch (Exception e) {
}
ufoXSpeed–;
}
else if ((keyState & RIGHT_PRESSED) != 0) {
// воспроизвести звук, означающий перемещение
try {
Manager.playTone(G4, 100, 50);
}
catch (Exception e) {
}
ufoXSpeed++;
}
if ((keyState & UP_PRESSED) != 0) {
// воспроизвести звук, означающий перемещение
try {
Manager.playTone(G4, 100, 50);
}
catch (Exception e) {
}
ufoYSpeed–;
}
else if ((keyState & DOWN_PRESSED) != 0) {
// воспроизвести звук, означающий перемещение
try {
Manager.playTone(G4, 100, 50);
}
catch (Exception e) {
}
ufoYSpeed++;
}
ufoXSpeed = Math.min(Math.max(ufoXSpeed, -8), 8);
ufoYSpeed = Math.min(Math.max(ufoYSpeed, -8), 8);
// переместить спрайт НЛО
ufoSprite.move(ufoXSpeed, ufoYSpeed);
checkBounds(ufoSprite);
// обновить спрайт астероида
for (int i = 0; i < 3; i++) {
// переместить спрайт астероида
roidSprite[i].move(i + 1, 1 – i);
checkBounds(roidSprite[i]);
// увеличить номер спрайта астероида
if (i == 1)
roidSprite[i].prevFrame();
else
roidSprite[i].nextFrame();
// проверить столкновение между НЛО и астероидом
if (ufoSprite.collidesWith(roidSprite[i], true)) {
// воспроизвести звук столкновения
try {
Manager.playTone(ToneControl.C4 – 12, 500, 100); //Воспроизвести низкий звук в течение половины секунды на полной громкости при столкновении
}
catch (Exception e) {
}
// восстановить начальное положение НЛО и его скорость
ufoSprite.setPosition((getWidth() – ufoSprite.getWidth()) / 2,
(getHeight() – ufoSprite.getHeight()) / 2);
ufoXSpeed = ufoYSpeed = 0;
for (int j = 0; j < 3; j++)
roidSprite[j].setPosition(0, 0);
// нет необходимости обновлять спрайты астероидов
break;
}
}
}
Если вы внимательно изучите код обработки пользовательского ввода, находящийся в начале метода, то узнаете код, который воспроизводит звук как реакцию на перемещение объекта. Звук столкновения воспроизводится ближе к концу метода. Возможно, самый интересный код этого метода располагается в самом начале, когда воспроизводится тоновая последовательность через произвольные интервалы времени, для чего вызывается метод playTune(). Важно понять, как создается этот метод.
Метод initTune() отвечает за инициализацию тоновой последовательности в мидлете UFO 3 (листинг 8.3).
Листинг 8.3. Метод initTune() в классе UFOCanvas инициализирует тоновую последовательность
private void initTune() {
byte tempo = 30; // 120bpm //Установить темп и длину нот
byte d4 = 16; // 1/4 ноты
byte d2 = 32; // 1/2 ноты
byte C4 = ToneControl.C4; //Определить последовательность нот на основании С4, а также тишину
byte A6 = (byte)(C4 + 21);
byte B6 = (byte)(C4 + 23);
byte G5 = (byte)(C4 + 19);
byte G4 = (byte)(C4 + 7);
byte D5 = (byte)(C4 + 14);
byte rest = ToneControl.SILENCE;
byte[] encountersSequence = {
ToneControl.VERSION, 1,
ToneControl.TEMPO, tempo,
ToneControl.BLOCK_START, 0,
A6,d4, B6,d4, G5,d4, G4,d4, D5,d2, rest,d2, //Мелодия из фильма «Близкие контакты»
ToneControl.BLOCK_END, 0,
ToneControl.PLAY_BLOCK, 0,
ToneControl.PLAY_BLOCK, 0,
};
try {
// создать тоновый проигрыватель
tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
tonePlayer.realize();
// создать тоновый проигрыватель и установить тоновую последовательность
ToneControl toneControl = (ToneControl)tonePlayer.getControl("ToneControl");
toneControl.setSequence(encountersSequence);
}
catch (IOException ioe) {
}
catch (MediaException me) {
}
}
Этот метод начинается с объявления ряда важных переменных, которые будут использоваться для описания тоновой последовательности. Затем аккуратно задается байтовый массив тоновой последовательности. Целесообразно сказать, что эта последовательность – мелодия из фильма «Близкие контакты третьего рода» («Close Encounters of the Third Kind»), в котором инопланетяне для контакта с людьми использовали эту мелодию. Пять нот повторяются дважды в байтовом массиве encounterSequence. На рис. 8.3 показана тема из «контактов» в виде тоновой последовательности encounterSequence.
Рис. 8.3. Простая мелодия из кинофильма «Близкие контакты третьего рода» закодирована в виде тоновой последовательности
Когда тоновая последовательность задана, создается и реализуется тоновый проигрыватель, организуется доступ к его управлению и передается последовательность. При выходе из этого метода проигрыватель уже содержит нужную последовательность, готовую к воспроизведению.
Метод playTune() воспроизводит тоновую последовательность, а метод cleanupTune() закрывает проигрыватель. В листинге 8.4 показаны эти два метода.
Листинг 8.4. Методы playTune() и cleanupTune() класса UFOCanvas соответственно воспроизводят и очищают тоновую последовательность
private void playTune() {
try {
// воспроизвести тоновую последовательность
tonePlayer.start();
}
catch (MediaException me) {
}
}
private void cleanupTune() {
// закрыть тоновый проигрыватель
tonePlayer.close();
}
Как вы видите, метод playTune() воспроизводит тоновую последовательность, для чего вызывается метод start() тонового проигрывателя. А вызов метода проигрывателя close() – это все, что необходимо, чтобы закрыть проигрыватель и очистить тоновую последовательность.
Полный код мидлета UFO вы можете найти на прилагаемом CD. Я выборочно осветил важные фрагменты, поэтому вам не придется пролистывать страницы уже знакомого вам кода.
Тестирование мидлета UFO 3 включает в себя тестирование динамиков и запуск мидлета в эмуляторе J2ME. Я бы хотел показать вам кадр из игры, где воспроизводится музыкальная тема и проигрывается тон во время столкновения, но, к сожалению, технология печати не достигла пока таких высот. Поэтому вам придется запустить мидлет и самим послушать тоны.
Совет Разработчику
В реальной игре вы можете предусмотреть регулирование громкости, чтобы пользователю не пришлось изменять громкость телефона. В некоторых телефонах Java позволяет регулировать громкость вне зависимости от громкости звуков самого телефона, но такую возможность поддерживают не все модели. По себе знаю, что иногда не хочется слышать звуки игры, но хочется услышать телефонный звонок.
Тестируя UFO 3, обратите внимание на звук, когда мидлет воспроизводит несколько звуков одновременно. Если говорить о реальных играх, то это обычная ситуация, поэтому убедитесь, что тоны воспроизводятся корректно. Если у вас под рукой есть мобильный телефон, поддерживающий стандарт MIDP 2.0, то протестируйте мидлет UFO 3 на нем.
РезюмеВ этой главе вы познакомились со звуком в мобильных играх. Вы не только узнали, какое место занимают звуки в играх, но и познакомились с основами работы с тонами и тоновыми последовательностями, используя MIDP 2.0 Media API. Также вы узнали, как опросить телефон о его возможностях работы с аудио. Далее вы изучили код, который позволяет воспроизводить не только отдельные звуки, но и целые мелодии. И в завершение этой главы были добавлены тоны и мелодия в мидлет UFO. В следующей главе вы продолжите работу со звуком, научитесь использовать Wav-файлы, MIDI-музыку и MP3-аудио.
ЭкскурсияЕсли вы ни разу не видели фильм «Близкие контакты третьего рода», то обязательно возьмите его в прокате. Это великолепный фильм, он поможет понять многие аспекты игры UFO 3. Если вы уже видели фильм, я советую расширить созданную тоновую последовательность. Если вы вспомните, инопланетяне использовали ряд интересных звуковых последовательностей, кроме той, что мы уже использовали.
Глава 9
Воспроизведение цифрового звука и музыки
Архив Аркад
Еще одна игра 1981 года – это Qix, созданная компанией Taito. Она имеет уникальный дизайн. Но я думаю, если вы не играли в эту игру, то ее описание покажется вам похожим на описание геометрической композиции. Однако Qix очень забавная игра. Ваша цель – рисовать на экране прямоугольники, избегая столкновения со спарксами (Sparx), перемещающимися вдоль уже нарисованных линий, и квиксами (Qix), перемещающимися по экрану. Как я уже сказал, описание игры не столь привлекательно, однако если вам представится возможность поиграть в Qix, непременно сделайте это, вам понравится.
Несмотря на то что тоны поддерживаются всеми телефонами MIDP 2.0, их применение, несомненно, ограничено. В эру, когда игроки привыкли к высококачественному звуку и музыке, было бы очень хорошо использовать подобные звуки в играх. К счастью, MIDP 2.0 Media API поддерживает разнообразные типы аудио: Wav-файлы, MIDI-музыку и MP3-аудио. В этой главе вы научитесь использовать эти типы звуков в играх.
Прочитав эту главу, вы узнаете:
► об основах цифровых звуков, способах хранения;
► подробнее познакомитесь с интерфейсами Player MIDP 2.0 Media API;
► как воспроизводить цифровые звуки в играх;
► как воспроизводить MIDI и MP3 музыку в играх;
► как изменить код мидлета Henway, чтобы воспроизводить цифровые звуки и MIDI-музыку.
Основы цифровых звуковХотя вы можете использовать цифровые звуки в играх, не изучая принципов их работы, я не хочу, чтобы все было именно так. Важно, по крайней мере, понять основы цифровых звуков, и какое отношение они имеют к реальным природным звукам. В отличие от тоновых звуков в основе которых лежит звук определенной частоты, цифровые звуки копируют реальные звуки, преобразовывая звуковую волну в цифровой аналог.
Когда микрофон преобразовывает звуковую волну, то на выходе получается аналоговый сигнал (непрерывный). Поскольку компьютеры – это цифровые машины, то для работы со звуком такой сигнал необходимо преобразовать из непрерывного в цифровой (дискретный). Эту задачу выполняют аналогово-цифровые преобразователи (АЦП), процесс преобразования аналогового сигнала в цифровой называется дискретизацией или сэмплированием (sampling). Точность передачи аналогового сигнала при дискретизации определяется частотой дискретизации, а также объемом информации, хранящейся в каждом сэмпле.
Чтобы сэмплировать звук, вы должны сохранить амплитуду звуковой волны через равные интервалы времени. Чем меньше интервал времени между соседними сэмплами, тем больше цифровой сигнал соответствует аналоговому, а, следовательно, при воспроизведении он больше похож на реальный звук. Именно поэтому при преобразовании звука в цифровой вид важны частота дискретизации и объем информации, хранящийся в одном сэмпле. Частота измеряется в Герцах (Гц, Hz), она определяет число сэмплов в одной секунде. Например, музыка CD-качества сэмлируется на частоте 44000 Гц (44 кГц), соответственно при прослушивании компакт-диска вы на самом деле слышите 44 тысячи сэмплов в секунду.
Кроме частоты, на качество звука влияет число бит, используемых для сохранения амплитуды звука, а также его качество (стерео или моно). Имея это в виду, можно разбить звук категории в зависимости от его параметров:
► частота;
► количество бит в сэмпле;
► моно/стерео.
Частота сэмплирования, как правило, варьируется от 8 кГц до 44 кГц, верхняя граница соответствует качеству звука, записанного на CD. Обычно один сэмпл содержит 8 или 16 бит, для звука CD-качества число бит равно 16.
Затем сэмплированый звук делится на стерео и моно. Под монозвуком понимается, что используется лишь один звуковой канал, в то время как стереозвук имеет два канала. Как вы, вероятно, поняли, стереозвук содержит в два раза больший объем данных по сравнению с монозвуком. Не удивительно, что звук CD-качества всегда стерео. Следовательно, теперь, когда речь пойдет о звуке CD-качества, вы должны понимать, что его характеристики таковы: 44 кГц, 16-бит, стерео.
В копилку Игрока
DVD-аудио поднял планку качества цифрового звука, и популярность этого вида носителя неуклонно растет. По сравнению с CD-аудио новый носитель позволяет использовать частоты до 192 кГц, число бит для хранения информации увеличить до 24, а число каналов до 6. Однако для хранения DVD-аудио требуется значительный объем памяти, что делает этот тип звука неприменимым для мобильных игр.
Поскольку в мобильных телефонах ограничена память и скорость соединения, то вы должны минимизировать необходимые вашему мидлету ресурсы. Я говорю не только о зависимости размера звукового файла от его длины, но и о качестве звука. Например, звук CD-качества (44 кГц, 16 бит, стерео) – это слишком большая роскошь для большинства современных мобильных телефонов. Поэтому очень важно найти компромисс между качеством звука и требуемым объемом памяти.
Есть еще один вопрос, который необходимо решить, если вы используете звуки в играх. Это вопрос авторского права. Вы не можете использовать авторские звуки без письменного согласия владельца прав. Например, звуки, сэмлированные из видео– или аудиозаписей, не могут быть использованы без разрешения. Это все равно, что нельзя использовать нелицензионное программное обеспечение. Поэтому будьте осторожны, сэмплируя звуки из источников, охраняемых авторским правом.
В копилку Игрока
Некоторые общедоступные коллекции звуковых эффектов на самом деле охраняются авторским правом, и могут навлечь на вас неприятности. Большинство таких типов коллекций – это аудио компакт-диски, содержащие различные звуковые эффекты. Внимательно прочитайте надписи на CD и убедитесь, что вы можете законно использовать его содержимое.