Текст книги "Создание игр для мобильных телефонов"
Автор книги: Майкл Моррисон
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 24 (всего у книги 35 страниц)
Чтобы использовать датаграммы для коммуникации через телефонную сеть, необходимо разделить данные на отдельные части – пакеты. Когда мобильные игры передают информацию через датаграммное соединение, они на самом деле отправляют и принимают пакеты. Датаграммные пакеты разработаны так, что они хранят массив байтов, поэтому любые данные в вашем пакете должны быть преобразованы в массив байтов. Когда вы создаете объект типа Datagram, необходимо определить число байтов, помещаемых в пакет. Ниже приведен пример создания объекта Datagram, способного хранить 64 байта информации:
Datagram dg = dc.newDatagram(64);
В этом коде объект Datagram создается вызовом метода newDatagram объекта соединения. Параметр метода newDatagram() – это размер датаграммы в байтах. Такой метод хорошо подходит для приема информации в играх.
Другой подход к созданию датаграммы – это создать и заполнить датаграмму в одной строке. Этот метод хорошо подходит для отправления информации, когда у вас есть данные для отправки. Многие игры для коммуникации используют сообщения, при этом каждая строка должна быть преобразована в байтовый массив перед тем, как будет сохранена в датаграмме:
String message = «GameOver»
byte[] bytes = message.getBytes();
В этом коде строка «GameOver» преобразуется в массив байтов, который сохраняется в переменной bytes. Для создания датаграммы используется другой вариант метода newDatagram():
Datagram dg = dc.newDatagram(bytes, bytes.length);
В этом коде массив байтов игровых данных передается первым параметром в метод newDatagram(), а его длина – вторым параметром. В ряде случаев (пакет пересылается от сервера к клиенту) необходимо использовать совершенно другой вариант метода newDatagram():
Datagram dg = dc.newDatagram(bytes, bytes.length, address);
В этом методе есть третий параметр, который содержит адрес цели – получателя датаграммного пакета. Адрес необходим только в случае, если сервер пересылает данные клиенту, при этом адрес можно получить из датаграммы клиента, для чего используется функция getAddress().
В копилку Игрока
В этой главе вы познакомитесь с еще более сложным методом создания датаграмм для сервера и клиента, когда будете работать над мидлетом Lighthouse.
Интерфейс DatagramConnection предоставляет единственный метод для отправки пакетов датаграммы. Я говорю о методе send(), который очень просто использовать. На самом деле все, что необходимо для отправки пакета, – это лишь одна строка кода:
dc.send(dg);
Посмотрим, как используется этот код в программе. Для этого рассмотрим следующий листинг, в котором сначала создается объект Datagram, а затем пересылается пакет через датаграммное соединение:
// Преобразовать строку в массив байтов
byte[] bytes = message.getBytes();
// Отправить сообщение
Datagram dg = null;
dg = dc.newDatagram(bytes, bytes.length);
dc.send(dg);
Вы уже видели все строки этого кода по отдельности, но здесь они объединены в один фрагмент. Это действительно все, что необходимо, чтобы сформировать пакет игровых данных и отправить через датаграммное соединение с сетью.
Получение пакета датаграммы похоже на отправление пакета, оно выполняется методом интерфейса DatagramConnection. Этот метод называется receive(), в качестве параметра он принимает объект Datagram, точно так же, как send(). Ниже приведен пример использования метода receive() для получения датаграммы:
dc.receive(dg);
Конечно, при этом пакет датаграммы должен быть определенного размера. Ниже приведен код, формирующий и принимающий пакеты датаграммы:
// Попытка получения пакета
Datagram dg = dc.newDatagram(64);
dc.recieve(dg);
// Убедиться, что датаграмма содержит информацию
if (dg.getLength() > 0) {
String data = new String(dg.getData(), 0, dg.getLength());
}
Важно отметить, что в этом коде полученная датаграмма проверяется методом getLength(). Такая проверка важна, поскольку необходимо знать, есть ли данные в датаграмме. Если данные есть, то датаграмма конвертируется в строку и сохраняется в переменной data. Затем эти данные можно обработать специальным кодом.
Создание примера LighthouseЗа много лет до появления мобильных телефонов, радиопередатчиков и приемников мореплаватели использовали более примитивное средство коммуникации. Я говорю о маяках, которые обычно устанавливались на самых высоких частях берега, на их верхушке зажигался свет, направлявший корабли. Несмотря на то что сейчас маяки используют современные средства связи, свет остается источником визуальной коммуникации. Поскольку мобильные телефоны – это современная форма связи, я думаю, что пример с маяком может послужить хорошим примером для создания сетевого мидлета.
Одним из способов коммуникации маяков с экипажами корабля была азбука Морзе – очень удобный способ передачи слов и букв последовательностями «точек» и «тире». Точка – это короткий визуальный или звуковой сигнал, например, вспышка света или металлический звук. Тире по длительности приблизительно равно трем точкам, что соответствует более длительному звуку или вспышке света. Последовательность точек и тире задает отдельные слова. Ниже приведены коды азбуки Морзе.
A – . – J – . – – – S – . . . 1 – . – – – -
B – – . . . K – – . – T – – 2 – . . – – -
C – . – . L – . – . – U – . . – 3 – . . . – -
D – – . . M – – – V – . . . – 4 – . . . . -
E – . N – – . W – . – – 5 – . . . . .
F – . O – – . X – – . . – 6 – – . . . .
G – – – . P – . – – . Y – . – . – 7 – – . . .
H – . . . . Q – – – . – Z – – – . . 8 – – – – . .
I – . . R – . – . 0 – – – – – – 9 – – – – – .
Используя эти коды, вы можете составлять слова и предложения. После каждой буквы следует небольшая пауза, а в конце предложения – более продолжительная. Ниже приведен код слова «hello» в азбуке Морзе:
. . . . . . – . . . – . . – – -
В копилку Игрока
Популярное слово азбуки Морзе – это SOS, что, как большинство ошибочно полагает, означает «Спасите Наши Души» (от англ. Save Our Souls). На самом деле это вовсе не аббревиатура, а простое сочетание букв, но оно служит важным сигналом. Это слово кодируется не по правилам азбуки Морзе – без пауз: . . . – – – . . .
Но вернемся к примеру мидлета Lighthouse. Идея этого приложения состоит в том, чтобы имитировать маяк на мобильном телефоне и использовать азбуку Морзе для коммуникации с другим телефоном с помощью вспышек маяка. Это работает так: на экране каждого телефона изображен маяк, вы смотрите на маяк на телефоне другого человека, а он смотрит на маяк на вашем телефоне. Используя клавиши направлений влево и вправо вы посылаете тире и точки через беспроводную сеть, в результате маяк на телефоне другого человека будет мигать, передавая точки и тире.
Совет Разработчику
Еще более простая версия мидлета Lighthouse могла бы использовать лишь одну клавишу для отправки точек и тире, при этом пользователь должен был бы задерживать клавишу нажатой на определенное время. Это больше походило бы на настоящий телеграф, но пример бы стал менее интересным.
Мидлет Lighthouse – это высокотехничная симуляция устаревшей формы коммуникации. С точки зрения программирования этот пример очень важен, поскольку он демонстрирует, как установить соединение «клиент – сервер» между устройствами, а затем выполнять обмен сообщениями.
Мидлет Lighthouse использует все преимущества отношения «клиент – сервер» между двумя мобильными телефонами. Соединение между мидлетами – датаграммное, это означает, что обмен информацией будет производиться датаграммными пакетами. Поскольку при разработке мидлета Lighthouse используется концепция «клиент – сервер», необходимо знать, какой из телефонов инициирует соединение. Ниже перечислено, что происходит между телефоном-клиентом и телефоном-сервером в мидлете Lighthouse:
1. сервер начинает датаграммное соединение и ждет ответа клиента;
2. телефон-клиент открывает датаграммное соединение с телефоном-сервером;
3. когда соединение установлено, клиент и сервер обмениваются сообщениями;
4. клиент и сервер завершают соединение.
Интерес в разрабатываемом мидлете представляет то, что один из телефонов должен функционировать и как клиент, и как сервер в зависимости от контекста. Чтобы реализовать эту двойную функциональность, пользователь при запуске мидлета может определить, какую роль будет играть его телефон – клиента или сервера. После чего один телефон будет работать либо в режиме клиента, либо в режиме сервера. Зная, что для мидлета Lighthouse есть два режима функционирования, целесообразно разделить сетевой код мидлета на код клиента и код сервера.
В копилку Игрока
С точки зрения программирования сетевых игр пример Lighthouse является не настоящим примером приложения «клиент – сервер», а коммуникатором между двумя устройствами. В настоящих сетевых играх, основанных на концепции «клиент – сервер», есть отдельное серверное приложение, запущенное на сетевом сервере. Мидлеты, подключающиеся к серверу, – клиенты, а сервер управляет игрой. Мидлет Lighthouse является приложением «клиент – сервер» только лишь с той точки зрения, что одно устройство (сервер) ожидает подключения другого устройства (клиента).
Мидлет Lighthouse может работать в двух режимах – режиме клиента и режиме сервера. Режим определяется пользователем через интерфейс при запуске мидлета (вы это увидите чуть позже). Перед тем как вы перейдете к этому, важно разобрать код работы с сетью, который выполняет отправление и прием пакетов через беспроводное соединение.
Клиент и сервер мидлета Lighthouse
Код «клиент – сервер» в мидлете Lighthouse намного легче понять, если начать рассмотрение кода сервера. Все функции сервера содержатся в классе LHServer, который отвечает за ожидание датаграммного подключения клиента. Класс LHServer реализует интерфейс Runnable, что означает, что он запускается в отдельном потоке:
public class LHServer implements Runnable {
Это важно, поскольку класс запускает отдельный поток, отслеживающий соединение, и получает сообщения от клиента. Кроме сетевого соединения с клиентом, сервер также должен обмениваться информацией с холстом мидлета, который отображает маяк.
Переменные класса LHServer говорят о некоторых его функциях:
private LHCanvas canvas;
private DatagramConnection dc;
private String address;
private Boolean connected;
Холст хранится внутри класса LHServer в переменной canvas. Датаграммное соединение хранится в переменной dc – объекте класса DatagramConnection. Переменная address хранит адрес клиента, чтобы пакеты датаграммы могли быть направлены непосредственно получателю. И наконец, переменная connected отслеживает текущее состояние соединения с клиентом.
Конструктор класса LHServer принимает единственный параметр – объект класса LHCanvas, конструктор выполняет ряд инициализаций:
public LHServer(LHCanvas c) {
canvas = c;
connected = false;
}
Метод start() также очень прост, он запускает поток:
public void start() {
Thread t = new Thread(this);
t.start();
}
Метод run() – это метод, в котором реализуются основные функции сервера (листинг 14.1).
Листинг 14.1. Метод run() класса LHServer отвечает на сообщения, принятые от клиента
public void run() {
try {
// соединиться с клиентским устройством
canvas.setStatus("Waiting for peer client..."); //Первое статусное сообщение сервера говорит о том, что он ожидает клиента
dc = null;
while (dc == null)
dc = (DatagramConnection)Connector.open("datagram://:5555"); //Порты клиента и сервера должны быть одинаковыми
while (true) {
// попробовать принять пакет датаграммы
Datagram dg = dc.newDatagram(32); //Размер датаграммы (32 байта) должен быть достаточно большим, чтобы вместить наибольшее возможное сообщение, однако в игре Lighthouse сообщения не очень велики
dc.receive(dg);
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.");
connected = true;
// попробовать ответить на принятое сообщение
sendMessage("Server");
}
else {
// отправить данные
canvas.receiveMessage(data); //Сообщение должно содержать знаки азбуки Морзе, поэтому необходимо его передать холсту
}
}
}
}
catch (IOException ioe) {
System.err.println("The network port is already taken.");
}
catch (Exception e) {
}
}
Метод run() начинается с вызова метода setStatus() класса LHCanvas, который выводит в строку статуса холста «Waiting for peer client…» – режим ожидания клиента. Пользователь будет знать, что сервер ожидает подключения клиента. После того как статус выведен на холст, вызывается метод run(), создающий датаграммное соединение. Номер использования порта (5555) – произвольный, однако важно, что клиент и сервер используют один порт для соединения. Также важно указать, что создаваемое соединение – датаграммное.
После того как датаграммное соединение установлено, метод run() запускает бесконечный цикл, в котором выполняются попытки принятия пакетов от клиента. Сначала создается объект класса Datagram, а затем он используется как хранилище и приемник датаграмм. Адрес датаграммы сохраняется на тот случай, если серверу потребуется отправить ответ.
Если датаграмма содержит данные, то байты датаграммы преобразуются в строку. Затем проверяется, равна ли эта строка «Client», специальному сообщению, обозначающему соединение клиента с сервером. Если соединение прошло успешно, то статус изменяется и клиенту отправляется сообщение «Server», таким образом клиент уведомляется о том, что соединение установлено.
Датаграммный пакет содержит строку «Client» только в том случае, если соединение установлено впервые. Далее будут отправляться и приниматься пакеты, содержащие только слова «Dot» (точка) или «Dash» (тире), в зависимости от того, какое сообщение отправляется клиентом. Сообщение передается в класс LHCanvas, где оно обрабатывается методом receiveMessage(). Подробнее об этом вы узнаете чуть позже, когда познакомитесь с кодом холста мидлета Lighthouse.
Последний метод класса LHServer – это метод sendMessage(), приведенный в листинге 14.2. Этот метод отправляет сообщения клиенту.
Листинг 14.2. Метод sendMessage() класса LHServer отправляет строковое сообщение как пакет датаграммы
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) {
}
}
В этом коде строковое сообщение преобразуется в массив байтов, а затем отправляется клиенту как датаграммный пакет. Обратите внимание, что адрес, сохраненный ранее в методе run(), теперь используется при создании объекта Datagram отправляемого сообщения. Этот адрес необходим, чтобы отправить сообщение клиенту. Однако, как вы увидите позже, этот адрес не обязателен при отправке сообщения клиентом серверу.
Другая часть сетевого кода мидлета Lighthouse – это класс LHClient, который очень похож на класс LHServer. Так же, как и LHServer, класс LHClient также реализует интерфейс Runnable:
public class LHClient implements Runnable {
Ниже приведен список членов класса LHClient.
private LHCanvas canvas;
private DatagramConnection dc;
private boolean connected;
Переменные класса должны быть вам знакомы, поскольку они точно такие же, как и в классе LHServer, за исключением отсутствия переменной address. Ниже приведен код конструктора класса LHClient, который выполняет инициализацию некоторых переменных:
public LHClient(LHCanvas c) {
canvas = c;
connected = false;
}
Метод start() класса LHClient точно такой же, как и аналогичный метод класса LHServer, поэтому давайте перейдем к методу run(). В листинге 14.3 приведен код метода run() класса LHClient.
Листинг 14.3. Метод run() класса LHClient отвечает на сообщения, полученные от сервера
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.");
connected = true;
}
else {
// отправить данные
canvas.receiveMessage(data); //Сообщение содержит символы азбуки Морзе, поэтому его следует передать холсту
}
}
}
}
catch (ConnectionNotFoundException cnfe) {
System.err.println("The network server is unavailable.");
}
catch (IOException ioe) {
}
}
Метод run() класса клиента очень похож на аналогичный метод класса сервера за исключением того, что в классе клиента отсутствует переменная адреса при отправлении датаграммы. Кроме того, URL немного отличается от того, который использовался в классе сервера. И снова важно отметить, что номер порта (5555) должен быть одинаковым для клиента и сервера.
Класс LHClient также реализует метод sendMessage(), который также очень похож на аналогичный метод сервера. В листинге 14.4 приведен код метода sendMessage() клиента.
Листинг 14.4. Метод sendMessage() класса LHClient отправляет строковое сообщение серверу как пакет датаграммы
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() сервера и клиента – это то, что версия класса клиента не использует адреса при отправлении пакета серверу. Это незначительное, но очень важное отличие.
Холст мидлета Lighthouse
Когда классы сервера и клиента созданы, перейдем к созданию холста класса Lighthouse. Класс называется LHCanvas, он выводит на экран информацию о ходе подключения, а также отображает нужную картинку с маяком в соответствии с получаемой информацией.
private Display display;
private boolean sleeping;
private long frameDelay;
private Image[] background = new Image[2]; //Эта переменная говорит о том, является данное приложение образом сервера или клиента
private LHClient client;
private LHServer server;
private boolean isServer;
private String status = "";
private int mode; // 0 = none, 1 = dot, 2 = dash
private int morseTimer;
Переменная background содержит два изображения маяка: с включенным и погашенным огнем. Переменные server и client – это объекты сервера и клиента соответственно, они отвечают за работу мидлета с сетью. Переменная isServer очень важна, она определяет сетевой режим работы мидлета. Эта переменная определяет, как работает мидлет – как клиент или как сервер.
Текст статуса хранится в переменной status. временная mode используется для контроля вывода изображений маяка, а также интервалов времени. Помните, что точка в азбуке Морзе по длительности в три раза меньше тире, поэтому в мидлете Lighthouse используется таймер вывода изображения маяка, который задерживает изображение с включенным огнем в соответствии с отображаемым сигналом. За задержку отвечают переменные mode и morseTimer.
Переменные холста широко используются в методе start(), код которого приведен в листинге 14.5.
Листинг 14.5. Метод start() класса LHCanvas запускает сервис Клиент-Сервер
public void start() {
// установить экран как холст
display.setCurrent(this);
// инициализация фонового изображения
try {
background[0] = Image.createImage("/LighthouseOff.png");
background[1] = Image.createImage("/LighthouseOn.png");
}
catch (IOException e) {
System.err.println("Failed loading images!");
}
// инициализация режима и таймера
mode = 0;
morseTimer = 0;
// запуск сетевого сервиса
if (isServer) { //Начиная с этой точки, мидлет работает в режиме сервера или клиента
server = new LHServer(this);
server.start();
}
else {
client = new LHClient(this);
client.start();
}
// начало потока анимации
sleeping = false;
Thread t = new Thread(this);
t.start();
}
После того как фоновые изображения инициализированы, метод start() инициализирует таймер и режим. Переменная mode инициализируется 0, что соответствует погашенному огню маяка (нет сообщения), в то время как переменная morseTimer обнуляется, несмотря на то что она не используется в отсутствие сообщения.
Наиболее важная часть кода метода start() реализует режим сервера или клиента. В зависимости от значения переменной isServer создается экземпляр класса LHServer или LHClient. После этого создается сетевой объект, вызывается метод старт, запускающий поток соединения.
Метод start() инициализирует мидлет Lighthouse, а метод update() обрабатывает пользовательский ввод и позволяет вам отправлять сообщения, закодированные азбукой Морзе. В листинге 14.6 приведен код метода update().
Листинг 14.6. Метод update() класса LHCanvas отправляет сообщения, закодированные азбукой Морзе, в соответствии с нажатыми клавишами
private void update() {
// обработка пользовательского ввода
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
if (isServer) //Передать точку на другой телефон
server.sendMessage("Dot");
else
client.sendMessage("Dot");
status = "Dot";
}
else if ((keyState & RIGHT_PRESSED) != 0) {
if (isServer) //Передать тире на другой телефон
server.sendMessage("Dash");
else
client.sendMessage("Dash");
status = "Dash";
}
// обновить таймер кода Морзе
if (mode != 0) {
morseTimer++;
// тайм-аут точки
if (mode == 1 && morseTimer > 3)
mode = 0;
// тайм-аут тире
else if (mode == 2 && morseTimer > 9)
mode = 0;
}
}
Метод update() проверяет нажатие клавиш и в соответствии с нажатыми клавишами отправляет нужный знак. Клавиша влево соответствует точке, а клавиша вправо – тире. Чтобы отправить код азбуки Морзе, метод update() просто вызывает метод sendMessage() сетевого объекта (клиента или сервера).
После проверки нажатий клавиш и отправки сообщения, если необходимо, метод update() обновляет таймер Морзе. Если значение переменной mode равно 1, то выводится точка, затем значение таймера увеличивается до 3, после чего выводится изображение маяка с погашенным огнем. Если значение переменной mode равно 2, выводится тире, при этом счетчик будет увеличиваться до 9. И наконец, если значение переменной mode равно 0, то следует вывести изображение маяка с погашенным огнем, таймер не изменяется.
Метод draw() выводит изображение маяка на экран (листинг 14.7).
Листинг 14.7. Метод draw() класса LHCanvas выводит на экран нужное изображение маяка
private void draw(Graphics g) {
// вывести фоновое изображение
if (mode == 0) //В зависимости от режима маяк светится или нет
g.drawImage(background[0], 0, 0, Graphics.TOP | Graphics.LEFT);
else
g.drawImage(background[1], 0, 0, Graphics.TOP | Graphics.LEFT);
// вывести сообщение о статусе
g.setColor(255, 255, 255); // white
g.setFont(Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD, Font.SIZE_MEDIUM));
g.drawString(status, getWidth() / 2, 5, Graphics.TOP | Graphics.HCENTER); // В верхней части экрана выводится статусное сообщение
// вывести содержимое буфера на экран
flushGraphics();
}
Метод draw() начинается с проверки значения переменной mode, которая определяет, какое изображение маяка следует вывести. Если значение этой переменной равно 0, то выводится изображение маяка с погашенным огнем, в противном случае выводится изображение маяка с включенным огнем. Остальной код выводит в нижней части экрана сообщение о статусе соединения.
Сообщение о текущем статусе выводится функцией setStatus():
public void setStatus(String s) {
// установить текущий статус
status = s;
}
Последний метод класса LHCanvas – это метод receiveMessage(), принимающий сообщение, закодированное азбукой Морзе, и в соответствии с сообщением настраивает холст. В листинге 14.8 приведен код этого метода:
Листинг 14.8. Метод receiveMessage() класса LHCanvas получает сообщение, отправленное по сети
public void receiveMessage(String message) {
// установить режим
if (message.equals("Dash")) // Изменить режим в соответствие с сообщением
mode = 2;
else if (message.equals("Dot"))
mode = 1;
else
mode = 0;
// обнулить таймер
morseTimer = 0;
// очистить сообщение о статусе
status = ""; // При отображении символов азбуки Морзе нет необходимости выводить статусное сообщение
}
Параметр метода receiveMessage() – это отправленное сообщение. Это сообщение всегда точка (Dot) или тире (Dash). В последнем случае значение переменной mode становится равным 2, в то время как в первом случае – 1. Если по какой-либо причине сообщение не содержит ни один из возможных вариантов, его значение переменной mode становится равным 0. После этого обнуляется таймер, обеспечивающий правильную работу мидлета.
Мидлет Lighthouse
Последний функциональный представляющий интерес фрагмент кода мидлета Lighthouse – это сам класс мидлета, в котором есть код, отличающий его от всех созданных ранее в книге мидлетов. В листинге 14.9 приведен код класса LighthouseMIDlet.
Листинг 14.9. Класс LighthouseMIDlet при загрузке приложения позволяет пользователю выбрать режим работы: клиент или сервер
public class LighthouseMIDlet extends MIDlet implements CommandListener {
private Form initForm; // Объект типа Form используется для реализации интерфейса
private ChoiceGroup choices;
private LHCanvas gameCanvas;
public void startApp() {
// создать стартовую форму
initForm = new Form("Connect 4");
// добавить выбор устройства
String[] peerNames = { "Server", "Client" }; // Создать группу выбора с двумя опциями: Клиент и Сервер
choices = new ChoiceGroup("Please select peer type:", Choice.EXCLUSIVE,
peerNames, null);
initForm.append(choices);
// добавить команды Play и Exit
Command exitCommand = new Command("Exit", Command.EXIT, 0);
initForm.addCommand(exitCommand);
Command playCommand = new Command("Play", Command.OK, 0);
initForm.addCommand(playCommand);
initForm.setCommandListener(this);
// вывести форму на экран
Display.getDisplay(this).setCurrent(initForm);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {
gameCanvas.stop();
}
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
destroyApp(true);
notifyDestroyed();
}
else if (c.getCommandType() == Command.OK) {
// определить тип функционирования приложения
String name = choices.getString(choices.getSelectedIndex()); // Когда выполняется команда Play, отображается холст игры, в который передается тип работы (клиент или сервер)
// создать новый игровой холст
if (gameCanvas == null) {
gameCanvas = new LHCanvas(Display.getDisplay(this), name);
Command exitCommand = new Command("Exit", Command.EXIT, 0);
gameCanvas.addCommand(exitCommand);
gameCanvas.setCommandListener(this);
}
// запустить игровой холст
gameCanvas.start();
}
}
}
Класс LighthouseMIDlet реализует пользовательский интерфейс в дополнение к основному холсту, в результате пользователь может выбрать режим функционирования приложения (клиент или сервер). Класс MIDP, который называется Form, используется для создания этого интерфейса в виде формы. На формах вы можете размещать стандартные элементы управления, например, кнопки и группы выбора. В мидлете Lighthouse используется группа выбора, предлагающая два варианта («Server» или «Client»), которая очень хорошо подходит в данном случае.
Группа выбора создается как объект типа ChoiceGroup, инициализируемый строковым массивом peerNames. Созданная группа применяется к форме и становится ее неотъемлемой частью. Затем к форме добавляются две команды Play (Играть) и Exit (Выход). Команда Exit завершает работу мидлета, а команда Play запускает мидлет, применяя выбранный режим работы. Команда Play связана с константой Command.OK, в результате выполнения команды создается объект класса LHCanvas. Это основной разработанный вами холст.
Важно отметить, что выбранный режим функционирования передается в качестве второго параметра конструктору класса LHCanvas. Именно так холст узнает, в каком режиме он должен функционировать, в соответствии с этим переменной isServer присваивается нужное значение.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.