Чтение онлайн

ЖАНРЫ

Создание игр для мобильных телефонов
Шрифт:

Переменные client и server представляют клиентскую и серверную сетевые компоненты. Важно понять, что в каждом запущенном образе игры используется лишь одна из указанных переменных. Иначе говоря, если игра работает в режиме сервера, то используется переменная server, в противном случае – client. Переменная isServer отслеживает, работает ли программа в режиме сервера.

Переменная status содержит текст, выводимый в строке состояния, а переменная gameOver говорит, закончена игра или нет. Переменная myMove определяет, может ли игрок совершить ход, или следует ожидать хода соперника. И наконец, переменная curSlot хранит номер текущего выбранного столбца на игровой доске.

Переменные класса C4Canvas впервые появляются в методе start, код которого приведен в листинге 15.5.

Листинг 15.5. Метод start класса C4Canvas начинается с инициализации переменных игры и активации сервиса клиент/сервер

public void start {

// установить вывод на экран

display.setCurrent(this);

// инициализация изображений фишек

try {

piece[0] = Image.createImage("/RedPiece.png");

piece[1] = Image.createImage("/BluePiece.png");

}

catch (IOException e) {

System.err.println("Failed loading images!");

}

//

инициализация спрайта стрелки

try {

// Create the arrow sprite

arrowSprite = new Sprite(Image.createImage("/Arrow.png"), 18, 16);

arrowSprite.setFrame(isServer ? 0 : 1); //Спрайт стрелки имеет два фрейма (синий и красный), каждый из которых используется в определенном режиме работы

}

catch (IOException e) {

System.err.println("Failed loading images!");

}

// инициализация проигрователей

try {

InputStream is = getClass.getResourceAsStream("Legal.wav");

legalPlayer = Manager.createPlayer(is, "audio/X-wav");

legalPlayer.prefetch;

is = getClass.getResourceAsStream("Illegal.wav");

illegalPlayer = Manager.createPlayer(is, "audio/X-wav");

illegalPlayer.prefetch;

is = getClass.getResourceAsStream("Win.wav");

winPlayer = Manager.createPlayer(is, "audio/X-wav");

winPlayer.prefetch;

is = getClass.getResourceAsStream("Lose.wav");

losePlayer = Manager.createPlayer(is, "audio/X-wav");

losePlayer.prefetch;

}

catch (IOException ioe) {

}

catch (MediaException me) {

}

// инициализация переменных игры

gameOver = true;

myMove = !isServer; // клиент всегда ходит первым

curSlot = 0;

gameState = new C4State;

// запуск сетевого сервиса

if (isServer) { //Начиная с этой точки мидлет работает в режиме сервера или клиента

server = new C4Server(this);

server.start;

}

else {

client = new C4Client(this);

client.start;

}

// запуск потока анимации

sleeping = false;

Thread t = new Thread(this);

t.start;

}

В методе start выполняется ряд важных инициализаций, например, изображений фишек и стрелки. Спрайт стрелки состоит из двух фреймов – синей и красной стрелок, цвет стрелки выбирается в соответствие с режимом работы игры (клиент или сервер). Затем выполняется инициализация проигрывателей, после чего инициализируются четыре основные игровые переменные (gameOver, myMove, curSlot и gameState). В зависимости от значения переменной isServer запускается нужный сетевой сервис (клиент или сервер). Значение этой переменной устанавливается при запуске конструктора C4Canvas.

Хотя метод start очень важен для инициализации приложения, метод update, приведенный в листинге 15.6, – это метод, в котором обрабатывается ввод и преобразуется в игровые события, передаваемые по сети.

Листинг 15.6. Метод update класса C4Canvas отвечает на нажатия клавиш и отправляет игровые сообщения

private void update {

// проверить, перезапущена ли игра

if (gameOver) {

int keyState = getKeyStates;

if ((keyState & FIRE_PRESSED) != 0) {

// начать новую игру

newGame;

// отправить сообщение о новой игре оппоненту

if (isServer)

server.sendMessage("NewGame"); //Оповестить другого игрока о начале игры

else

client.sendMessage("NewGame");

}

// игра окончена, обновление не требуется

return;

}

// обработка нажатия клавиш

if (!gameOver && myMove) {

// обработка пользовательского ввода

int keyState = getKeyStates;

if ((keyState & LEFT_PRESSED) != 0) {

if (–curSlot < 0) //Переместить маркер колонки влево

curSlot = 0;

}

else if ((keyState & RIGHT_PRESSED) != 0) {

if (++curSlot > 6) //Переместить маркер колонки вправо

curSlot = 6;

}

else if ((keyState & FIRE_PRESSED) != 0) {

if (makeMove(isServer ? 0 : 1, curSlot)) {

myMove = false; //Ход игрока окончен

// отправить сообщение другому игроку

if (isServer) //Передать информацию о ходе другому устройству

server.sendMessage(Integer.toString(curSlot));

else

client.sendMessage(Integer.toString(curSlot));

}

}

// обновить положение стрелки

arrowSprite.setPosition( //Изменить положение маркера колонки в соответствии с текущей выбранной колонкой

getWidth * (curSlot + 1) / 8 – arrowSprite.getWidth / 2, 21);

}

}

Метод update начинается с проверки завершения игры и, если это так, то начинается новая игра. Обратите внимание, что перезапуск игры выполняется методом newGame, а также отправкой сообщения NewGame другому образу игры. Если новая игра не начата, то проверяются нажатия клавиш Влево, Вправо и Огонь. Обратите внимание, что нажатия клавиш обрабатываются, пока игра запущена.

Стрелки Влево и Вправо изменяют значение переменной curSlot в соответствии с выбранной колонкой игровой доски. Код для обработки нажатия клавиши Огонь намного интереснее, ее нажатие говорит о совершении хода, в результате вызывается метод makeMove. Об этом методе вы узнаете чуть позже. Независимо от нажатия клавиши Огонь в конце метода update выполняется обновление спрайта стрелки в соответствии с изменениями переменной curSlot.

В листинге 15.7 приведен код метода draw, который отвечает за графику мидлета Connect 4.

Листинг 15.7. Метод draw класса C4Canvas отвечает за графику мидлета Connect 4

private void draw(Graphics g) {

// заполнить фон

g.setColor(128, 128, 128); // серый

g.fillRect(0, 0, getWidth, getHeight);

// вывести статусное сообщение

g.setColor(0, 0, 0); // черные

g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM));

g.drawString(status, getWidth / 2, 2, Graphics.TOP | Graphics.HCENTER); //Строка статусных сообщений располагается в верхней части игрового экрана

if (!gameOver && myMove) { //Вывести стрелку, если игра продолжается и ход принадлежит игроку

// вывести стрелку

arrowSprite.paint(g);

}

// вывести фишку

for (int i = 0; i < 7; i++)

for (int j = 0; j < 6; j++)

switch(gameState.board[i][j]) {

case 0:

g.drawImage(piece[0],

(getWidth * (i + 1)) / 8 – (piece[0].getWidth / 2), //Вывести фишки игрока сервера

((getHeight – 33) * (6 – j)) / 7 – (piece[0].getHeight / 2) + 33,

Graphics.TOP | Graphics.LEFT);

break;

case 1:

g.drawImage(piece[1],

(getWidth * (i + 1)) / 8 – (piece[0].getWidth / 2), //Вывести

фишки игрока клиента

((getHeight – 33) * (6 – j)) / 7 – (piece[1].getHeight / 2) + 33,

Graphics.TOP | Graphics.LEFT);

break;

default:

g.setColor(255, 255, 255); // белый //Вывести свободные ячейки

g.fillArc((getWidth * (i + 1)) / 8 – (piece[0].getWidth / 2),

((getHeight – 33) * (6 – j)) / 7 – (piece[0].getHeight / 2) + 33,

piece[0].getWidth, piece[0].getHeight, 0, 360);

break;

}

// вывести графику на экран

flushGraphics;

}

Метод draw начинается с заливки фона игрового экрана. Затем в нижней части экрана появляется игровое статусное сообщение. Если игра запущена и ход принадлежит игроку, то спрайт стрелки выводится под строкой статуса. Оставшаяся часть метода draw выводит фишки и пустые ячейки на игровой доске. Значение 0 на игровой доске соответствует фишке красного цвета – игрока серверного приложения, а значение 1 – фишке синего цвета, принадлежащей игроку клиентского приложения.

Метод newGame вызывается для запуска новой игры, его задача – инициализировать игровые переменные и обновить строку состояния. В листинге 15.8 приведен код этого метода.

Листинг 15.8. Метод newGame класса C4Canvas запускает новую игру Connect 4

public void newGame {

// Initialize the game variables

gameOver = false;

curSlot = 0;

gameState = new C4State;

// Update the status message

status = myMove ? "Your turn." : "Waiting for player\'s move...";

}

Этот код вполне очевидный, переменной gameOver присваивается значение false, переменной curSlot – 0, игровая доска обновляется при создании переменной gameState. Затем обновляется сообщение в строке статуса в соответствии с очередностью хода.

Вы уже несколько раз видели вызов метода receiveMessage (листинг 15.9), который отвечает за получение и обработку сообщений.

Листинг 15.9. Метод receiveMessage класса C4Canvas получает и обрабатывает сообщения, переданные по сети

public void receiveMessage(String message) {

if (gameOver) {

// проверка сообщения о запуске новой игры

if (message.equals("NewGame")) //Если получено сообщение NewGame, то начать новую игру

newGame;

}

else {

if (!myMove) {

// попытка получить сообщение с информацией о ходе

try {

// отобразить ход соперника

int slot = Integer.parseInt(message);

if (slot >= 0 && slot <= 6) { //Проверить, что сообщение содержит допустимое значение колонки (от 0 до 6), а затем выполнить ход

if (makeMove(isServer ? 1 : 0, slot))

myMove = true;

}

}

catch (NumberFormatException nfe) {

}

}

}

}

Этот метод вызывается как клиентом, так и сервером. Он обрабатывает сообщения, отправленные соперником.

Сетевое сообщение всегда содержит один из возможных типов информации – сообщение о начале новой игры, или сообщение о номере столбца, в который соперник поставил фишку. Если получено сообщение NewGame, то запускается новая игра. Если получен номер столбца, в который был сделан ход, то он передается в метод makeMove.

Метод makeMove – это последний интересный метод класса C4 Canvas. В листинге 15.10 приведен его код. Этот метод реализует большую часть логики мидлета Connect 4.

Листинг 15.10. Метод makeMove класса C4Canvas отображает ходы, сделанные в игре

private boolean makeMove(int player, int slot) {

// бросить фишку

if (gameState.dropPiece(player, slot) == -1) { //Попытаться бросить фишку в колонку, в случае неудачи возвратить значение false

// воспроизвести звук неправильного хода

try {

illegalPlayer.start;

}

catch (MediaException me) {

}

return false;

}

// воспроизвести звук корректного хода

try {

legalPlayer.start;

}

catch (MediaException me) {

}

// проверить, закончена ли игра

if (gameState.isWinner(player)) {

if ((isServer && (player == 0)) || (!isServer && (player == 1))) { //Проверить, выиграл ли игрок

// воспроизвести звук победы

try {

winPlayer.start;

}

catch (MediaException me) {

}

status = "You won!";

}

else { //Игрок проиграл

// воспроизвести звук поражения

try {

losePlayer.start;

}

catch (MediaException me) {

}

status = "You lost!";

}

gameOver = true;

}

else if (gameState.isTie) { //Проверить, закончилась ли игра ничьей

// воспроизвести звук ничьей

try {

losePlayer.start;

}

catch (MediaException me) {

}

status = "The game ended in a tie!";

gameOver = true;

}

else {

// обновить сообщение о статусе

status = myMove ? "Waiting for other player..." : "Your turn.";

}

return true;

}

Я знаю, что метод makeMove достаточно запутан, однако он не такой сложный, как это может показаться. Во-первых, важно отметить, что два параметра, принимаемых методом, – это игрок и номер столбца, в который совершается ход. Метод начинается с вызова dropPiece, в который передается переменная gameState. Этот метод пытается поместить фишку в выбранный столбец. Я говорю «пытается», потому что ход может быть невозможным из-за того, что столбец уже полон. В этом случае метод возвращает значение false, которое говорит о том, что ход сделать нельзя.

Если ход возможен, то метод makeMove воспроизводит звуковой файл и проверяет, завершает ли этот ход игру. В вызываемый метод isWinner передается объект, описывающий состояние игры, он проверяет, победил ли игрок, сделавший ход. Если да, то следует проверка, кто победил – игрок или его соперник. Затем обновляется статусное сообщение, а переменной gameOver присваивается значение true.

Игра Connect 4 может закончиться, когда на игровом поле не остается свободной ячейки, а никто из игроков не смог выставить 4 фишки в ряд. Чтобы определить ничью, достаточно вызвать метод isTie класса C4Canvas. Метод makeMove вызывает метод isTie и проверяет, окончилась ли игра ничьей.

Состояние игры Connect 4

Последний фрагмент головоломки с названием Connect 4 – это класс, описывающий детали игры Connect 4, например, положение фишек на игровой доске. Класс C4State моделирует текущее состояние игры Connect 4, он содержит следующие переменные:

Поделиться с друзьями: