Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 18 (всего у книги 35 страниц)
В примере Wanderer 2 необходимо ввести ряд переменных для управления дополнительным слоем, менеджером слоев, окном вида, а также текущим изображением воды. Ниже приведены наиболее важные переменные мидлета Wanderer 2:
private LayerManager layers;
private int xView, yView; //Важно отслеживать положение окна вида менеджера слоев
private TiledLayer backgroundLayer;
private TiledLayer barrierLayer;
private int waterDelay, waterTile;
private Sprite personSprite;
Первая переменная – это менеджер слоев, в ней нет ничего удивительного. Переменные xView и yView хранят координаты положения окна вида – текущей видимой области слоев. Если вы вспомните, о чем шла речь ранее, окно вида используется для отображения видимой области слоев, при этом отпадает необходимость перемещать сами слои, как это было сделано в примере Wanderer.
Переменные waterDelay и waterTile помогают создавать анимационные элементы с изображением воды. Первая из этих переменных задает скорость анимации, а вторая содержит номер выводимого на экран изображения.
Два слоя создаются как объекты класса TiledLayer. Следующий код задает одинаковые размеры слоев:
try {
backgroundLayer = new TiledLayer(16, 16, //Фоновый слой и слой-преграда имеют одинаковый размер
Image.createImage("/Background.png"), 48, 48);
barrierLayer = new TiledLayer(16, 16,
Image.createImage("/Barrier.png"), 48, 48);
}
catch (IOException e) {
System.err.println("Failed loading images!");
}
Код, создающий фоновый слой и инициализирующий холст, расположен в методе start() класса WCanvas. Так, фоновый слой задается массивом целых чисел (картой):
int[] backgroundMap = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //Нули в коде – это пустые ячейки, которые будут покрыты слоем-барьером
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 5, 15, 15, 15, 15, 15, 15, 6, 2, 2, 0,
0, 2, 2, 2, 2, 7, 10, 1, 1, 1, 1, 1, 16, 2, 2, 0,
0, 2, 2, 2, 2, 2, 14, 1, 1, 1, 1, 1, 16, 2, 2, 0,
0, 2, 2, 2, 2, 2, 7, 10, 1, 1, 1, 1, 16, 2, 2, 0,
0, 2, 2, 2, 2, 2, 2, 14, 1, 1, 1, 1, 16, 2, 2, 0,
0, 2, 2, 2, 2, 2, 2, 14, 1, 9, 10, 1, 16, 2, 2, 0,
0, 2, 2, 5, 15, 6, 2, 14, 1, 11, 12, 1, 16, 2, 2, 0,
0, 2, 2, 14, 1, 16, 2, 7, 13, 13, 13, 13, 8, 2, 2, 0,
0, 2, 2, 7, 13, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
Такой массив должен быть вам знаком. Почти такой же код вы видели, когда познакомились с описанием фонового слоя. Следующий код инициализирует замощенный слой в соответствии с его картой:
for (int i = 0; i < backgroundMap.length; i++) {
int column = i % 16;
int row = (i – column) / 16;
backgroundLayer.setCell(column, row, backgroundMap[i]);
}
Наиболее важный элемент этого кода – это число 16, которое определяет число строк и столбцов в замощенном слое.
Аналогично выполняется инициализация слоя-барьера. Ниже приведен код карты этого слоя, который также задан в виде массива целых чисел:
barrierLayer.createAnimatedTile(1);
int[] barrierMap = {
–1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, //Ячейки с индексом -1 будут содержать анимационные изображения воды
–1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1,
1, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 22, 1,
1, 18, 0, 5, 5, 5, 5, 8, 0, 0, 8, 0, 0, 0, 20, -1,
1, 18, 0, 0, 0, 0, 0, 0, 0, 16, 8, 0, 0, 0, 20, 1,
–1, 18, 7, 7, 7, 11, 7, 8, 0, 0, 10, 5, 0, 0, 20, -1,
1, 18, 0, 11, 0, 0, 11, 7, 7, 12, 0, 0, 0, 0, 20, -1,
–1, 18, 0, 7, 7, 7, 0, 11, 12, 8, 0, 0, 0, 0, 20, 1,
1, 18, 0, 11, 12, 0, 15, 10, 0, 8, 0, 0, 0, 0, 20, 1,
1, 18, 0, 0, 13, 0, 10, 5, 5, 9, 0, 0, 0, 0, 20, -1,
–1, 18, 7, 10, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 20, 1,
–1, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, -1,
1, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 1,
1, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 1,
–1, 23, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 24, -1,
–1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1
};
Эта карта инициализирует слой в следующем фрагменте кода:
for (int i = 0; i < barrierMap.length; i++) {
int column = i % 16;
int row = (i – column) / 16;
barrierLayer.setCell(column, row, barrierMap[i]);
}
После того как слои созданы и инициализированы, можно переходить к созданию менеджера слоев. Помните, что менеджер слоев еще и управляет спрайтом героя, а также окном вида на спрайт и замощенные слои. Ниже приведен код, создающий и инициализирующий менеджер слоев и окно вида:
layers = new LayerManager();
layers.append(personSprite); //Порядок добавления слоев очень важен, поскольку он определяет их Z-порядок
layers.append(barrierLayer);
layers.append(backgroundLayer);
xView = (backgroundLayer.getWidth() – getWidth()) / 2;
yView = (backgroundLayer.getHeight() – getHeight()) / 2;
layers.setViewWindow(xView, yView, getWidth(), getHeight());
personSprite.setPosition(xView + (getWidth() -
personSprite.getWidth()) / 2,
yView + (getHeight() – personSprite.getHeight()) / 2);
Метод менеджера слоев append() добавляет слой. Важно отметить, что слои добавляются сверху вниз. Иначе говоря, последний слой будет помещен под предыдущими. Поэтому сначала добавляется спрайт персонажа, а затем – слой-барьер и фоновый слой. Затем задаются положение и размер окна вида. Его размер равен размеру холста, а его положение хранится в переменных xView и yView и инициализируется координатами центра слоев. Спрайт героя размещается в центре экрана.
Ранее вы узнали, что определенные элементы замощенного слоя – анимационные. Для создания анимации необходимы две переменные. Вот как они инициализируются:
waterDelay = 0;
waterTile = 1;
Переменная waterDelay – это просто счетчик, поэтому она инициализируется значением 0. Переменная waterTile содержит номер первого изображения анимационного элемента замощенного слоя, в данном случае -1 (рис. 11.5). Переменные для создания анимации воды используются в методе update(), в котором также реализована большая часть логики мидлета. В листинге 11.1 приведен код метода update().
Листинг 11.1. Метод update() класса WCanvas перемещает окно вида в соответствии с нажатиями клавиш
private void update() {
// обработка пользовательского ввода
if (++inputDelay > 2) {
int keyState = getKeyStates();
int xMove = 0, yMove = 0;
if ((keyState & LEFT_PRESSED) != 0)
xMove = -12;
else if ((keyState & RIGHT_PRESSED) != 0)
xMove = 12;
if ((keyState & UP_PRESSED) != 0)
yMove = -12;
else if ((keyState & DOWN_PRESSED) != 0)
yMove = 12;
if (xMove != 0 || yMove != 0) { //Если произошло движение, то необходимо изменить положение окна вида, центрировать спрайт героя на экране, воспроизвести анимацию спрайта героя
layers.setViewWindow(xView + xMove, yView + yMove, getWidth(),
getHeight());
personSprite.move(xMove, yMove);
personSprite.nextFrame();
}
// Проверить столкновение спрайта со слоем-барьером
if (personSprite.collidesWith(barrierLayer, true)) {
// Воспроизвести звук столкновения
try {
Manager.playTone(ToneControl.C4 + 12, 100, 100); //Воспроизвести звук, если герой столкнулся со слоем-барьером
}
catch (Exception e) {
}
// Восстановить исходные положения окна вида и персонажа
layers.setViewWindow(xView, yView, getWidth(), getHeight());
personSprite.move(-xMove, -yMove);
}
else {
// если нет столкновения, то применить изменения к окну вида
xView += xMove;
yView += yMove;
}
// обновить анимацию элементов слоя
if (++waterDelay > 2) {
if (++waterTile > 4) //Этот код воспроизводит анимацию изображения воды
waterTile = 1;
barrierLayer.setAnimatedTile(-1, waterTile);
waterDelay = 0;
}
// обнулить задержку ввода
inputDelay = 0;
}
}
Первый интересный фрагмент кода – это обработка пользовательского ввода, в результате персонаж перемещается по замощенному слою. В отличие от предыдущего примера Wanderer, в этой версии для отображения текущей видимой области слоев используется окно вида. Временные переменные xMove и yMove используются для того, чтобы определить необходимость перемещения окна вида. При необходимости окно перемещается на значения, хранимые в этих переменных. В этом случае спрайт героя перемещается в центр экрана.
Настоящее волшебство начинается в середине метода update(), где определяется столкновение между спрайтом героя и слоем-барьером. Этот код превращает слой в слой-барьер. Если столкновение произошло, то воспроизводится соответствующий звук, а окно вида и спрайт героя возвращаются в положение до столкновения. Если столкновения нет, то положение окна вида изменяется, переменные xView и yView принимают новые значения.
Совет Разработчику
Важно отметить, что метод update() больше не вызывает метод checkBackgroundBounds(), как это делалось в мидлете Wanderer Этот метод больше не требуется, потому что теперь перемещения героя ограничиваются проверкой столкновений со слоем-барьером.
В конце метода update() вы обнаружите код, обновляющий фрагменты слоя с изображением воды. Счетчик waterDelay контролирует, что обновление будет выполняться на каждом четвертом цикле. Счетчик принимает значения 0, 1, 2, затем выполняется обновление, и счетчик обнуляется. А изображения воды изменяются от 1 до 4 (рис. 11.5). Этот код создает эффект движения воды во всех элементах замощенного слоя с индексом -1.
Несомненно, стоит рассмотреть и последний простой фрагмент кода мидлета Wanderer 2. Чтобы понять, о чем я говорю, посмотрите листинг 11.2.
Листинг 11.2. Метод draw() в менеджер слоев, одной строкой кода
private void draw(Graphics g) {
// вывести слои
layers.paint(g, 0, 0); //Вывод спрайтов и слоев
// вывести содержимое буфера
flushGraphics();
}
Приведенный листинг содержит код метода draw() мидлета Wanderer 2, этот код отвечает за вывод графики на холст мидлета. Как вы видите, этот метод вызывает лишь один метод рисования, метод paint() менеджера слоев. Поскольку в окне вида уже установлена выводимая на экран область слоев, то вы можете передать в метод paint() координаты (0,0).
Изменения кода по сравнению с мидлетом Wanderer не столь значительны, однако эффект, как вы увидите далее, велик.
Мидлет Wanderer 2 – это скромное подобие мобильной игры, в которой вы управляете героем, проводите его через лабиринт и исследуете виртуальный мир. Все, что остается сделать, – это усложнить лабиринт и добавить спрайты врагов. Даже если считать, что Wanderer 2 мало похож на мобильную игру, этот мидлет очень интересен с точки зрения применения замощенных слоев и их эффективного использования.
На рис. 11.7 показано, как выглядит экран при первом запуске мидлета Wanderer 2; игровой экран центрирован относительно замощенных слоев, а спрайт героя находится в центре лабиринта.
Рис. 11.7. В мидлете Wanderer 2 герой пробирается через лабиринт, расположенный поверх фонового слоя
По мере продвижения героя по лабиринту, вы заметите, что невозможно различить два замощенных слоя, использованных для построения мидлета. Дойдя до края карты, вы увидите анимацию воды. На рис. 11.8 показан герой, стоящий у воды, некоторые элементы – анимационные.
Рис. 11.8. Некоторые из элементов слоя с изображением воды – анимационные, они создают более реалистичный эффект
Конечно, печатная страница не может передать анимацию, но если вы посмотрите ближе, заметите, что некоторые из элементов слоя с изображением воды отличаются от других. А еще лучше, запустите мидлет Wanderer 2 самостоятельно и посмотрите на анимацию на экране эмулированного устройства или вашего телефона.
РезюмеВ этой главе вы соединили все знания о спрайтах и замощенных слоях, полученные в предыдущих главах, научились управлять ими. Вы узнали, как использовать стандартный класс LayerManager для управления несколькими слоями как единым целым. Вы также изменили мидлет Wanderer, разработанный в предыдущей главе, добавили один слой, который служит лабиринтом, по которому перемещается герой.
Вы, вероятно, удивляетесь, что добрались до середины книги, а сделали лишь одну полноценную игру. Следующая глава решит эту проблему. Вы создадите самую интересную игру книги – приключенческую пиратскую игру High Seas.
В заключениеВы, вероятно, заметили, что в примере Wanderer 2 я не использовал все пространство слоя-барьера для стен лабиринта. Вы можете сделать этот мидлет интереснее, если увеличите размер слоев и создадите большой лабиринт. Для этого выполните следующие шаги:
1. сначала определитесь с размером карты. После этого на листе бумаги, или, используя специальное программное обеспечение, создайте карту с лабиринтом;
2. измените код создания карты в методе start() в соответствии с новыми размерами замощенного слоя;
3. вставьте карты фонового слоя и слоя-барьера в код мидлета как целочисленный массив (также в методе start());
4. при инициализации замощенного слоя убедитесь, что в цикле for указано верное число строк и столбцов.
Такое сравнительно небольшое число изменений позволит добиться значительных результатов. Вы даже можете использовать какой-нибудь метод автоматического создания лабиринтов, чтобы при каждом запуске мидлета появлялся новый лабиринт.
Глава 12
High Seas: почувствуй себя пиратом!
Архив Аркад
На заре игр про Тарзана, в 1982 году, компания Taito выпустила аркаду Jungle King. В этой захватывающей игре вы перепрыгиваете с лианы на лиану, чтобы спасти девушку, похищенную каннибалами. На протяжении нескольких уровней, герой был должен передвигаться с помощью лиан, перепрыгивать через глыбы и, вооруженный ножом, осторожно пройти реку, полную голодных крокодилов. Компании Taito был предъявлен иск владельцами прав на Тарзана, Edgar Rise Burrogh's estate. В ответ на это игра Jungle King была переименована в Jungle Hunt, а герой, Тарзан, поменял львиную шкуру на костюм исследователя. Конечно, из игры был удален и знаменитый крик Тарзана.
В главе 7 вы разработали свою первую полноценную мобильную игру, Henway. Несмотря на то что вы создали также ряд интересных мидлетов, не было разработано ни одной полной мобильной игры. В этой главе вы пройдете по этапам создания игры High Seas. Это приключенческая игра, в которой вы управляете пиратским кораблем и пытаетесь спасти пиратов, оказавшихся за бортом. В игре High Seas вы используете практически все, что было изучено вами до настоящего момента. Это хороший шанс поиграть и поэкспериментировать.
Прочитав главу, вы узнаете:
► что мобильные игры про пиратов – это не всегда грабеж и разрушение;
► как разработать мобильную игру High Seas, использующую преимущества замощенных слоев;
► как управлять взаимодействием спрайтов в реальной игре;
► как создать код игры High Seas.
Обзор игры High SeasВ игре High Seas, которую вы будете разрабатывать и создавать в этой главе, игрок управляет пиратским кораблем, который во время шторма потерял часть команды. Цель игры – спасти как можно больше членов команды. На вашем пути встретятся водные мины и кровожадные осьминоги, которые усложняют спасательную кампанию. Ваш корабль в игре имеет ограниченный запас энергии, который уменьшается каждый раз, когда вы нарываетесь на мину или попадаетесь в щупальца осьминога. Чтобы пополнить запас энергии, вы должны найти бочки с провизией и подобрать их. Игра заканчивается, когда корабль теряет всю энергию и тонет.
В игре High Seas используется карта, размер которой много больше размеров экрана. Видимая область карты изменяется по мере перемещения корабля по экрану. Аналогично примеру Wanderer 2, рассмотренному в предыдущей главе, в игре High Seas используются два слоя. Слой с изображением воды – это фоновый слой. Поверх него располагается слой, содержащий землю, маленькие скалистые острова – препятствия на пути пиратского судна.
В игре High Seas сделан еще Game один шаг вперед по сравнению с мидлетом Wanderer 2. Здесь необходимо отображать игровую информацию, например, энергию пиратского корабля и число спасенных пиратов. Эта информация отображается в строке, расположенной у верхней границы экрана. Окно вида расположено непосредственно под этой строкой. На рис. 12.1 показана укрупненная схема игрового экрана приложения High Seas.
Рис. 12.1. Игра High Seas состоит из информационной строки, окна вида на слои, двух замощенных слоев и нескольких спрайтов
Рисунок 12.1 дает очень хорошее представление о том, как будет выглядеть экран игры High Seas. Информационная строка располагается в верхней части экрана над окном вида, в ней отображается важная игровая информация: оставшаяся у корабля энергия и число спасенных пиратов. Окно вида – эта та область экрана, в которой разворачиваются основные события игры. Чтобы создать виртуальный мир, океан с островами и скалами, используются два замощенных слоя – фоновый и слой-барьер. Наконец, несколько спрайтов формируют саму игру (осьминоги и мины, которые разрушают корабль, бочки, пополняющие энергию судна и пираты, которых необходимо спасти).
В этой игре нет определенной цели, например, прохождение уровня или уничтожение врага. Вы просто должны спасти как можно больше пиратов, прежде чем подорветесь на мине или угодите в щупальца спрутов.
Разработка игрыОбзор игры High Seas уже дал вам представление о внешнем виде игры, даже если вы не представляете его в деталях. Например, вы уже знаете, сколько нужно спрайтов в игре. Вы знаете, что есть один пиратский корабль, управляемый игроком. В игре должен присутствовать, по крайней мере, один спрайт потерявшегося пирата, спрайты бочки, мины и осьминога. Можно использовать по одному спрайту каждого вида, но в этом случае игра не будет такой захватывающей и привлекательной. Я предлагаю использовать следующее количество спрайтов: 2 пирата, 2 бочки, 3 мины и 3 спрута.
Обратите внимание, что в игре больше «отрицательных» спрайтов (мин и осьминогов), чем положительных (бочек и пиратов). Идея включать больше отрицательных элементов, чем положительных, заключается в том, чтобы корабль игрока с большей вероятностью потерпел крушение. Поверьте мне, что лучше сделать игру сложной, чем скучной. Игроки могут адаптироваться к сложностям, а вот сделать скучную игру интереснее нельзя.
В копилку Игрока
Многие из популярных аркад оставались такими долгое время благодаря своей сложности. Сразу вспоминаются игры Joust и Defender в которые, несмотря на достаточно простой дизайн, не очень просто играть. Хотя вы можете переусердствовать и сделать игру чересчур сложной, многие игроки ценят трудности.
Вы можете догадаться, сколько изображений понадобится? Как показано ниже, в игре необходимо восемь растровых изображений:
► изображение информационной строки;
► фоновое изображение воды;
► фоновое изображение с элементами суши;
► изображение пиратского корабля (рис. 12.2);
Рис. 12.2. Изображение пиратского корабля состоит из четырех фреймов, нос корабля повернут в четырех различных направлениях
► изображение пирата (рис. 12.3);
Рис. 12.3. Изображение пирата состоит из четырех фреймов, создающих иллюзию того, что пират качается на волнах
► изображение бочки (рис. 12.4);
Рис. 12.4. Изображение бочки состоит из четырех фреймов, которые создают впечатление, что бочка дрейфует в море
► изображение мины (рис. 12.5);
Рис. 12.5. Изображение мины состоит из двух фреймов, имитирующих качание на волнах
► изображение осьминога (рис. 12.6).
Рис. 12.6. Изображение спрута состоит из двух фреймов, создающих иллюзию, что он плывет
Первое изображение (информационная строка) – единственное, что может удивить в этом описании. Изображение информационной строки – это просто чистое изображение, служащее фоном. Два фоновых изображения – замощенные слои, имитирующие воду и сушу. В следующих двух разделах вы узнаете об этих изображениях подробнее.
В копилку Игрока
Информационная строка – это единственный элемент игры High Seas, который зависит от размеров экрана мобильного устройства (ширины). Чтобы масштабировать игру в зависимости от размеров экрана телефона, для информационной строки вы можете использовать или более широкое, или замощенное изображение. К счастью, больший размер экрана не повлияет на динамику игры, а лишь увеличит видимую область карты.
Остальные спрайтовые изображения используют фреймовую анимацию, что делает игру визуально интереснее. Например, спрайт пиратского корабля состоит из четырех фреймов, в каждом из которых нос корабля ориентирован в определенном направлении. Спрайты пирата, бочки и мин перемещаются по поверхности воды. Наконец, спрайт осьминога показывает свои щупальца, устрашая игрока.
Теперь, когда вы познакомились с большей частью графических объектов, используемых в игре, давайте рассмотрим остальные необходимые в игре элементы. Во-первых, очевидно, что необходимо следить за тем, сколько у корабля осталось энергии. Также нужно вести счет спасенных пиратов. Необходима булевская переменная, которая будет отслеживать, закончена ли игра. Итак, игра High Seas должна содержать средства контроля следующей информации:
► оставшаяся у корабля энергия;
► счет – число спасенных пиратов;
► логическая переменная, говорящая об окончании игры.
Теперь вы можете перейти к созданию карт слоев игры High Seas. Помните, что в игре необходимы и другие переменные, например, спрайты и проигрыватели, но приведенный список переменных отслеживает состояние игры и хранит необходимую информацию.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.