Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 17 (всего у книги 35 страниц)
Когда весь код мидлета Wanderer написан, пора приступать к тестированию. Посмотрите на рис. 10.12, на котором показан экран при запуске игры.
Рис. 10.12. При запуске мидлета Wanderer герой появляется в центре карты
Герой находится в центре экрана и в центре игрового мира (карты). Если вы вспомните программный код, то персонаж никогда не уходит со своего места, перемещается лишь фоновый слой, создавая иллюзию ходьбы героя. Когда вы нажимаете клавиши в J2ME-эмуляторе или на клавиатуре телефона, замощенный слой перемещается, выводя на экран новые фрагменты карты. В результате персонаж перемещается по виртуальному миру (рис. 10.13).
Рис. 10.13. В игре Wanderer персонаж остается неподвижным, а фоновый слой перемещается
Так же, как и в реальном мире, виртуальный мир в Wanderer имеет границы. Соответствующий код в программе тщательно проверяет, не достиг ли герой края карты, и если да, то фоновый слой далее перемещаться не будет – графика застынет. В играх, в которых применяются замощенные слои, очень важно выполнять такие проверки и запрещать дальнейшее перемещение. В мидлете Wanderer используется первый подход. Результат показан на рис. 10.14.
Рис. 10.14. Мидлет Wanderer достаточно умен, чтобы позволить вам выйти за границы виртуального мира
В копилку Игрока
Да, конечно, Вселенная безгранична, однако карты, созданные людьми, имеют границы. А карты для замощенных слоев – не исключение.
Хотя этот мидлет – не совсем игра, вы могли бы поспорить, что Wanderer – это одна из самых интересных программ, которую вы уже видели в этой книге. Изменяющийся мир, по которому вы можете перемещаться, – это значительный шаг на пути перевода мобильных игр на новый уровень.
РезюмеДо сих пор вы, вероятно, думали, что игровая графика – это фон и спрайты. Вы не могли представить, что графику можно построить из отдельных блоков. Теперь вы имеете представление о замощенных слоях и о том, как их применять для создания игровой графики, состоящей из сравнительно небольших элементов. Замощенные слои хороши не только тем, что их можно создавать динамически, но также тем, что они требуют очень мало ресурсов. Поскольку такое свойство очень критично для мобильных игр, их целесообразно применять, когда вы будете создавать собственные игры.
В следующей главе вы продолжите знакомство с игровыми слоями, изучите работу с менеджером MIDP, который предоставляет эффективные средства управления слоями, как единым объектом. До сих пор вы сами управляли слоями, но менеджер слоев значительно облегчит вашу жизнь.
ЭкскурсияЯ никогда не думал о том, что я буду рекомендовать в книге о создании игровых мидлетов сшивать что-то из отдельных кусочков. Недавно я наткнулся на статью, в которой рассказывалось, что вдова военного разрезала одежду своего мужа на кусочки и сшила лоскутное одеяло. Это был единственный способ оставить память о муже и избавиться от его вещей. Я подумал, что процесс создания замощенного слоя очень похож на пошив одеяла из лоскутков. Если у вас, вашего друга или родственника есть лоскутное одеяло, обязательно посмотрите, какая уникальная композиция составлена из маленьких кусочков. А потом представьте, как могло бы выглядеть одеяло, если расположить кусочки несколько иначе. Это – сила замощенных слоев!
Глава 11
Управление игровыми слоями
Архив Аркад
Один из самых популярных сиквелов игр в истории Donkey Kong Junior – это переложение спортивных тем на сюжет знаменитой игры Donkey Kong. Выпущенная в 1982 году компанией Nintendo игра Donkey Kong Junior предлагает вам помочь маленькой горилле (Junior) спасти отца (Donkey Kong) от рук злого Марио (Mario). Donkey Kong Junior выделяется среди игр компании Nintendo тем, что в ней Марио – отрицательный герой. Также Donkey Kong Junior – это вторая игра в трилогии Donkey Kong, в которой Donkey Kong и Donkey Kong 3 – это начало и окончание соответственно.
Замощенные слои открывают новые возможности для мобильных игр. Как только вы начали использовать замощенные слои и спрайты, которые тоже являются слоями, управлять ими стало намного сложнее. Сложно контролировать то, какой слой должен быть нарисован поверх остальных, и каков порядок их отображения. К счастью, в MIDP API предусмотрен специальный класс, разработанный для работы со слоями в мобильной игре. Я говорю о классе LayerManager, который полезно использовать для автоматизации некоторых задач при работе с несколькими слоями. В этой главе вы не только изучите работу с классом LayerManager, но и доработаете игру Wanderer, сделаете ее намного интереснее.
В этой главе вы узнаете:
► о трудностях, связанных с управлением несколькими игровыми слоями;
► как стандартный класс LayerManager может упростить работу со слоями;
► как можно использовать два замощенных слоя для создания интересных эффектов;
► как из мидлета Wanderer сделать интересный лабиринт.
Работа с несколькими слоямиВероятно, к настоящему моменту у вас сложилось представление, что любая игра, создаваемая с помощью MIDP API, построена из слоев. Если вы вспомните, о чем шла речь в предыдущих главах, класс Layer служит базовым классом для Sprite и TiledLayer в MIDP API. В примерах, рассмотренных к настоящему моменту, слои использовались для представления различных визуальных компонентов, но они были всегда независимы друг от друга. Каждый слой необходимо было рисовать вызовом метода paint(). Аналогично, при выводе слоев на экран, вам приходилось четко контролировать очередность рисования.
Кроме отображения и отслеживания глубины каждого слоя, вам приходилось использовать специальный код для работы со слоями, размер которых больше размера экрана. Например, в мидлете Wanderer, рассмотренном в главе 10, для имитации движения вам пришлось перемещать фоновый слой. Это нетрудно, однако в более сложной игре вы можете работать с несколькими слоями и множеством спрайтов. В этом случае вы можете столкнуться с массой проблем.
Вы, вероятно, поняли, что я к чему-то веду, критикуя ранее написанный код. Я критикую предыдущую программу потому, что в сложных играх задача управления становится более трудной. К счастью, в MIDP API предусмотрено решение этой проблемы – класс LayerManager. Этот класс реализует простые, но эффективные средства рисования, создания и управления слоями.
Класс LayerManager может самостоятельно вычислять видимые области слоев, а следовательно, выводить только нужные части в окне. Хотя вы можете подумать, что окно имеет такой же размер, что и экран, – это не всегда так.
Например, число очков, количество жизней и прочая игровая информация может отображаться вдоль нижней границы экрана, отдельно от «игровой области». В этом случае вы должны уменьшить высоту окна, оставив место для информации. На рис. 11.1 показано, как менеджер слоев работает с несколькими слоями.
Рис. 11.1. Окно вида менеджера слоев можно сделать меньше игрового экрана, оставив место для другой информации
Рисунок показывает, как спрайт и слой видны в окне менеджера слоев. Более того, размер окна менеджера меньше размера экрана, важная игровая информация показывается в верхней части экрана.
Работа с классом LayerManagerХотя с первого взгляда может показаться, что работать с множеством слоев сложно, стандартный класс LayerManager достаточно просто использовать. Этот класс выступает на первый план после того, как создан слой (спрайт или замощенный слой). Идея заключается в том, что как только вы создали слой, вы передаете его менеджеру слоев, который отвечает за отображение, очередность рисования и создание окна вида.
Для управления слоями используется сравнительно небольшой набор методов класса LayerManager:
► append() – добавить слой в нижнюю часть множества управляемых менеджером слоев;
► insert() – вставить слой в определенное место во множестве;
► remove() – удалить слой с определенным индексом;
► getSize() – возвращает число управляемых слоев;
► getLayerAt() – получить слой с определенным индексом;
► paint() – вывести все слои;
► setViewWindow() – установить положение, ширину и высоту окна вида.
Эти методы применимы к каждому слою менеджера, которому присвоен уникальный индекс. Индекс слоя определяет его глубину по отношению к экрану. Индекс 0 имеет слой, самый близкий к экрану, с увеличением глубины индекс растет. Иначе говоря, самый верхний слой имеет индекс 0, а самый нижний слой – самый большой индекс. Менеджер автоматически нумерует слои по мере добавления новых, поэтому в большинстве случаев нет необходимости самостоятельно определять индексы слоев.
Хотя перечисленные выше методы класса LayerManager полезны, вы можете сделать многое, используя лишь их часть. Но перед вызовом любого из методов, необходимо создать объект класса LayerManager:
LayerManager layers = new LayerManager();
После того как объект LayerManager создан, в него необходимо добавить или вставить слои. Добавление слоя – несколько проще, поскольку вам не нужно определять индексы, но возникает необходимость добавлять слои в определенном порядке. Если вы вспомните описание метода append(), то слои добавляются в нижнюю часть множества. Это означает, что верхние слои вы должны добавлять в первую очередь. Ниже приведен пример того, как можно добавить несколько спрайтов и фоновый слой во вновь созданный менеджер:
layers.append(sprite1);
layers.append(sprite2);
layers.append(backgroundLayer);
В результате выполнения этого слоя фоновый слой окажется позади двух спрайтов. Более того, объект sprite1 будет находиться над объектом sprite2, поскольку он был добавлен первым.
Последний шаг в создании менеджера слоев – это определение окна вида. Ниже приведен код, создающий такое окно в верхнем левом углу экрана и размером с экран:
layers.setViewWindow(0, 0, getWidth(), getHeight());
Если необходимо переместить окно вида, то просто вызовите метод setViewWindow() снова, изменив два первых параметра. Вот и все, что необходимо для перемещения окна.
Анимация и замощенные слоиЯ еще не рассказал вам о приеме, с помощью которого можно создавать анимацию слоев внутри замощенного слоя. Это делается так: в карте слоя вы задаете слои с отрицательными индексами -1, -2 и т. д. Эти индексы представляют особые анимационные слои, которые можно использовать в любой момент игры.
Например, вы хотите «оживить» воду в примере Wanderer, чтобы карта мира выглядела более реалистично. Некоторые из слоев карты вы можете обозначить индексом -1, а не 1 (1 – это индекс изображения воды). Затем в методе update() мидлета необходимо добавить код, обрабатывающий все слои с индексом -1. Я имею в виду, что этот код должен менять изображения, чтобы создавать иллюзию движения. Для этого вы можете использовать любые слои из множества замощенного слоя. Чтобы создать иллюзию движения воды, достаточно добавить еще несколько «водных» изображений в набор.
Анимация в замощенных слоях поддерживается двумя методами класса TiledLayer():
► createAnimatedTile() – создание анимации в замощенном слое;
► setAnimatedTile() – установление статического изображения для определенного элемента слоя.
Чтобы понять принцип работы, нужно объяснить значение некоторых терминов. Статическим элементом будем называть элемент слоя, имеющий индекс 1 или более. Индекс 0 означает пустой элемент замощенного слоя. Анимационным элементом будем называть элемент слоя, который может отображать последовательность статических изображений, и имеет индекс -1 и меньше. Итак, анимационный элемент слоя имеет отрицательный индекс, однако в любой момент времени этот элемент представляет собой статическое изображение – часть анимации.
Чтобы собрать все воедино, посмотрите на следующий код карты слоя:
1, 1, -1, 1,
–1, -1, 1, 1,
1, -1, 1, -1,
–1, 1, -1, -1
Перед тем как интерпретировать эту карту, важно отметить, что в ней четыре статических элемента, отображающих различные изображения воды. Если эти изображения показывать в определенном порядке, то создается иллюзия движения воды. Эти элементы имеют индексы 1, 2, 3 и 4. Элементы слоя с индексом 1 – это обычные элементы, с которыми вы работали прежде. Элементы с индексом -1 – это анимационные элементы, они отображают последовательность статических элементов с индексами 1, 2, 3, 4. Эта последовательность не отражена в карте, чуть позже вы узнаете, как она применяется к анимационным слоям.
Если говорить на языке кода, сначала вы создаете анимационный слой, а потом карту замощенного слоя. Ниже приведен код, создающий анимационный слой для примера с водой:
waterLayer.createAnimatedTile(1);
Параметр в вызове этого метода – начальное статическое изображение, которое будет выводиться на месте анимационного слоя. Несмотря на то что этот элемент будет изменяться, создавая анимацию, вы должны задать нужный статический элемент. Метод createAnimatedTile() возвращает индекс созданного элемента. Первому созданному анимационному слою автоматически присваивается индекс -1, при создании последующих слоев этот индекс уменьшается (-2, -3 и т. д.).
Теперь вы создали анимационный элемент и установили карту для замощенного слоя. Пока этот элемент будет похож на все остальные, без анимации, поскольку ему при инициализации был присвоен индекс 1. Чтобы начать анимацию, вызовите метод setAnimatedTile() и передайте ему новое значение индекса:
waterLayer.setAnimationTile(-1, 2);
Этот код изменяет все анимационные элементы с индексом -1, теперь на их месте отображаются изображения с индексом 2. Полезно хранить индекс текущего изображения в отдельной переменной, чтобы периодически увеличивать его. В этом случае вы можете изменять элементы циклически, вызывая переменную setAnimatedTile().
Совет Разработчику
Если вы хотите создать реалистичный эффект движения воды, используйте несколько различных анимационных элементов слоя, которые изменяются асинхронно. Это создаст реалистичную иллюзию движения.
Если вы потеряли суть в таком количестве деталей, то я повторю. Основное достоинство анимационных элементов слоя заключается в том, что они реализуют возможность изменять множество элементов слоя одной строкой кода. Если пример анимации воды показался вам интересным, вы будете приятно удивлены, что в примере Wanderer 2, приведенном в следующем разделе, применяется эта техника.
Создание программы Wanderer 2В предыдущей главе вы познакомились с замощенными слоями и создали программу Wanderer. В мидлете Wanderer вы можете управлять героем, перемещающимся по карте, которая намного крупнее экрана большинства мобильных телефонов. В мидлете Wanderer использовался один замощенный слой, который играл роль скорее фона, нежели интерактивной составляющей программы. Слои становятся более ценными, если вы разрабатываете их так, чтобы они взаимодействовали со спрайтами. Например, вы можете создать «слои-барьеры», ограничивающие перемещение спрайтов. Это становится возможным благодаря классу Sprite, который позволяет определять столкновения не только спрайтов, но и спрайтов с замощенными слоями.
Оставшаяся часть этой главы посвящена модификации мидлета Wanderer, в котором будет применяться фоновый слой и слои-барьеры. Фоновый слой в мидлете Wanderer похож на исходный фоновый слой, а слои-преграды – это нововведение, они создают лабиринт, по которому должен пробираться герой. Если вы знакомы со старыми играми, например, Gauntlet или Castle Wolfenstein, вы можете представить, насколько полезными могут быть слои-лабиринты для создания уровней игры.
В мидлете Wanderer 2 используются не только замощенные слои, эта программа также демонстрирует преимущества анимационных слоев. В этом случае анимационные слои – слои с изображением воды, расположенные вдоль краев фонового слоя из примера Wanderer.
Другое важное изменение кода в Wanderer 2 – это применение класса LayerManager, который в новой программе используется для управления фоновым слоем и спрайтом героя. Окно вида менеджера показывает текущее положение слоев, нет необходимости перемещать слои относительно экрана телефона.
Подведем краткий итог. Я перечислю все изменения, которые мы внесем в мидлет Wanderer, созданный в предыдущей главе:
► добавить слои-барьеры, немного изменить фоновый слой. Слои-барьеры ограничивают передвижение героя;
► анимационные элементы замощенного слоя создают более реалистичную имитацию воды;
► менеджер слоев применяется для управления слоями и спрайтом персонажа;
► код должен перемещать окно вида менеджера слоев, при этом слои остаются неподвижными. Поскольку спрайт должен перемещаться в координатах, связанных с окном вида, то он должен перемещаться вместе с окном вида.
Теперь вы понимаете, что мидлет Wanderer 2 будет интереснее своего предшественника. Если вы с трудом представляете, какие изменения будут внесены, вероятно, вам следует посмотреть еще раз пример Wanderer, рассмотренный в предыдущей главе. В любом случае, код программы Wanderer 2, который вы увидите чуть позже, расставит все на свои места.
В мидлете Wanderer 2 используются два замощенных слоя, следовательно, необходимы и две карты слоев. Два слоя – это фоновый слой, земля, по которой герой может свободно перемещаться, и слой-барьер, состоящий из воды и стен, и ограничивающий. Слой-барьер должен отображаться поверх фонового слоя так, чтобы создавалась иллюзия единого пространства.
Смысл использования двух слоев заключается в том, чтобы разъединить объекты, ограничивающие перемещение героя, от прочих объектов. Любая графика слоя-барьера ограничивает движения персонажа.
Фоновая карта
Вы можете подумать, что фоновая карта в программе Wanderer 2 будет точно такая же, как и в мидлете Wanderer, однако это не так, в ней будет существенное отличие. Если вы вспомните программу Wanderer, то герой не мог передвигаться по воде. Такое ограничение было сделано простым вычислением текущего положения спрайта персонажа. Поскольку, используя слой-барьер, можно с легкостью ограничить перемещение спрайта персонажа, то нет необходимости ограничивать движение героя, создавая специальный код. Важно также то, что теперь нет необходимости создавать элементы в тех местах, где будет размещаться слой-барьер.
Чтобы представить, о чем я говорю, посмотрите на рис. 11.2, теперь фоновому слою не нужны границы.
Рис. 11.2. Теперь фоновому слою не нужны границы, поскольку они будут покрыты элементами с изображением воды слоя-барьера
Черная область, которую вы видите вокруг области суши на рисунке, – это прозрачные элементы слоя, которые не содержат графики. Аналогичные элементы, расположенные в слое-преграде, будут заполнены изображением воды, которое будет ограничивать перемещения персонажа. На самом деле, как вы увидите чуть позже, травянистый берег будет ограничен скалами слоя-преграды.
А пока посмотрим на код карты фонового слоя:
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
К сожалению, этот код не имеет особого смысла, если не посмотреть на изображение, ассоциированное с этим замощенным слоем. На рис. 11.3 показаны элементы слоя, которые используются для построения фонового слоя.
Рис. 11.3. Фоновый замощенный слой можно визуально представить, если вместо индексов подставить соответствующие изображения
Если вы индексам поставите в соответствие изображения, то вам нетрудно будет представить карту, показанную на рис. 11.2; помните, что ячейкам с индексом 0 соответствуют прозрачные области замощенного слоя, а следовательно, в этих областях не будет ничего выводиться. Карту слоя-барьера вы увидите в следующем разделе и поймете, почему края фонового слоя прозрачны.
Карта преград
Слой-барьер разработан таким образом, что он выводится поверх фонового слоя. Это означает, что графика слоя-барьера выводится поверх графики фонового слоя. Более того, мидлет Wanderer 2 разработан так, что этот слой ограничивает перемещение спрайта персонажа. Иначе говоря, пустые ячейки слоя барьера означают те области карты, по которым герой может передвигаться.
На рис. 11.4 показан слой-барьер, черные области соответствуют тем областям, в которых персонаж может свободно перемещаться.
Рис. 11.4. В слое-барьере для ограничения передвижений спрайта героя используются вода, скалы и фрагменты лабиринта
Большая часть слоя-барьера прозрачна – персонаж может свободно перемещаться. Даже фрагмент лабиринта содержит значительные прозрачные области, означающие свободу передвижения героя. Ниже приведен код карты слоя, показанного на рис. 11.4:
-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
Этот код карты сложно понять, не имея представления о том, какие изображения стоят за индексами. На рис. 11.5 показаны изображения, из которых создается замощенный слой-барьер.
Рис. 11.5. Можно представить, как выглядит слой-барьер, если расположить элементы в нужном порядке
Возвращаясь к коду карты, сложно не заметить, что в карте присутствуют элементы с отрицательными индексами. Если вы вспомните, о чем шла речь чуть раньше в этой главе, отрицательные индексы используются для обозначения анимационных элементов слоя. В нашем примере элементы с индексом -1 означают анимационный элемент с изображением воды. Обратите внимание, что одни элементы в замощенном слое-барьере имеют индекс -1, а другие – статические, с индексом 1. Это делает анимацию более реалистичной, потому что не все элементы должны изменяться одновременно.
Более подробно с созданием анимации элементов слоя вы познакомитесь в следующем разделе. А перед тем как вы перейдете к ней, посмотрите на то, как выглядят фоновый слой и слой-барьер вместе (рис. 11.6).
Рис. 11.6. Пример Wanderer 2 состоит из двух слоев – фона и лабиринта
Рисунок 11.6 должен прояснить все, что касается пустых элементов слоев. Пустые элементы фонового слоя оказываются под элементами слоя-барьера, в то время как сквозь пустые элементы слоя-преграды видны трава и песок фонового слоя.
Слои – это сущность примера Wanderer 2, это отражается в коде, который будет приведен далее.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.