Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 33 (всего у книги 35 страниц)
Я бы хотел научить вас создавать список рекордов (одну из особенностей классических аркад), в который можно вводить ваше имя или инициалы. К сожалению, эта задача достаточно сложна с точки зрения программирования. Если быть более точным, то необходимо отступить от темы повествования, не углубляясь в детали. Поэтому вместо списка рекордов, хранящего имена и счет лучших пяти игроков, вы создадите список рекордов, содержащий лишь лучшие 5 результатов. Хотя при этом имена рекордсменов будут неизвестны, тем не менее такой способ хорош для отражения лучших достижений.
В копилку Игрока
Поскольку мы имеем дело с мобильными телефонами – персональными устройствами, в списке рекордов в большинстве случаев будете присутствовать только вы. Поэтому ввод имени рекордсмена не столь необходим.
Поскольку нет необходимости сортировать имена, вам придется сортировать лишь счет игры. Если вы вспомните, то в игре Space Out счет– это четырехразрядное число (то есть меньше 10000), что означает, переменная типа int хорошо подходит для его хранения. Однако вы знаете, что данные в хранилище записей хранятся как массивы байтов. Следовательно, необходимо конвертировать данные в массив байтов и обратно.
Давайте рассмотрим конвертирование целых чисел в байтовый массив с точки зрения создания одной записи. Идея заключается в том, чтобы одно целое число преобразовать в массив типа byte. Ниже приведен код, выполняющий это:
byte[] recordData = Integer.toString(hiScore).getBytes();
В этом примере рекорд хранится в переменной hiScore, которая сначала преобразуется в строку, для чего вызывается метод Integer.toString(). Затем эта строка преобразуется в массив байтов методом getBytes(). Все, что необходимо, – это одна строка кода, и целое число преобразовано в массив байтов. На рис. 19.2 представлена графическая иллюстрация этого процесса.
Рис. 19.2. Чтобы преобразовать целое число в массив байтов, сначала необходимо конвертировать его в строку
Преобразование данных о рекордах в нужный формат – это важная задача, которая решается обратным конвертированием. Используя тип string как промежуточный тип, массив байтов преобразуется в целое число. Приведенный ниже код выполняет это:
hiScore = (Integer.parseInt(new String(recordData, 0, len)));
Конструктор String(), используемый в этом коде, принимает массив байтов, смещение и число конвертируемых байтов. Переменная len, которая хранит число конвертируемых данных, содержит число, возвращенное методом getRecord(), считывающим запись. Затем строка передается в статический метод Integer.parseInt(), преобразующий строку в целое число. Рисунок 19.3 иллюстрирует процесс обратного конвертирования (массива байтов в целое число).
Рис. 19.3. Чтение записи рекорда их хранилища записей требует обратного конвертирования
Когда вы не работаете с хранилищем записей, рекорды – это обычные целые числа. Иначе говоря, все эти сложности необходимы лишь для преобразования данных при работе с хранилищем записей. Еще один случай, в котором необходимо конвертировать числа в строку, – вывод рекордов на экран, для чего необходимо использовать метод drawString().
Помните, что предыдущая строка кода считывает лишь одну запись из хранилища. В реальных мобильных играх список рекордов состоит из нескольких записей. Поэтому чтение и запись данных в хранилище должны выполняться в цикле. В этом случае вы сможете с легкостью выполнить все необходимые задачи, написав минимум кода.
Создание игры Space Out 2Игра Space Out, созданная в предыдущей главе, идеально подходит для того, чтобы добавить в нее список рекордов. Оставшаяся часть главы будет посвящена добавлению списка рекордов в игру, и не только. Список рекордов будет выводиться на экран вместе с названием игры – растровым изображением.
Заставка видео появляется при запуске игры, а также между уровнями. Заставки могут быть очень занятными или простыми, они могут нести такую информацию, как название игры, иллюстрации, информация об авторских правах, инструкции по игре, и рекорды. В игре Space Out 2 вы создадите заставку, состоящую из названия игры и списка рекордов. На рис. 19.4 показано растровое изображение Space Out 2.
Рис. 19.4. Заставка игры Space Out 2 состоит из растрового изображения названия игры
Совет Разработчику
В играх на заставку целесообразно выносить информацию об авторских правах, чтобы четко установить свои права на игру.
Такая простая заставка игры объясняется тем, что игра работает в условиях ограниченных ресурсов мобильного устройства. Конечно, вы можете вынести больше информации на экран, однако иногда лучше меньше, чем больше. Кроме того, необходимо оставить место для вывода списка рекордов.
Игра Space Out 2 содержит список из 5 рекордов, которые помещаются в хранилище записей. Хотя хранилище используется для постоянного хранения информации о рекордах, в игре они являются целыми числами. Ниже приведено объявление переменных игры Space Out 2, хранящих игровую заставку и массив рекордов:
private Image splash;
private int[] hiScores = new int[5];
Совет Разработчику
Вам ничего не мешает при желании расширить список рекордов. Просто помните, чтобы отобразить больший список рекордов, требуется больше места на экране.
Добавление списка рекордов в игру Space Out прежде всего ведет к изменениям метода start(), который, как вы знаете, отвечает за инициализацию игры и ее запуск. Этот метод как нельзя лучше подходит для чтения списка рекордов из хранилища записей. В методе start() чтение из хранилища записей выполняется одной строкой:
readHiScores();
Метод readHiScores() отвечает за открытие хранилища записей и последовательного чтения данных в целочисленный массив hiScores. В листинге 19.1 приведен код метода readHiScores():
Листинг 19.1. Метод readHiScores() считывает список рекордов из хранилища записей
private void readHiScores()
{
// открыть хранилище записей
RecordStore rs = null;
try {
rs = RecordStore.openRecordStore("HiScores", false); //Хранилище записей называется «HiScores»
}
catch (Exception e) {
}
if (rs != null) {
// считать список рекордов
try {
int len;
byte[] recordData = new byte[8];
for (int i = 1; i <= rs.getNumRecords(); i++) { //Пройти по всем записям хранилища
// при необходимости изменить размер выделенной памяти
if (rs.getRecordSize(i) > recordData.length)
recordData = new byte[rs.getRecordSize(i)];
// считать рекорд, преобразовать в число и записать в массив
len = rs.getRecord(i, recordData, 0);
hiScores[i – 1] = (Integer.parseInt(new String(recordData, 0, len))); //Преобразовать массив байтов в целое число и сохранить в массив рекордов
}
}
catch (Exception e) {
System.err.println("Failed reading hi scores!");
}
// закрыть хранилище данных
try {
rs.closeRecordStore();
}
catch (Exception e) {
System.err.println("Failed closing hi score record store!");
}
}
else {
// The record store doesn't exist, so initialize the scores to 0
for (int i = 0; i < 5; i++)
hiScores[i] = 0;
}
}
Метод readHiScores() начинается попыткой открытия хранилища записей, которое называется «HiScores». Второй параметр метода (false) означает, что новое хранилище не нужно создавать, если хранилище с указанным именем не найдено. Если хранилище открыто успешно, то метод readHiScores() продолжает работу с хранилищем и считывает последовательно данные в массив целых чисел. После того как список рекордов считан, хранилище записей закрывается. Обратите внимание, что если хранилища с указанным именем не существует, то массив hiScores инициализируется 0. Этот вариант работает только при первом запуске игры.
Другое, но очень важное изменение метода start() игры Space Out 2 касается работы метода в случае ранее наступившего окончания игры. В исходной версии игры Space Out игра начинается сразу при запуске мидлета.
В игре Space Out 2 заставка и список рекордов отображаются при первом запуске игры. Иначе говоря, игра Space Out 2 начинается в режиме «окончания игры». Поэтому в методе start() больше не вызывается метод newGame(), а переменной gameOver присваивается значение true:
gameOver = true;
Подобно тому, как список рекордов считывается в методе start(), он записывается в методе stop():
writeHiScores();
Метод writeHiScores() записывает целочисленный массив в хранилище записей. В листинге 19.2 приведен код этого метода:
Листинг 19.2. Метод writeHiScores() записывает целочисленный массив HiScores в хранилище данных
private void writeHiScores()
{
// удалить предыдущее хранилище записей
try {
RecordStore.deleteRecordStore("HiScores"); //Сначала удаляется хранилище записей
}
catch (Exception e) {
}
// создать новое хранилище записей
RecordStore rs = null;
try {
rs = RecordStore.openRecordStore("HiScores", true); //Значение true говорит о том, что если хранилище записей с указанным именем не будет найдено, то будет создано новое хранилище
}
catch (Exception e) {
System.err.println("Failed creating hi score record store!");
}
// записать рекорды
for (int i = 0; i < 5; i++) {
// подготовить данные для записи
byte[] recordData = Integer.toString(hiScores[i]).getBytes(); //Преобразовать целое число в массив байтов, чтобы записать его в хранилище
try {
// записать данные в хранилище
rs.addRecord(recordData, 0, recordData.length);
}
catch (Exception e) {
System.err.println("Failed writing hi scores!");
}
}
// закрыть хранилище
try {
rs.closeRecordStore();
}
catch (Exception e) {
System.err.println("Failed closing hi score record store!");
}
}
Метод writeHiScores() использует уникальную методику записи рекордов. Вместо того чтобы заменить отдельную запись в хранилище, заменяется все хранилище целиком. Хотя такой подход может показаться грубым, он значительно упрощает код игры. Это и объясняет, почему в начале метода writeHiScores() удаляется хранилище записей.
После того как хранилище записей удалено, метод writeHiScores() создает новое хранилище, для чего вторым параметром при вызове метода openRecordStore() передается true. Затем выполняется цикл по всем элементам массива hiScores, каждый из элементов записывается в хранилище. Когда все рекорды записаны, хранилище закрывается, для чего вызывается метод closeRecordStore().
Вы создали код, считывающий список рекордов в начале игры, и записывающий список в хранилище по окончании игры. Но я не упомянул о том, как обновляется список рекордов. При окончании игры метод update() вызывает метод updateHiScores(), обновляющий список рекордов:
if (carsLeft– == 0) {
// остановить музыку
try {
musicPlayer.stop();
}
catch (MediaException me) {
}
// воспроизвести звук окончания игры
try {
gameoverPlayer.start();
}
catch (MediaException me) {
}
// спрятать спрайт автомобиля
playerSprite.setVisible(false);
// обновить список рекордов
updateHiScores(); //Вызов метода updateHiScores() – это все, что необходимо для обновления списка рекордов
gameOver = true;
return;
}
Метод updateHiScores() – это вспомогательный метод, который проверяет, попадает ли результат игрока в список рекордов. Если да, то он добавляет этот результат, удаляя наименьший рекорд. В листинге 19.3 приведен код этого метода.
Листинг 19.3. Метод updateHiScores() обновляет список рекордов
private void updateHiScores() {
// проверить, попадает ли результат игрока в список рекордов
int i;
for (i = 0; i < 5; i++)
if (score > hiScores[i]) //Если счет больше, чем текущий рекорд, то поместить результат игры в список рекордов
break;
// поместить результат в список рекордов.
if (i < 5) {
for (int j = 4; j > i; j–) { //Цикл смещает меньшие результаты в конец списка рекордов
hiScores[j] = hiScores[j – 1];
}
hiScores[i] = score;
}
}
Метод updateHiScores() сначала проверяет, попадает ли результат, набранный игроком, в список рекордов. Если да, то он добавляется в список рекордов, при этом наименьший результат удаляется из списка. В списке рекордов содержится не более 5 записей, поэтому прежние рекорды уступают место новым. Помните, что список рекордов временно хранится в памяти телефона, пока игра существует, данные не будут помещены в хранилище, если не будет вызван метод stop().
Последнее необходимое изменение кода игры Space Out 2 касается метода draw(), который будет выводить список рекордов на игровой заставке. В листинге 19.4 приведен код метода draw().
Листинг 19.4. Метод draw() выводит заставку и список рекордов по окончании игры
private void draw(Graphics g) {
// вывести фоновое изображение звездного неба
g.drawImage(background, 0, 0, Graphics.TOP | Graphics.LEFT);
// вывести слои
layers.paint(g, 0, 0);
if (gameOver) {
// вывести изображение заставки и список рекордов
g.drawImage(splash, 90, 10, Graphics.TOP | Graphics.HCENTER);
g.setColor(255, 255, 255); // white
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,
Font.SIZE_LARGE));
for (int i = 0; i < 5; i++)
g.drawString(Integer.toString(hiScores[i]), 90, 90 + (i * 15),
Graphics.TOP | Graphics.HCENTER);
}
else {
// вывести оставшееся число автомобилей и счет
for (int i = 0; i < carsLeft; i++)
g.drawImage(smallCar, 2 + (i * 20), 2, Graphics.TOP | Graphics.LEFT);
g.setColor(255, 255, 255); // white
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,
Font.SIZE_MEDIUM));
g.drawString(Integer.toString(score), 175, 2, Graphics.TOP |
Graphics.RIGHT);
}
// вывести графику на экран
flushGraphics();
}
Метод draw() игры Space Out 2 устроен несколько иначе, чем его предыдущая версия. Теперь он содержит условный оператор if, проверяющий окончание игры. Если игра окончена, то метод draw() выводит на экран заставку со списком рекордов. Если игра не окончена, то на экран выводятся оставшееся число автомобилей и счет в игре. Слои выводятся вне зависимости от статуса игры.
Аналогично предшественнику, игру Space Out 2 достаточно просто тестировать. На самом деле это даже весело, потому что вам придется поиграть несколько раз, чтобы сформировать список рекордов. На рис. 19.5 показана заставка игры, на которой выводится список рекордов. Если игра запущена впервые, то список рекордов пуст.
Рис. 19.5. При первом запуске игры на экране появляется заставка, список рекордов состоит из одних нулей
Помните, что игра пытается считать список рекордов из хранилища записей, однако если хранилища не существует, то все элементы списка рекордов равны 0. Когда вы несколько раз поиграете в Space Out 2, в список рекордов будут занесены новые результаты. Если вы выйдете из игры, то список рекордов будет сохранен в хранилище записей. Когда игра запускается снова, рекорды считываются из хранилища. На рис. 19.6 показан список рекордов, загруженный из памяти.
Рис. 19.6. Список рекордов считывается из памяти телефона
Список рекордов очень полезное дополнение игры Space Out 2, поскольку он отслеживает ваши лучшие результаты.
РезюмеВ копилку Игрока
Пожалуйста, не судите строго о моих способностях как игрока по результатам, приведенным на рис. 19.6. Хотя вы можете превзойти мои результаты, тестируя игру, я не претендую на звание мастера игры Space Out. Немного практики, и все получится!
Хотя списки рекордов не так популярны на сегодняшний день, как во времена широкого распространения аркад, вы не можете целиком сбрасывать их со счетов. По сей день хорошо отслеживать ваши игровые достижения и устанавливать новые горизонты. Списки рекордов – хороший способ запоминать наилучшие игры, а также могут послужить стимулом для других игроков. Конечно, списки рекордов не столь необходимы во всех мобильных играх, но вы должны добавлять их, если это целесообразно. Игра Space Out – хороший пример такой игры.
Эта глава завершает книгу, я надеюсь, она послужила вам началом дороги в мир разработки и программирования мобильных игр. Вы, вероятно, готовы к тому, чтобы использовать полученные знания для создания собственных игр и проектов. Я желаю вам успехов в работе над собственными играми. Вы можете зайти на мой сайт и поделиться идеями создания игр на форуме, который посвящен этой книге(http://www.michaelmorrison.com/).
В заключениеПодобно Джорджу Кастанца (George Cantanza) из классического эпизода «Сейнфелда» (Seinfeld), вы должны использовать свои знания в области игр и оставить свой след в списке рекордов. Выберите любую игру, наберите большое число очков и внесите себя в игровую историю. Вы сможете продемонстрировать свои достижения не только родственникам и друзьям. Возможно это подтолкнет создать список рекордов, куда можно было бы вводить имена и инициалы.
Приложения
Приложение А
Java Game API
Java – это не просто язык программирования; это библиотека классов и интерфейсов, которая предлагает разработчикам широкий диапазон функций. Даже язык MIDP API, являющийся разделом Java, который был специально создан для программирования на мобильных телефонах, содержит весьма интересные функции. В MIDP API имеется пакет классов, предназначенных исключительно для мобильных игр. Данный пакет называется javax.microedition.lcdui.game. Он был добавлен в версии 2.0 MIDP API в ответ на многочисленные запросы разработчиков мобильных игр.
Классы в пакете javax.microedition.lcdui.game часто называют «API для мобильных игр»; эти классы очень важны, потому что они поддерживают функции, которые разработчикам MIDP 1.0 приходилось создавать самостоятельно. Другими словами, вам не придется изобретать велосипед, чтобы создавать новые игры в MIDP 2.0 API. Вероятно, самой важной функцией в API является встроенная поддержка графики с двойной буферизацией, которая максимально упрощает разработку игр с плавной графической анимацией. Кроме того, API поддерживает такие функции, как анимация спрайтов, вложенные слои, поиск ошибок и так далее.
API для мобильных игр в MIDP 2.0 включает пять классов:
► GameCanvas;
► Layer;
► LayerManager;
► Sprite;
► TiledLayer.
Остальные разделы данного приложения представляют собой краткий справочник по API для мобильных игр, который содержит описания классов MIDP 2.0, поддерживающих программирование для мобильных игр.
Класс GameCanvasКласс GameCanvas происходит из стандартного класса Canvas; он предлагает специальную схему, которая поддерживает графику с двойной буферизацией. Вы можете воспринимать класс GameCanvas в качестве функции, обеспечивающей отображение интерфейса мобильных игр на экране телефона. Конечно, это может показаться вам странным, но класс GameCanvas отвечает за поддержку клавиатуры в играх. Для обработки команд с клавиатуры могут применяться и другие классы J2ME, однако поддержка клавиатуры в классе GameCanvas намного более эффективна, поэтому она лучше отвечает высоким требованиям, предъявляемым к мобильным играм.
В классе GameCanvas заданы следующие константы, которые используются для идентификации клавиш на мобильном телефоне:
► LEFT_PRESSED – клавиша ←;
► RIGHT_PRESSED – клавиша →;
► UP_PRESSED – клавиша ↑;
► DOWN_PRESSED – клавиша ↓;
► FIRE_PRESSED – клавиша Primary Fire;
► GAME_A_PRESSED – клавиша Game A (опционально);
► GAME_B_PRESSED – клавиша Game B (опционально);
► GAME_C_PRESSED – клавиша Game C (опционально);
► GAME_D_PRESSED – клавиша Game D (опционально).
Эти константы используются вместе с методикой getKeyStates(), которая описана в разделе «Методы» описания класса GameCanvas. Все константы клавиш являются масками бита, а это значит, что вы можете их использовать для того, чтобы определить, была нажата определенная клавиша или нет.
Как видно из списка, только клавиши LEFT_PRESSED, RIGHT_PRESSED, UP_PRESSED, DOWN_PRESSED и FIRE_PRESSED будут гарантированно поддерживаться на всех мобильных телефонах; остальные клавиши являются опциональными.
Класс GameCanvas имеет только один конструктор, принимающий один параметр, который определяет, можно ли использовать механизм управления, заданный в J2ME, по умолчанию: GameCanvas(boolean suppressKeyEvents).
Класс GameCanvas предлагает свою методику обработки нажатий клавиш, getKeyStates(), следовательно, большинство игр не используют стандартную систему реагирования на нажатия клавиш в J2ME. Поэтому многие игры напрямую обращаются к конструктору GameCanvas, позволяющему отключить методику восприятия нажатий клавиш по умолчанию. Методика getKeyStates() более эффективна, так как она не конфликтует с обычной системой восприятия клавиш. Если ваша игра использует смешанный подход к обработке нажатий клавиш, вам необходимо передать конструктору команду «false», чтобы активировать методику обработки нажатий клавиш по умолчанию.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.