Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 32 (всего у книги 35 страниц)
Несколько раз я уже упоминал о методе newGame() при обсуждении кода игры Space Out. В листинге 18.4 приведен код этого метода:
Листинг 18.4. Метод newGame() класса SOCanvas инициализирует игровые переменные и запускает музыку
private void newGame() {
// Initialize the game variables
gameOver = false;
score = 0;
carsLeft = 3;
// Initialize the player car sprite
playerSprite.setPosition(0, getHeight() – playerSprite.getHeight() – 10); //Поместить спрайт автомобиля в центре пустыни (по высоте)
playerSprite.setXSpeed(4);
playerSprite.setYSpeed(0);
playerSprite.setVisible(true);
// Initialize the alien and explosion sprites
for (int i = 0; i < 3; i++) { //При запуске игры пришельцы не видны
blobboSprite[i].setVisible(false);
jellySprite[i].setVisible(false);
timmySprite[i].setVisible(false);
explosionSprite[i].setVisible(false);
}
// Initialize the missile sprites
for (int i = 0; i < 10; i++) {
missileSprite[i].setVisible(false);
}
// Start the music (at the beginning)
try {
musicPlayer.setMediaTime(0);
musicPlayer.start();
}
catch (MediaException me) {
}
}
Метод newStart() начинается с инициализации трех основных переменных: gameOver, score и carsLeft. Спрайт игрока устанавливается в исходное положение и становится видимым – это необходимо сделать, поскольку спрайт скрывается по окончании игры. Все пришельцы, взрывы и ракеты в начале игры скрыты. Метод newGame() завершается запуском звукового проигрывателя, для чего вызываются методы setMediaTime() и start().
Оставшаяся часть кода добавляет пришельцев, ракеты и взрывы. Этот код разделен на три метода, первый из которых – это addAlien(). В листинге 18.5 приведен код метода addAlien(), который отвечает за добавление пришельцев в игру.
Листинг 18.5. Метод addAlien() класса SOCanvas добавляет пришельца в игру
private void addAlien() {
switch (Math.abs(rand.nextInt() % 3)) {
// добавить Блоббо
case 0:
for (int i = 0; i < 3; i++) //Найти спрайт пришельца Блоббо, который еще не виден, изменить его положение и сделать видимым
if (!blobboSprite[i].isVisible()) {
placeSprite(blobboSprite[i]);
blobboSprite[i].setVisible(true);
break;
}
break;
// добавить Джелли
case 1:
for (int i = 0; i < 3; i++) //Если три спрайта пришельца Джелли уже видны, новый спрайт не будет добавлен
if (!jellySprite[i].isVisible()) {
placeSprite(jellySprite[i]);
jellySprite[i].setVisible(true);
break;
}
break;
// Добавить Тимми
case 2:
for (int i = 0; i < 3; i++)
if (!timmySprite[i].isVisible()) {
placeSprite(timmySprite[i]);
timmySprite[i].setVisible(true);
break;
}
break;
}
}
Совет Разработчику
Метод placeSprite() вызывается addAlien(), его задача – вычислить случайное положение на игровом экране и поместить в него спрайт. Это вычисление помогает убедиться, что спрайт не будет помещен слишком низко, близко к спрайту автомобиля. Спрайт также размещается подальше от границ экрана, чтобы он сразу не столкнулся с одной из них. Код метода placeSprite() вы можете найти на прилагаемом компакт-диске в коде игры Space Out.
Этот метод случайным образом выбирает тип пришельца, а затем добавляет его спрайт в игру, для чего выполняются следующие шаги:
1. найти подходящий спрайт пришельца, который еще невидим;
2. спрайт помещается в случайное место;
3. показать спрайт.
Подобно тому, как добавляются спрайты пришельцев, метод addMissle() добавляет спрайты ракет. Однако этот метод отличается от addAlien() тем, что в него передается единственный параметр – спрайт, запускающий ракету, чтобы определить тип ракеты. В коде 18.6 приведен код метода addMIssle().
Листинг 18.6. Метод addMissle() класса SOCanvas добавляет ракету так, что создается впечатление, что она запущена спрайтом
private void addMissile(MovingSprite sprite) {
for (int i = 0; i < 10; i++)
if (!missileSprite[i].isVisible()) {
switch (Math.abs(sprite.getXSpeed())) { //Поскольку спрайты игрока и пришельцев имеют различные скорости по оси Х, вы можете использовать значение этой скорости для определения типа запускаемой ракеты
// запустить ракету Блоббо
case 3:
missileSprite[i].setFrame(1);
missileSprite[i].setPosition(sprite.getX() + 5, sprite.getY() + 21);
missileSprite[i].setXSpeed(sprite.getXSpeed() / 2);
missileSprite[i].setYSpeed(5);
break;
// запустить ракету Джелли
case 1:
missileSprite[i].setFrame(2);
missileSprite[i].setPosition(sprite.getX() + 5, sprite.getY() + 21);
missileSprite[i].setXSpeed(0);
missileSprite[i].setYSpeed(4);
break;
// запустить ракету Тимми
case 5:
missileSprite[i].setFrame(3); //Каждый фрейм анимации – это определенный тип ракеты
missileSprite[i].setPosition(sprite.getX() + 5, sprite.getY() + 11);
missileSprite[i].setXSpeed(sprite.getXSpeed() / 2);
missileSprite[i].setYSpeed(3);
break;
// запустить ракету игрока
case 2:
case 4:
missileSprite[i].setFrame(0);
missileSprite[i].setPosition(sprite.getX() + 6, sprite.getY() – 11);
missileSprite[i].setXSpeed(0);
missileSprite[i].setYSpeed(-4);
break;
}
// показать ракету
missileSprite[i].setVisible(true);
break;
}
}
Метод addMissle()принимает спрайт игрока в качестве единственного параметра, создается эффект запуска ракеты указанным спрайтом.
Основная хитрость этого метода – определение типа запускаемой ракеты. Необходим простой и надежный метод определения типа спрайта, запускающего ракету. Хитрость заключается в том, чтобы проверять скорость Х спрайта, поскольку каждый спрайт имеет уникальное значение этой составляющей скорости. Следовательно, оператор условного перехода switch использует именно эту величину для определения типа добавляемой ракеты.
Процесс добавления ракеты содержит следующие этапы:
1. найти подходящий спрайт, который еще невидим;
2. выбрать нужный фрейм спрайтового изображения;
3. поместить ракету в точку, находящуюся рядом с запускающим спрайтом;
4. установить скорость ракеты в зависимости от ее типа;
5. показать ракету.
И наконец, мы подходим к последнему методу игры Space Out, очень похожему на рассмотренные ранее методы addAlien() и addMissle(). В листинге 18.7 приведен код метода addExplosion().
Листинг 18.7. Метод addExplosion() класса SOCanvas добавляет взрыв при разрушении спрайта
private void addExplosion(MovingSprite sprite) {
for (int i = 0; i < 3; i++)
if (!explosionSprite[i].isVisible()) {
// Add an explosion where the moving sprite is located
explosionSprite[i].setFrame(0); //Проверка, что анимация взрыва начинается с первого фрейма
explosionSprite[i].setPosition(sprite.getX(), sprite.getY());
explosionSprite[i].setVisible(true);
break;
}
}
Этот метод добавляет спрайт взрыва на место указанного спрайта игрока или пришельца. Ниже перечислены шаги, выполняемые при добавлении спрайта взрыва:
1. найти подходящий спрайт взрыва, который еще не задействован;
2. установить номер первого фрейма анимации – 0;
3. разместить спрайт взрыва в центре уничтоженного спрайта;
4. показать взрыв.
Метод addExplosion() завершает код игры Space Out. Я представляю, что к разработке кода были приложены титанические усилия, но следующий раздел вознаградит ваши старания!
Тестирование игрыЯ уже много раз говорил, что тестирование – это один из самых веселых этапов тестирования игры, а теперь вы подошли к тестированию совершенно новой игры. Подобно игре High Seas, игра Space Out требует значительного времени на тестирование из-за большого числа взаимодействий игровых спрайтов. Самое хорошее, что для тестирования надо просто поиграть в Space Out. На рис. 18.9 показано начало игры, пришелец запускает ракету, автомобиль отвечает огнем.
Рис. 18.9. Игра Space Out начинается с того, что пришелец атакует игрока ракетой
Автомобиль можно перемещать, нажимая клавиши Влево или Вправо, чтобы запустить ракету – необходимо нажать клавишу Огонь (клавиша ввода на клавиатуре, если вы используете эмулятор). Если вы попадете в пришельца, то он взорвется (рис. 18.10).
Рис. 18.10. Когда вы попадаете в пришельца, появляется взрыв
В итоге, вы окажетесь на опасной территории под атакой пришельцев, они попадают в автомобиль, на месте которого появляется взрыв (рис. 18.11).
Рис. 18.11. Когда пришельцы подбивают машину, на экране появляется взрыв
В вашем распоряжении есть только 4 автомобиля. Число оставшихся машин выводится в левом верхнем углу экрана, а число набранных очков – в верхнем правом. Когда вы теряете все автомобили, игра завершается (рис. 18.12).
Рис. 18.12. Когда вы потеряете все свои машины, игра закончится и на дисплее будет отображено game over (игра закончена)
Чтобы начать новую игру, просто нажмите кнопку Огонь. Я надеюсь, что вам понравится игра Space Out, вы будете довольны результатом проделанной работы.
РезюмеВне зависимости от того, являетесь ли вы поклонником космических шутеров, я надеюсь, что вы понимаете значимость разработанной вами в этой главе игры Space Out, поскольку это наиболее полная игра, разработанная в книге. И это не только потому, что эта игра – хороший способ воплотить ваши идеи в реальность, но и потому, что эту игру можно расширить. Прежде чем вы начнете модифицировать игру, у меня есть пример модификации для вас.
В следующей главе вы создадите список рекордов для игры. Несмотря на то что в мобильных телефонах нет жестких дисков (пока), в J2ME есть средство хранения данных от одного запуска приложения до другого.
В заключениеИгра Space Out – это полноценная игра, поэтому я не хочу уходить далеко от основной темы. Поэтому давайте сфокусируемся на возможностях улучшения созданной игры. Прежде всего, плохих парней в игре не может быть много, поэтому одно из улучшений – это добавить новых пришельцев. Например, вы можете добавить пришельца, который будет перемещаться по земле и пытаться съесть автомобиль игрока. Поскольку автомобиль не может стрелять в сторону, то игрок должен убегать от пришельца, пока пришелец не исчезнет. Другая возможность, которую хорошо бы предусмотреть в игре, – это бонусы, объекты, которые случайным образом появляются на экране. Лучший способ – это бросать бонусы на землю с неба. Эти бонусы могут давать игроку временный щит, выстрел несколькими ракетами. Ниже перечислены основные шаги, которые необходимо выполнить:
1. создайте изображения новых пришельцев;
2. измените метод addAlien(), чтобы случайным образом добавлять спрайты новых пришельцев на экран. Убедитесь, что новые типы спрайтов имеют уникальные значения скорости. Например, для пришельца, перемещающегося по поверхности земли, скорость по оси Y должна быть равна 0;
3. измените метод update() так, чтобы он детектировал столкновения между ракетой игрока и спрайтом нового пришельца, после чего скрывал уничтоженный спрайт;
4. создайте новый метод addPowerUp(), аналогичный методу addAlien(), за исключением того, что он должен добавлять бонусы;
5. создайте булевскую переменную, которая будет отслеживать, что бонусы активны (например, временный щит), а затем измените метод update() в соответствии с привнесенными новшествами;
6. измените метод update(), чтобы детектировать столкновение между спрайтом игрока (автомобилем) и спрайтом бонуса и обрабатывать это событие.
Несмотря на то что я отметил, что здесь я немного отступлю от темы всей главы, здесь вы можете в полной мере проявить все полученные знания. Идея состоит в том, чтобы вы начали понимать все аспекты кода. Вы, вероятно, найдете, что по сравнению с созданием новой игры дополнение существующей игры – это намного меньший труд, который вознаграждается очень быстро.
Глава 19
Создание списка рекордов
Архив Аркад
Созданная в 1982 году компанией Seg игра Zaxxon была одной из самых первых видеоигр, использующих преимущества изомерии. Сегодня сложно представить, что графика игры Zaxxon была первоклассной для того времени. Но дело не только в этом. В игре вы могли управлять своим шатлом в трехмерном пространстве. Альтиметр, располагавшийся в левом углу экрана, играл очень важную роль в игровой стратегии, поскольку было необходимо постоянно подстраивать высоту для стрельбы по различным целям. Zaxxon – это одна из самых сложных игр, созданных в 80-х годах XX века, и она по праву считается классикой.
В период расцвета аркад 80-х, вы, вероятно, не задумывались о том, как попасть в топ-лист рекордов. Список рекордов в аркадах – это признание тех, у кого есть время, умение и четвертаки, чтобы быть лучшим из лучших. Если вы думаете, что я несколько драматизирую, то вспомните фрагмент фильма «Сейнфилд» (Seinfield), в котором Джордж Кастанца (George Castanza) попытался перетащить аркаду Frogger через улицу с оживленным движением, чтобы подсоединить ее к аккумулятору и сохранить свой рекорд. Даже если вы не такой большой эгоист, тем не менее лестно, что вы находитесь впереди других игроков. Конечно, менее сильные чувства вы испытаете, если будете знать, что список рекордов ограничен вашим телефоном, но идея остается такой же. В этой главе будет показано, как разработать список рекордов, который будет храниться в постоянной памяти мобильного телефона.
В этой главе вы узнаете:
► почему так важно хранить список рекордов;
► как представить список рекордов в игре;
► как сохранить и получить данные о рекордах с помощью системы управления записями J2ME (J2ME Record Management System, RMS);
► как добавить список рекордов в игру Space Out.
Важность сохранения достиженийРаньше лучшие игроки были известны лишь своими инициалами, которые высвечивались в списке рекордов аркад. Список рекордов в классической аркаде был очень важен для многих ранних игр, поскольку это был единственный способ продемонстрировать достижения игры.
Грустно, что списки рекордов теперь не так популярны, как когда-то, но мы не можем посетовать на достижения технологии. С другой стороны, это вовсе не означает, что списки рекордов полностью остались в прошлом. Например, в большинстве популярных игр, как Tony Hawk Pro Skater или Underground, до сих пор используются списки рекордов, чтобы почтить наиболее сильных игроков. Изменилось то, что применение списка рекордов в аркадах не только изменило его сущность, теперь он в меньшей степени используется для слежения за набранным числом очков. Тем не менее мне нравится идея списка рекордов, даже если в нем лишь друзья. Или просто забавно усовершенствовать свое мастерство в той или иной игре.
В этой главе рассматривается, как добавить список рекордов в игру Space Out, разработанную в предыдущей главе. Список рекордов представляет для вас как программиста мобильных игр сложность, поскольку вы должны сохранять список рекордов, чтобы он оставался в памяти и после закрытия приложения. Но подождите! Ведь в мобильных телефонах нет жестких дисков! Как же можно сохранить данные от одной игры к другой? Ответ лежит в Java Record Management System (Система управления записями в Java) или RMS, которая позволяет постоянно хранить данные в памяти телефона.
Перед тем как вы проникнете в сущность RMS, давайте рассмотрим, как смоделировать данные о рекордах. Иначе говоря, сперва вы должны установить, что и как вы будете хранить. Пока необходимо запомнить, что RMS позволяет хранить данные в специальном контейнере – хранилище записей (record store).
Знакомство с Java RMSКак вы знаете, дисковые накопители не входят в стандартную комплектацию мобильных телефонов, по крайней мере, пока не входят. Поэтому необходимо найти другие способы хранения информации. К счастью, в мобильных телефонах есть область памяти, которая используется для постоянного хранения данных, поэтому вы можете использовать ее в своих целях. В отличие от жестких дисков, которые работают на основе файлов, фундаментальное понятие хранилища в J2ME – это хранилище записей.
В копилку Игрока
То, как телефон хранит данные, зависит от конкретной модели. В современных мобильных телефонах обычно используется память устройства, но в будущем телефоны могут иметь и микро жесткие диски или какие-либо другие средства хранения информации. Хорошо, что, с точки зрения программирования, способ хранения данных не важен.
Хранилище записей – это упрощенная база данных. Запись – это единица информации, имеющая уникальный числовой идентификатор (ID). Хранилище записей можно представить как таблицу, состоящую из двух колонок (рис. 19.1).
Рис. 19.1. Хранилище записей состоит из отдельных записей, имеющих уникальный ID
Каждое хранилище записей в RMS ассоциировано с пакетом мидлета и имеет текстовое имя, идентифицирующее ее. Так, например, хранилище списка рекордов для игры Space Out может называться HiScores, доступ к нему может быть получен только через приложение Space Out. Если вы распространяете другие игры вместе со Space Out в одном пакете, то остальные игры также будут иметь доступ к этому хранилищу.
В копилку Игрока
Пакет мидлетов определяется JAR-файлом. Чтобы создать пакет мидлетов, просто упакуйте несколько мидлетов в один JAR-файл и создайте необходимый дескриптор (JAD) для каждого из них. Все примеры игр и программы, приведенные в книге, упакованы в отдельные JAR-файлы.
Данные, находящиеся в хранилище, – это массив байтов. Независимо от того, сохраняете ли вы строку текста или целые числа, они сохраняются в виде последовательности байтов.
Позже в этой главе вы узнаете, что любые стандартные данные Java очень легко конвертировать в массив байтов и обратно, и научитесь делать это.
MIDP API поддерживает RMS через пакет javax.microedition.rms. В этом пакете находятся класс и несколько интерфейсов, поддерживающих создание и работу с хранилищами данных. Эти функции выполняет класс RecordStore, он предоставляет программируемый интерфейс для одного хранилища данных. Этот класс выполняет чтение и запись хранилищ записей.
Использование класса RecordStore обычно подразумевает выполнение следующих шагов:
1. открытие/создание хранилища записей;
2. запись/чтение данных в/из хранилища записей;
3. закрытие хранилища записей.
Вам также может потребоваться выполнить особые задачи, например, удалить определенную запись или целое хранилище, эти действия также можно выполнить, используя класс RecordState.
Ниже перечислены некоторые методы класса RecordState, используемые для работы с записями:
► openRecordStore() – открывает хранилище данных для чтения/записи;
► getNumRecords() – возвращает число записей в хранилище;
► getRecordSize() – возвращает размер определенной записи;
► getRecord() – возвращает данные определенной записи;
► addRecord() – добавляет данные в хранилище;
► deleteRecord() – удаляет определенную запись;
► deleteRecordStore() – удаляет хранилище данных;
► closeRecordStore() – закрывает хранилище данных.
Как вы видите, эти методы выполняют основные задачи по управлению записями в хранилище. Конечно, в классе RecordStore есть и другие методы, но перечисленных методов вполне достаточно для хранения и управления списком рекордов.
Чтобы начать работу с хранилищем записей, необходимо создать экземпляр класса RecordStore:
RecordStore rs = null;
Чтобы создать сам объект REcordStore, необходимо вызывать статический метод openRecordStore():
try {
rs = RecordStore.openRecordStore("HiScores", true);
}
catch (Exception e) {
System.err.println("Failed creating hi score record store!");
}
Первый параметр, передаваемый в метод, – это название хранилища записей, в данном случае – хранилища списка рекордов. Второй параметр определяет, нужно ли создать новое хранилище записей, если указанного хранилища не существует. Значение true говорит о том, что хранилище записей будет открыто или создано, если значение параметра равно false, то хранилище будет открыто, только если оно существует. Вот почему переменная rs инициализируется значением null – вы сможете проверить, было ли открыто хранилище.
Когда хранилище открыто, вы готовы начать чтение и/или запись данных. Если вы вспомните, о чем шла речь ранее, то запись состоит из уникального числового ID и массива байтов. Давайте рассмотрим, как можно добавить данные в хранилище, используя метод addRecord() класса RecordStore:
try {
rs.addRecord(recordData, 0, recordData.length);
}
catch (Exception e) {
System.err.println("Failed writing hi scores!");
}
В приведенном коде переменная recordData – это массив байтов, содержащий помещаемые в хранилище данные. Метод recordData() принимает три параметра: байтовый массив данных, смещение, с которого начинаются данные в массиве, а также число байт записываемых данных. Если вы хотите записать весь массив данных, то вторым параметром передайте 0, а третьим – длину массива байтов, как показано в примере.
Чтение данных из хранилища несколько сложнее, чем запись, потому что вы не знаете, сколько данных находится в хранилище. Чтобы прочитать данные из хранилища, необходимо выполнить следующие ходы:
1. пройти по всем записям хранилища;
2. получить размер текущей записи;
3. при необходимости изменить указатель записи, чтобы вместить всю запись;
4. прочитать запись.
Я мог бы вам показать, как прочитать одну запись, однако в большинстве случаев необходимо считать все содержимое хранилища. Описанные выше шаги уже дают представление о том, как это реализовать, – пройти по всем записям хранилища. Ниже приведен код, выполняющий это:
try {
int len;
byte[] recordData = new byte[8]; //В размере записи (8 байт) нет ничего магического – это просто предположение о среднем размере записи
for (int i = 1; i <= rs.getNumRecords(); i++) {
// выделить память при необходимости
if (rs.getRecordSize(i) > recordData.length) //Если размер записи больше 8 байт, этот код выделяет необходимый объем памяти
recordData = new byte[rs.getRecordSize(i)];
// считать данные в массив
len = rs.getRecord(i, recordData, 0);
// Do something with the record data
... //Здесь вы напишете игровой код, конвертирующий и сохраняющий данные в обычный формат, например, int
}
}
catch (Exception e) {
System.err.println("Failed reading hi scores!");
}
Этот код показывает, как пройти по всем записям хранилища, считывая по одной записи. Важно отметить, что при необходимости выделяется память для записи. Обычно этого не требуется при работе со списком рекордов, поскольку все записи в данном случае имеют приблизительно одинаковый размер, но осторожность не повредит.
Есть ряд ситуаций, когда может потребоваться удалить все хранилище записей. К счастью, в классе RecordStore для этого есть статический метод deleteRecordStore(). Все, что необходимо сделать, – это передать ему название хранилища записей, например, так:
try {
Rs.deleteRecordStore("HiScores");
}
catch (Exception e) {
System.err.println("Failed deleting record store!");
}
Метод deleteRecordStore() полезен в тех случаях, когда вам не нужны данные старого хранилища, а вы хотите записать новое. Этот прием будет использован дальше в этой главе, когда вы будете обновлять содержимое списка рекордов игры Space Out. Вместо того чтобы искать и изменять конкретную запись в хранилище, игра Space Out 2 удаляет старое хранилище и записывает новое. Об этом вы узнаете чуть позже в этой главе.
Тем временем метод closeRecord() – последний метод класса RecordStore, который интересен с точки зрения программирования мобильных игр. Этот метод необходим для закрытия хранилища записей по окончании работы с ним:
try {
rs.closeRecordStore();
}
catch (Exception e) {
System.err.println("Failed closing hi score record store!");
}
Хотя про хранилища записей и поддержку MIDP API Системы управления записями можно сказать намного больше, вам необходимо знать лишь то, что поможет добавить интересные штрихи в создаваемые вами мобильные игры. Поэтому оставшаяся часть главы посвящена добавлению списка рекордов в игру Space Out, разработанную в предыдущей главе.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.