Создание игр для мобильных телефонов - Майкл Моррисон
Шрифт:
Интервал:
Закладка:
if (playerSprite.collidesWith(landLayer, true)) {
// восстановить исходные положения окна вида и спрайта игрока
layers.setViewWindow(xView, yView, getWidth(),
getHeight() – infoBar.getHeight());
playerSprite.move(-xMove, -yMove);
}
else {
// если столкновение не произошло, изменить координаты окна вида
xView += xMove;
yView += yMove;
}Если столкновение произошло, то окно вида возвращается в исходное положение, которое было сохранено в переменных xView, yView. Спрайт игрока также возвращается в исходное положение таким образом, что он остается в центре игрового экрана. Если столкновения нет, то окно вида перемещается в новое положение, определяемое переменными xView и yView. Обновление спрайтов игры High Seas – это та часть кода, в которой выполняется большее число действий. Вот как это делается:
for (int i = 0; i < 2; i++) {
// обновить спрайты пиратов, бочек и мин
pirateSprite[i].update();
barrelSprite[i].update();
// проверить столкновение спрайта корабля и спрайта пирата
if (playerSprite.collidesWith(pirateSprite[i], true)) {
// воспроизвести звук спасения пирата
try {
rescuePlayer.start();
}
catch (MediaException me) {
}
// увеличить число спасенных пиратов
piratesSaved++; //Увеличить счетчик пиратов, потому что был спасен пират
// поместить пирата в новое положение
placeSprite(pirateSprite[i], landLayer); //Использовать спрайт пирата снова, поместив его в новое место
}
// проверить столкновение спрайта корабля со спрайтом бочки
if (playerSprite.collidesWith(barrelSprite[i], true)) {
// воспроизвести звук пополнения энергии
try {
Manager.playTone(ToneControl.C4 + 12, 250, 100);
}
catch (MediaException me) {
}
// увеличить энергию игрока
energy = Math.min(energy + 5, 45); //Увеличить энергию игрока, потому что была подорвана бочка
// поместить бочку в новое положение
placeSprite(barrelSprite[i], landLayer); //Использовать спрайт бочки снова, поместив его в новое положение
}
}После обновления обоих спрайтов этот код проверяет столкновение между спрайтом корабля и спрайтом пирата. Если столкновение определено, то воспроизводится звук спасения, означающий, что пират спасен. Число спасенных пиратов, определяемое переменной piratesSaved, увеличивается на 1. Спрайт пирата помещается в новое случайное положение, для чего вызывается метод placeSprite(). Для игрока пират исчез, а в реальности он просто переместился в другое место на карте. Это удобный способ убрать пирата и создать нового простым перемещением спрайта. Наконец, в этом фрагменте кода показано, как применять метод placeSprite(). После того, как было определено столкновение между спрайтами корабля и пирата, проверяется столкновение корабля с бочкой. В этом случае воспроизводится тоновый сигнал, а не wav-файл. Энергия игрока увеличивается, а бочка перемещается в новое место на карте.
...Совет Разработчику
Максимальный объем энергии игрока в игре High Seas равен 45, поэтому код, изменяющий энергию игрока при столкновении с бочкой, восстанавливает уровень энергии до 45. Если бы не было этого ограничения, то индикатор энергии мог бы бесконечно расти, загородив индикатор спасенных пиратов.
Спрайты мины и осьминога обновляются в методе update() так же, как и спрайты бочки и пирата. Но этот код отделен от обновления бочек и пиратов, потому что число мин и осьминогов больше числа бочек и пиратов. Именно поэтому необходим другой цикл for:
for (int i = 0; i < 5; i++) {
// Update the mine and squid sprites
mineSprite[i].update();
squidSprite[i].update();
// проверить столкновение спрайта игрока и спрайта мины
if (playerSprite.collidesWith(mineSprite[i], true)) {
// воспроизвести звук подрыва на мине
try {
minePlayer.start();
}
catch (MediaException me) {
}
// уменьшить энергию игрока
energy -= 10; //Уменьшить энергию игрока, потому что он подорвался на мине
// поместить мину в новое случайное положение
placeSprite(mineSprite[i], landLayer); //Использовать спрайт мины снова, поместив его в новое положение
}
// проверить столкновение спрайта игрока и спрута
if (playerSprite.collidesWith(squidSprite[i], true)) {
// воспроизвести звук столкновения со спрутом
try {
Manager.playTone(ToneControl.C4, 250, 100);
}
catch (MediaException me) {
}
// уменьшить энергию игрока
energy -= 5; //Уменьшить энергию игрока, потому что он попал в щупальца спрута
}
}Сначала выполняется обновление каждого спрайта, затем проверяется столкновение между игроком и миной, в этом случае воспроизводится звуковой эффект, и энергия игрока уменьшается. Мина также перемещается в новое место, аналогично тому, как это делается с пиратом и бочкой.
Столкновение со спрайтом осьминога выполняется почти так же. Вместо звукового файла воспроизводится тон, а энергия игрока также уменьшается. Однако спрайт осьминога не перемещается в новое положение. Это означает, что встреча корабля с осьминогом не заканчивается гибелью или исчезновением бедного морского животного. В этом случае игрок теряет энергию до тех пор, пока он находится в щупальцах монстра. Это делает осьминогов опаснее мин, несмотря на то, что потери энергии меньше.
Энергия корабля служит индикатором продолжения игры. Когда энергия становится меньше 0, игра заканчивается. Ниже приведен код, завершающий игру в случае гибели пиратского судна:if (energy <= 0) {
// остановить музыку
try {
musicPlayer.stop();
}
catch (MediaException me) {
}
// воспроизвести звук тонущего корабля
try {
gameoverPlayer.start();
}
catch (MediaException me) {
}
// спрятать корабль игрока
playerSprite.setVisible(false); //Спрятать корабль игрока, потому что игра окончена
gameOver = true;
}При окончании игры сначала останавливается музыка, затем воспроизводится булькающий звук тонущего корабля. Затем спрайт игрока скрывается, для чего вызывается метод setVisible(). Это означает, что корабль затонул. Наконец, переменной gameOver присваивается значение true, что говорит о том, что игра закончена. Последний фрагмент кода метода update() создает анимацию водного слоя:
if (++waterDelay > 3) {
if (++waterTile[0] > 3)
waterTile[0] = 1;
waterLayer.setAnimatedTile(-1, waterTile[0]);
if (–waterTile[1] < 1)
waterTile[1] = 3;
waterLayer.setAnimatedTile(-2, waterTile[1]);
waterDelay = 0;
}В случае анимации водного слоя каждый из двух анимационных элементов изменяет свой вид. Обратите внимание, что анимация слоя выполняется в противоположных направлениях, для того чтобы элементы слоя не были одинаковыми. Это очень важно, поскольку они используют одинаковый набор изображений.
Вывод игрового экрана
Благодаря менеджеру слоев вывод игрового экрана весьма прост. В листинге 12.3 приведен код метода draw() класса HSCanvas.
Листинг 12.3. Метод draw() класса HSCanvas выводит информационную строку, игровые слои и строку «Game Over» при необходимостиprivate void draw(Graphics g) {
// вывести информационную строку, оставшуюся энергию и число спасенных пиратов
g.drawImage(infoBar, 0, 0, Graphics.TOP | Graphics.LEFT);
g.setColor(0, 0, 0); // черный
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM));
g.drawString("Energy:", 2, 1, Graphics.TOP | Graphics.LEFT);
g.drawString("Pirates saved: " + piratesSaved, 88, 1, Graphics.TOP |
Graphics.LEFT);
g.setColor(32, 32, 255); // синий //Справа от текста Energy вывести оставшуюся энергию как синий прямоугольник
g.fillRect(40, 3, energy, 12);
// вывести слои
layers.paint(g, 0, infoBar.getHeight());
if (gameOver) {
// вывести сообщение об окончании игры и набранные очки
g.setColor(255, 255, 255); // white
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE));
g.drawString("GAME OVER", 90, 40, Graphics.TOP | Graphics.HCENTER);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,
Font.SIZE_MEDIUM)); //Вывести число спасенных пиратов
if (piratesSaved == 0)
g.drawString("You didn't save any pirates.", 90, 70,
Graphics.TOP | Graphics.HCENTER);
else if (piratesSaved == 1)
g.drawString("You saved only 1 pirate.", 90, 70,
Graphics.TOP | Graphics.HCENTER);
else
g.drawString("You saved " + piratesSaved + " pirates.", 90, 70,
Graphics.TOP | Graphics.HCENTER);
}
// вывести графику
flushGraphics();
}Первая часть кода выводит информационную строку – фоновое растровое изображение, индикатор энергии и число спасенных пиратов. Индикатор энергии рисуется с помощью метода fillRect(), а текст выводится методом drawString().
Слои выводятся в середине метода draw(), для этого нужна лишь одна строка кода, за которой следует сообщение об окончании игры. Если игра закончена, то выводится сообщение о конце игры – «GAME OVER», после чего появляется число спасенных пиратов – счет игры.
Начало новой игры
В разъяснениях я несколько раз упоминал о методе newGame(). Пришла пора увидеть, как он работает. Листинг 12.4 содержит код этого метода, начинающего новую игру.
Листинг 12.4. Метод newGame() класса HSCanvas инициализирует переменные игры, изменяет положение пиратского корабля и начинает воспроизведение музыкиprivate void newGame() {
// инициализировать переменные игры
gameOver = false;
energy = 45;
piratesSaved = 0;
// показать спрайт пиратского корабля
playerSprite.setVisible(true); //В начале игры важно вывести на экран корабль игрока
// поместить игрока и переместить окно вида
placeSprite(playerSprite, landLayer); //При запуске игры корабль игрока помещается на карте случайно
xView = playerSprite.getX() – ((getWidth() – playerSprite.getWidth()) / 2);
yView = playerSprite.getY() – ((getHeight() – playerSprite.getHeight()) / 2);
layers.setViewWindow(xView, yView, getWidth(),
getHeight() – infoBar.getHeight());
// начать воспроизведение музыки
try {
musicPlayer.setMediaTime(0);
musicPlayer.start();
}
catch (MediaException me) {
}
}Метод newGame() начинается с инициализации трех основных игровых переменных. Обратите внимание, что значение переменной energy равно максимально возможному значению 45. Затем спрайт игрока становится видимым, для чего вызывается метод setVisible(). Это необходимо потому, что при окончании игры спрайт пиратского корабля исчезает с экрана. Спрайт игрока помещается в случайное место на карте, для чего вызывается метод placeSprite(). В соответствии с этим изменяется положение окна вида таким образом, чтобы спрайт оказался в центре окна. В конце вызовом методов setMediaTime() и start() начинается воспроизведение музыки.
Безопасное размещение спрайтов