Первая часть этого кода идентична коду метода chackBounds мидлета UFO 2. Второй блок – новый, он ограничивает перемещение спрайта. По мере работы с книгой вы обнаружите, что метод checkBounds очень полезен и широко применяется в играх.
Хотя я не хочу приводить большие листинги, стоит посмотреть на класс HCanvas целиком. В листинге 7.1 приведен полный код класса HCanvas.
Листинг 7.1. Класс HCanvas – это специальный холст мидлета Henwayimport javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.util.*;
import java.io.*;
public class HCanvas extends GameCanvas implements Runnable {
private Display display;
private boolean sleeping;
private long frameDelay;
private int inputDelay;
private Random rand;
private Image background;
private Image chickenHead;
private Sprite chickenSprite;
private Sprite[] carSprite = new Sprite[4];
private int[] carYSpeed = new int[4];
private boolean gameOver;
private int numLives;
private int score;
public HCanvas(Display d) {
super(true);
display = d;
// Set the frame rate (30 fps)
frameDelay = 33;
// обнулить задержку ввода
inputDelay = 0;
}
public void start {
// установить холст как текущий экран
display.setCurrent(this);
// инициализировать генератор случайных чисел
rand = new Random;
// инициализация переменных
gameOver = false;
numLives = 3;
score = 0;
// инициализация фонового изображения и спрайтов
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!");
}
// запустить поток анимации
sleeping = false;
Thread t = new Thread(this);
t.start;
}
public void stop {
// остановить анимацию
sleeping = true;
}
public void run {
Graphics g = getGraphics;
// основной игровой цикл
while (!sleeping) {
update;
draw(g);
try {
Thread.sleep(frameDelay);
}
catch (InterruptedException ie) {}
}
}
private void update {
// проверить, перезапущена ли игра
if (gameOver) {
int keyState = getKeyStates;
if ((keyState & FIRE_PRESSED) != 0) {
// Start a new game
chickenSprite.setPosition(2, 77);
gameOver = false;
score = 0;
numLives = 3;
}
// игра окончена, нет необходимости обновления
return;
}
// обработать пользовательский ввод
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);
// обнулить задержку ввода
inputDelay = 0;
}
// проверить, перешел ли цыпленок через шоссе
if (chickenSprite.getX > 154) {
// воспроизвести звук, если цыпленок преодолел шоссе
AlertType.WARNING.playSound(display);
// вернуть спрайт цыпленка в исходное положение и увеличить счет
chickenSprite.setPosition(2, 77);
score += 25;
}
// обновить спрайты автомобилей
for (int i = 0; i < 4; i++) {
// переместить спрайты автомобилей
carSprite[i].move(0, carYSpeed[i]);
checkBounds(carSprite[i], true); //Значение true, передаваемое вторым параметром, говорит о том, что автомобили при достижении границы экрана появятся у противоположного края
// проверить столкновения между спрайтами автомобилей и спрайтом цыпленка
if (chickenSprite.collidesWith(carSprite[i], true)) {
// воспроизвести звук при гибели цыпленка
AlertType.ERROR.playSound(display);
// проверить, не закончена ли игра
if (–numLives == 0) {
gameOver = true;
} else {
// вернуть спрайт цыпленка в исходное положение
chickenSprite.setPosition(2, 77);
}
// нет необходимости обновлять спрайты автомобилей
break;
}
}
}
private void draw(Graphics g) {
// вывести фоновое изображение
g.drawImage(background, 0, 0, Graphics.TOP | Graphics.LEFT);
// вывести число оставшихся жизней
for (int i = 0; i < numLives; i++) //Ряд маленьких изображений цыплят отражает число оставшихся жизней
g.drawImage(chickenHead, 180 – ((i + 1) * 8), 170, Graphics.TOP |
Graphics.LEFT);
// нарисовать спрайт цыпленка
chickenSprite.paint(g);
// нарисовать спрайт автомобиля
for (int i = 0; i < 4; i++)
carSprite[i].paint(g);
if (gameOver) {
// вывести сообщение о конце игры и счет
g.setColor(255, 255, 255); // белый
g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD,
Font.SIZE_LARGE));
g.drawString("GAME OVER", 90, 40, Graphics.TOP | Graphics.HCENTER);
g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD,
Font.SIZE_MEDIUM));
g.drawString("You scored " + score + " points.", 90, 70, Graphics.TOP |
Graphics.HCENTER);
}
// вывести содержимое буфера на экран
flushGraphics;
}
private void checkBounds(Sprite sprite, boolean wrap) {
// переместить/остановить спрайт
if (wrap) {
// переместить спрайт в исходное положение
if (sprite.getX < -sprite.getWidth)
sprite.setPosition(getWidth, sprite.getY);
else if (sprite.getX > getWidth)