Всего за 239 руб. Купить полную версию
![]()
Рис. 6.2. Несколько фреймов спрайта помогают создать иллюзию вращения астероида
Вероятно, сложно представить, что это изображение может помочь имитировать движение, но именно этот эффект достигается при быстрой смене фреймов. Вы можете создать анимационный спрайт, передав конструктору спрайта изображение, а также его размер. Фреймы изображения должны иметь одинаковый размер. Ниже приведен код создания анимационного спрайта, изображение которого показано на рис. 6.2:
roidSprite = new Sprite(Image.createImage("/Roid.png"), 42, 35);
Этот код определяет размер фрейма в изображении – 42х35 пикселей. Фреймы в изображении могут располагаться вертикально, горизонтально или в двух направлениях. Если вы располагаете фреймы по сетке, то нумерация происходит слева направо и сверху вниз (рис. 6.3).

Рис. 6.3. Располагая фреймы изображения в сетке, проход по сетке осуществляется слева направо и сверху вниз
Чтобы создать фреймовую анимацию спрайта, необходимо вызвать методы nextFrame() и prevFrame():
roidSprite.nextFrame();
Этот метод отображает следующий фрейм анимации спрайта. По умолчанию эта последовательность соответствует порядку следования фреймов в изображении, однако вы можете изменить эту последовательность. При достижении конца последовательности воспроизведения фреймов начинается воспроизведение с противоположного конца. В любое время вы можете узнать индекс текущего фрейма, вызвав метод getFrame(). Этот метод возвращает индекс фрейма в последовательности, а не реальный индекс в изображении. Рассмотрим в качестве примера следующую последовательность фреймов:
int [] sequence = {0, 1, 2, 3, 3, 3, 2, 1};
Пятый элемент этой последовательности – это третий фрейм изображения. Если сейчас отображается пятый фрейм анимации, то метод getFrame() возвратит значение 4 (отсчет ведется от 0), а не номер фрейма в изображении. Метод setFrame() позволяет назначить текущий индекс фрейма. Выполнив setFrame(6), вызовите фрейм с номером 6, поскольку 2 – это номер фрейма, который стоит шестым по счету. Помните, что эти номера соответствуют местам фреймов в изображении. Последовательности фреймов можно использовать для имитации взмахов крыльев, взрывов и т. п. С помощью метода setFrameSequence() вы можете изменить последовательность отображения фреймов. Этот метод принимает в качестве параметра целочисленный массив. Ниже приведен пример вызова этой функции для спрайта с птицей:
birdSprite.setFrameSequence(sequence);
Если вы уже близки к пониманию анимации спрайтов, то можно двинуться дальше! Оставшаяся часть главы посвящена совершенствованию мидлета UFO, рассмотренного в предыдущей главе. Вы добавите анимацию спрайта и пользовательский ввод. Ведь лучше один раз увидеть, чем сто раз услышать!
Создание программы UFO 2
Пример программы UFO из предыдущей главы поможет на практике освоить анимацию спрайтов. Теперь вы можете перевести мидлет на новый уровень, добавив управление, а также астероиды – препятствия на пути НЛО. Я буду называть эту программу UFO 2.
Мидлет UFO 2 содержит следующие изменения по отношению к исходной программе:
► пользовательский ввод, обеспечивающий управление летающим объектом;
► анимационные астероиды, летающие по экрану;
► детектирование столкновений летающего объекта с астероидами.
Вы уже достаточно хорошо подготовлены, чтобы сделать это!
Написание программного кода
Класс мидлета в примере UFO 2 не изменился по сравнению с предыдущим приложением, поэтому давайте перейдем непосредственно к изменению класса UFOCanvas. Первое изменение – это добавление трех спрайтов астероидов, которые хранятся в массиве типа Sprite:
private Sprite[] roidSpace = new Sprite[3];
В методе start() выполняется инициализация спрайтов астероида следующим кодом:
Image img = Image.createImage("/Roid.png");
roidSprite[0] = new Sprite(img, 42, 35);
roidSprite[1] = new Sprite(img, 42, 35);
roidSprite[2] = new Sprite(img, 42, 35);
Как вы видите, изображение астероида (Roid.png) создается один раз, а затем передается каждому конструктору спрайта. Также при инициализации изменилось и начальное положение НЛО:
ufoSprite.setPosition((getWidth() – ufoSprite.getWidth()) / 2, (getHeight() – ufoSprite.getHeight()) / 2);
Хотя этот код может показаться странным, но он не делает ничего особенного, просто выводит спрайт в центре экрана, чтобы НЛО сразу не столкнулся с астероидом, который стартует из точки (0,0). В методе update() находятся наиболее интересные новые строки кода. Вся обработка пользовательского ввода сосредоточена в следующем фрагменте кода:
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0)
ufoXSpeed–;
else if ((keyState & RIGHT_PRESSED) != 0)
ufoXSpeed++;
if ((keyState & UP_PRESSED) != 0)
ufoYSpeed–;
else if ((keyState & DOWN_PRESSED) != 0)
ufoYSpeed++;
ufoXSpeed = Math.min(Math.max(ufoXSpeed, -8), 8); //Скорость НЛО устанавливается случайно из диапазона от -8 до 8
ufoYSpeed = Math.min(Math.max(ufoYSpeed, -8), 8);
Этот код просто проверяет нажатия четырех клавиш управления и в соответствии с этим изменяет скорость НЛО. Обратите внимание, что и в этом случае скорость ограничена 8 вне зависимости от того, сколько раз была нажата та или иная клавиша. После того как скорость изменена, НЛО обновляется следующим кодом:
ufoSprite.move(ufoXSpeed, ufoYSpeed); checkBounds(ufoSprite);
Известный метод move() перемещает спрайт, а метод checkBounds() проверяет, не вышел ли НЛО за границы экрана. Проверка не изменилась, но ее код оформлен отдельным методом. Это очень важно, поскольку вам необходимо выполнить аналогичную проверку и для астероидов. Для этого нецелесообразно копировать код, если можно использовать существующий. Обновление спрайтов астероидов производится в цикле, который выполняет несколько функций. Ниже приведено начало цикла:
for (int i = 0; i < 3; i++) {
Первое, что нужно выполнить в цикле, – это переместить астероиды и проверить, не вышли ли они за границы экрана:
roidSprite[i].move(i + 1, 1 – i); checkBounds(roidSprite[i]);
Единственная хитрость в этом коде – перемещения астероидов. Чтобы каждый астероид двигался со своей особой скоростью, для перемещения используется индекс каждого из них. Аналогичный код используется для изменения очередности следования фреймов анимации:
if (i == 1)
roidSprite[i].prevFrame();
else
roidSprite[i].nextFrame();
Идея этого кода заключается в том, что второй астероид вращается в направлении, противоположном остальным. Для этого достаточно пролистывать фреймы спрайта в противоположном направлении относительно других. Оставшаяся часть кода в цикле обновления астероидов проверяет их столкновение с НЛО:
if (ufoSprite.collidesWith(roidSprite[i], true)) {
// воспроизвести предупреждающий звук
AlertType.ERROR.playSound(display);
// вернуть спрайт в исходное положение и обнулить скорости
ufoSprite.setPosition((getWidth() – ufoSprite.getWidth()) / 2, //Спрайт выводится в центре игрового экрана, его скорость равна 0
(getHeight() – ufoSprite.getHeight()) / 2);
ufoXSpeed = ufoYSpeed = 0;
for (int j = 0; j < 3; j++)
roidSprite[j].setPosition(0, 0);
// нет необходимости обновлять спрайты астероидов
break;
}
}
Если столкновение произошло, то воспроизводится стандартный звук возникновения ошибки (он зависит от конкретной модели телефона), для чего используется объект AlertType. В главе 8 вы узнаете, как использовать разнообразные звуки в играх. В этой программе столкновение возвратит НЛО в исходное положение и обнулит его скорость. Если бы вы создавали полноценную игру, то в этом месте вы бы уменьшили число жизней и проверили, не закончена ли игра. Но в этой программе вы просто изменяете положение спрайтов, и анимация продолжается. По сравнению с мидлетом UFO в методе draw() есть только одно незначительное изменение – код, рисующий астероиды:
for (int i = 0; i < 3; i++) roidSprite[i].paint(g);
На этом весь новый код мидлета UFO 2 завершен. В листинге 6.1 приведен полный код нового класса UFOCanvas. Листинг 6.1. Класс UFOCanvas, выполняющий роль холста для мидлета UFO 2
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.util.*;
import java.io.*;
public class UFOCanvas extends GameCanvas implements Runnable {
private Display display;
private boolean sleeping;
private long frameDelay;
private Random rand;
private Sprite ufoSprite;
private int ufoXSpeed, ufoYSpeed;
private Sprite[] roidSprite = new Sprite[3]; //В игре UFO 2 есть 3 спрайта астероида
public UFOCanvas(Display d) {
super(true);
display = d;
// установить частоту кадров (30 fps)
frameDelay = 33;
}
public void start() {
// установить холст как текущий экран
display.setCurrent(this);
// инициализировать генератор случайных чисел
rand = new Random();
// инициализировать спрайты НЛО и астероидов
ufoXSpeed = ufoYSpeed = 0;
try {
ufoSprite = new Sprite(Image.createImage("/Saucer.png"));