Создание игр для мобильных телефонов - Майкл Моррисон
Шрифт:
Интервал:
Закладка:
dc = null;
while (dc == null)
dc = (DatagramConnection)Connector.open("datagram://:5555"); //Номер порта сервера должен совпадать с номером порта клиента
while (true) {
// попытка получения датаграммного пакета
Datagram dg = dc.newDatagram(32); //Размер датаграммы (32 байта) должен быть достаточно большим, чтобы
dc.receive(dg); //вместить наибольшее возможное сообщение, однако в игре Lighthouse сообщения не очень велики
address = dg.getAddress();
// убедиться, что пакет содержит данные
if (dg.getLength() > 0) { //Ответить на сообщение клиента о соединении
String data = new String(dg.getData(), 0, dg.getLength());
if (data.equals("Client")) {
// сообщить пользователю об удачном соединении
canvas.setStatus("Connected to peer client.");
canvas.newGame();
connected = true;
// попытка ответить на принятое сообщение
sendMessage("Server");
}
else { //Сообщение содержит символы азбуки Морзе, поэтому его следует передать холсту
// отправить игровые данные по сети
canvas.receiveMessage(data);
}
}
}
}
catch (IOException ioe) {
System.err.println("The network port is already taken.");
}
catch (Exception e) {
}
}Метод run() начинается с важной строки кода, которая устанавливает статус холста в состояние «Waiting for peer client…» (Ожидание соединения клиента). Метод setStatus() класса C4Canvas устанавливает сообщение, которое выводится в нижней части экрана. Когда вы устанавливаете статус, вы напрямую обмениваетесь информацией с пользователем. В этом случае передаваемая информация – это ожидание подключения клиента. После того как статус холста установлен, метод run() создает датаграммное соединение.
Оставшаяся часть метода run() – это бесконечный цикл, который постоянно пытается получить пакеты датаграммы и ответить на них. Если пакет получен, его адрес сохраняется и выполняется проверка длины. После этого проверяется равенство полученного сообщения значению Client – специальному сообщению, отправляемому клиентом при первом установлении соединения. Если соединение установлено, то статус изменяется и игра начинается. Также сервер отправляет сообщение клиенту, содержащее слово Server, оно означает, что соединение установлено успешно.
Если полученный пакет датаграммы не равен Client, то это, вероятно, фрагмент игровых данных. Игровые данные – это номер столбца, в который соперник поставил фишку. Однако сервер не должен заниматься обработкой этих данных, сервер должен передать эти данные холсту, для чего вызывается метод receiveMessage().
Последний метод класса C4Server осуществляет отправку сообщений клиенту (листинг 15.2).
Листинг 15.2. Метод sendMessage() класса C4Server отправляет строковое сообщение клиенту через датаграммное соединениеpublic void sendMessage(String message) {
// отправить сообщение
try {
// преобразовать строку в массив байтов
byte[] bytes = message.getBytes(); //Строковое сообщение должно быть преобразовано в массив байтов
// отправить сообщение
Datagram dg = null;
dg = dc.newDatagram(bytes, bytes.length, address); //Упаковка данных в датаграмму и отправка клиенту
dc.send(dg);
}
catch (Exception e) {
}
}Метод sendMessage() упаковывает строку в массив байтов и отправляет клиенту как пакет датаграммы. В приведенном коде нет ничего удивительного, он очень похож на код отправки сообщения мидлета Lighthouse из главы 14. Вторая половина сетевого уравнения Connect 4 – класс C4Client, который очень похож на класс C4Server. Ниже приведены переменные этого класса:
private C4Canvas canvas;
private DatagramConnection dc;
private boolean connected;Эти переменные повторяют переменные класса C4 Server за исключением отсутствующей переменной address. Конструктор C4Client() также аналогичен конструктору C4Server():
public C4Client(C4Canvas c) {
canvas = c;
connected = false;
}Этот код идентичен коду конструктора класса сервера за исключением названия. Классы клиента схожи не только этим фрагментом кода, а также кодом методов start() и stop():
public void start() {
Thread t = new Thread(this);
t.start();
}
public void stop() {
}Итак, коды классов сервера и клиента во многом очень похожи, отличаются они лишь методом run(), код которого приведен в листинге 15.3. Листинг 15.3. Метод run() класса C4Client – это сердце клиента игры Connect 4
public void run() {
try {
// соединиться с серверным устройством
canvas.setStatus("Connecting to peer server..."); //Клиент отображает начальное соединение, что говорит о том, что он пытается соединиться с сервером
dc = null;
while (dc == null)
dc = (DatagramConnection)Connector.open("datagram://localhost:5555"); //Номер порта клиента должен совпадать с номером порта сервера
while (true) {
// попробовать отправить датаграммный пакет
if (!connected) //Если соединение не установлено, отправить клиентское сообщение об установлении соединения серверу
sendMessage("Client");
// попробовать получить датаграммный пакет
Datagram dg = dc.newDatagram(32);
dc.receive(dg);
//проверить, что датаграмма содержит данные
if (dg.getLength() > 0) {
String data = new String(dg.getData(), 0, dg.getLength());
if (data.equals("Server")) { //Ответить на сообщение сервера о соединении
// сообщить пользователю об установлении соединения
canvas.setStatus("Connected to peer server.");
canvas.newGame();
connected = true;
}
else {
// отправить игровые данные по сети
canvas.receiveMessage(data); //Сообщение содержит символы азбуки Морзе, поэтому его следует передать холсту
}
}
}
}
catch (ConnectionNotFoundException cnfe) {
System.err.println("The network server is unavailable.");
}
catch (IOException ioe) {
}
}Если подумать, то вы найдете этот код очень знакомым. Метод run() класса клиента структурирован точно так же, как и метод run() сервера, за исключением двух моментов. Во-первых, текст о статусе отличается от текста, выводимого на сервере, потому что клиент пытается установить соединение. Датаграммное соединение по-прежнему создается после определения статуса, но в данном случае URL другой, поскольку это клиентское устройство. Важно отметить, что номера портов на сервере и клиенте должны совпадать.
После того как клиент начал бесконечный цикл, сообщение Client немедленно отправляется серверу – сообщается об установлении соединения. После этого клиент переходит в режим «получения информации», так же, как и сервер. Клиент приступает к обработке входящих сообщений. Этими сообщениями могут быть либо Server (посылка сервера об удачном соединении), либо игровые данные о ходах соперника. Если получено специальное сообщение Server, то клиент изменяет статус холста и начинает новую игру. В противном случае клиент продолжает игру, обрабатывая определенным образом входящие сообщения.
В классе C4Server также метод sendMessage(), который очень похож на одноименный метод класса сервера. Код этого метода приведен в листинге 15.4.
Листинг 15.4. Метод sendMessage() класса C4Client отправляет строковое сообщение серверу датаграммным пакетомpublic void sendMessage(String message) {
// отправить сообщение
try {
// преобразовать строку в массив байтов
byte[] bytes = message.getBytes();
// отправить сообщение
Datagram dg = null; //Упаковка данных в датаграмму и отправка серверу
dg = dc.newDatagram(bytes, bytes.length);
dc.send(dg);
}
catch (Exception e) {
}
}При подробном рассмотрении кода видно, что клиентская версия sendMessage() не использует адреса для отправки датаграммы серверу. Это незначительное, но очень важное изменение. Теперь, когда классы клиента и сервера созданы, самое время перейти к разработке класса игры Connect 4.
Холст игры Connect 4
Холст игры Connect 4 находится в классе C4Canvas, который в значительной степени отвечает за работу игры. Ниже приведены переменные этого класса:
private Display display;
private boolean sleeping;
private long frameDelay;
private Image[] piece = new Image[2];
private Sprite arrowSprite;
private Player legalPlayer;
private Player illegalPlayer;
private Player winPlayer;
private Player losePlayer;
private C4State gameState; //Класс C4State содержит большую часть логики игры Connect 4, включая положения фишек на игровой доске
private C4Client client;
private C4Server server;
private boolean isServer; //Эта переменная показывает, является ли данный экземпляр игры сервером
private String status = "";
private boolean gameOver;
private boolean myMove;
private int curSlot;
Переменная piece хранит изображения фишек, используемых в игре (одну красного цвета и одну синего). Переменная arrowSprite – это спрайт с изображением стрелки, который выводится на игровом поле и указывает на текущую выбранную колонку. Переменные типа Player – это проигрыватели, сопровождающие звуком события, например, ход игрока, невозможный ход, победа или поражение.
...В копилку Игрока
Невозможный ход в игре Connect 4 – это попытка поставить фишку в уже заполненную колонку.
Переменная gameState очень важна, ее назначение следует объяснить подробно. Вы узнаете о ней намного больше в следующей главе, а пока важно понять, что эта переменная отражает состояние игры Connect 4 в любой момент времени, включая положение фишек на доске, счет, таблицу выигрышных комбинаций, которая используется для определения победителя.
Переменные client и server представляют клиентскую и серверную сетевые компоненты. Важно понять, что в каждом запущенном образе игры используется лишь одна из указанных переменных. Иначе говоря, если игра работает в режиме сервера, то используется переменная server, в противном случае – client. Переменная isServer отслеживает, работает ли программа в режиме сервера.
Переменная status содержит текст, выводимый в строке состояния, а переменная gameOver говорит, закончена игра или нет. Переменная myMove определяет, может ли игрок совершить ход, или следует ожидать хода соперника. И наконец, переменная curSlot хранит номер текущего выбранного столбца на игровой доске.