Создание игр для мобильных телефонов - Майкл Моррисон
Шрифт:
Интервал:
Закладка:
Давайте подведем итог. Первоначальная разработка игры Henway говорит о том, что в процессе игры мы должны управлять следующими элементами:
► числом жизней цыплят;
► счетом;
► булевской переменной окончания игры;
► переменной задержки пользовательского ввода.
Помня об этом, вы готовы перейти дальше к разработке кода игры Henway.
Разработка игры
Я надеюсь, что к настоящему моменту вы поняли, из чего состоит игра Henway. В следующих разделах речь пойдет о разработке кода этого мидлета. Это достаточно просто, поскольку большая часть кода основана на рассмотренных ранее примерах.
Написание кода
Неудивительно, что код игры Henway начинается с написания класса специального холста, производного от класса GameCanvas. Я говорю о классе Hcanvas, который ответственен за реализацию всей логики игры. Давайте рассмотрим один из его фрагментов. Ниже приведено объявление переменных класса:
private Display display;
private boolean sleeping;
private long frameDelay;
private int inputDelay;
private Random rand;
private Image background;
private Image chickenHead;
private Sprite chickenSprite; //Спрайты в игре Henway – это спрайт цыпленка и 4 спрайта автомобилей
private Sprite[] carSprite = new Sprite[4];
private int[] carYSpeed = new int[4]; //Поскольку автомобили движутся вертикально, не нужно хранить горизонтальные составляющие их скоростей
private boolean gameOver;
private int numLives;
private int score;Первые две переменные и переменная rand должны быть вам знакомы по созданным ранее программам UFO. Четвертая переменная – новая. Переменная inputDelay контролирует чувствительность пользовательского ввода в игре. Оказывается, что если цыпленок сможет перемещаться очень быстро с одной стороны шоссе на другую, то в игру будет не так уж и весело играть. Чтобы ограничить скорость цыпленка, просто используйте переменную inputDelay.
Две переменные – объекты класса Image – используются для хранения фонового изображения и изображения головы цыпленка, жизни. Хотя эти изображения очень важны в игре, все же сердце Henway – это спрайты. Переменная chickenSprite – это спрайт цыпленка, а массив carSprite хранит спрайты всех четырех автомобилей. Поскольку при нажатиях на клавиши цыпленок перемещается на равные расстояния, то нет необходимости создавать переменную скорости. Однако автомобили движутся с различными скоростями, поэтому необходим массив carYSpeed – массив скоростей автомобилей вдоль оси Y.
Последние три переменные есть практически во всех играх, они хранят текущее состояние игры, число оставшихся жизней и счет. Переменная gameOver используется в нескольких фрагментах кода для проверки конца игры.
Переменная numLives хранит число оставшихся жизней цыпленка и используется для проверки окончания игры, а также определяет число изображений головы цыпленка, выводимых на экран. Наконец, переменная score хранит число очков, набранных игроком, ее значение будет отображаться в конце игры.
Как вы знаете, при создании объекта холста класса HCanvas вызывается конструктор. Кроме того, что он устанавливает частоту кадров игры, в нем выполняется очистка экрана и обнуление задержки ввода:// установить частоту кадров (30 кадров/с)
frameDelay = 33;
// обнулить задержку ввода
inputDelay = 0;...Совет Разработчику
Помните, что частота кадров рассчитывается как обратная величина времени между кадрами в секундах. Поэтому, если перевести 33 мс в секунды, то получится 0.033 с. Если разделить 1 на 0.033, то получится приблизительно 30, то есть частота равна 30 кадров/с.
Смысл переменной inputDelay станет ясен чуть позже, когда вы узнаете, как она применяется для контролирования пользовательского ввода. Метод start() игры Henway очень важен, поскольку выполняет ряд особых инициализаций в игре. Например, следующий код инициализирует три основные глобальные переменные:
gameOver = false;
numLives = 3;
score = 0;Метод start() также загружает изображения и создает игровые спрайты:
try {
background = Image.createImage("/Highway.png");
chickenHead = Image.createImage("/ChickenHead.png");
chickenSprite = new Sprite(Image.createImage("/Chicken.png"), 22, 22);
chickenSprite.setPosition(2, 77); //Спрайт цыпленка помещается на траве в зоне старта, в левой части экрана
carSprite[0] = new Sprite(Image.createImage("/Car1.png"));
carSprite[0].setPosition(27, 0); //Этот автомобиль, также как и другие, помещается на дороге
carYSpeed[0] = 3;
carSprite[1] = new Sprite(Image.createImage("/Car2.png"));
carSprite[1].setPosition(62, 0);
carYSpeed[1] = 1;
carSprite[2] = new Sprite(Image.createImage("/Car3.png"));
carSprite[2].setPosition(93, 67);
carYSpeed[2] = -2;
carSprite[3] = new Sprite(Image.createImage("/Car4.png"));
carSprite[3].setPosition(128, 64);
carYSpeed[3] = -5;
}
catch (IOException e) {
System.err.println("Failed loading images!");
}Этот код сначала создает фон и изображения голов цыпленка, после чего переходит к созданию спрайтов. Обратите внимание, каждый спрайт привязан к определенной области экрана. Хотя вы можете использовать выражения, вычисляющие положение спрайтов на основании данных о высоте и ширине экрана, можно непосредственно указать нужные координаты, что я и сделал. После того как начальные координаты установлены, инициализируется скорость спрайтов так, чтобы автомобили двигались в разных направлениях.
...Совет Разработчику
Этот код приводит к вопросу о том, как будет вести себя приложение в зависимости от модели мобильного телефона. В нашем случае игра Henway создана для эмулятора J2ME, размер экрана которого 180 177, поэтому все координаты графики относятся именно к этому экрану. Если вы хотите, чтобы вашу игру можно было запускать на различных моделях телефонов, то вы должны вычислять положения спрайтов и изображений.
Хотя метод start() очень важен, все же большую роль играет метод update(), который обеспечивает работу всех игр, рассматриваемых в книге. В игре Henway метод update() выполняет ряд очень важных задач, например, обработку пользовательского ввода, перемещение спрайта цыпленка и проверку, попал ли цыпленок под колеса автомобиля или в сохранности преодолел шоссе. Перед выполнением любой задачи, осуществляется проверка, запущена ли игра:
if (gameOver) {
int keyState = getKeyStates();
if ((keyState & FIRE_PRESSED) != 0) {
// запустить новую игру
chickenSprite.setPosition(2, 77); //Чтобы начать игру заново, необходимо установить спрайт цыпленка в исходное положение и установить значения ряда переменных
gameOver = false;
score = 0;
numLives = 3;
}
// игра закончена, поэтому не нужно выполнять обновление
return;
}Этот код проверяет, закончена ли игра – в единственном месте, где имеет смысл перезапустить игру. Клавиша стрельбы используется для перезапуска игры. В разных телефонах эта клавиша называется по-разному, но в эмуляторе J2ME это клавиша Select, связанная с клавишей Enter персонального компьютера. Код перезапуска игры в методе update() восстанавливает исходное положение спрайта цыпленка, обнуляет переменную gameOver, счет, а также восстанавливает исходное количество жизней. Это все, что требуется для перезапуска игры. Метод update() также обрабатывает пользовательский ввод и перемещает цыпленка по экрану. Ниже приведен код, перемещающий спрайт цыпленка в соответствии с нажатыми клавишами:
if (++inputDelay > 2) {
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
chickenSprite.move(-6, 0); //Кроме того, что спрайт цыпленка перемещается, с каждым нажатием клавиши изменяется номер фрейма анимации
chickenSprite.nextFrame();
}
else if ((keyState & RIGHT_PRESSED) != 0) {
chickenSprite.move(6, 0);
chickenSprite.nextFrame();
}
if ((keyState & UP_PRESSED) != 0) {
chickenSprite.move(0, -6);
chickenSprite.nextFrame();
}
else if ((keyState & DOWN_PRESSED) != 0) {
chickenSprite.move(0, 6);
chickenSprite.nextFrame();
}
checkBounds(chickenSprite, false); //Значение false, передаваемое вторым параметром, говорит о том, что цыпленок не должен выйти за границы экрана
// обнулить задержку ввода
inputDelay = 0;
}Этот код объясняет, как работает переменная inputDelay: она увеличивается на каждой итерации игрового цикла и обрабатывает нажатия клавиш на каждой третьей итерации. Иначе говоря, реакция на нажатия клавиш снижена в три раза, это делает игру Henway более интересной и захватывающей, особенно на сложных уровнях. После того как детектировано нажатие клавиши, спрайт цыпленка перемещается на определенное расстояние и вызовом метода nextFrame() изменяется фрейм. Поскольку изображение цыпленка состоит из двух фреймов, то они сменяют друг друга при движении цыпленка. В результате такой простой анимации создается иллюзия того, что цыпленок идет.
...Совет Разработчику
Порог для переменной inputDelay, несомненно, варьируется от одной игры к другой. В некоторых играх вам может понадобиться молниеносная реакция при нажатии на клавиши, в этом случае переменная inputDelay становится ненужной.
Другой фрагмент кода, представляющий интерес, – это метод checkBounds(), который проверяет, что цыпленок остается на экране. Если вы вспомните программу UFO 2, то одноименный метод использовался для проверки того, что астероиды находятся на экране. В игре Henway новая версия этого метода, второй параметр говорит о том, следует ли ограничить перемещение спрайта (значение false) или вернуть его на противоположную сторону (значение true). Чуть позже будет приведен код этого метода.