Смекни!
smekni.com

Разработка приложений для мобильного устройства (стр. 2 из 2)

callSerially(Runnable r)


Вызов этого метода заставляет ВМ вызывать метод run() объекта r сразу после окончания перерисовки экрана. Вызов осуществляется только один раз.

Объекты класса Canvas могут реагировать на нажатие кнопок при помощи методов:

keyPressed(int key)

keyReleased(int key)

keyRepeated(int key)

Использовать коды кнопок напрямую не рекомендуется. Для получения действия, связанного с тем или иным кодом кнопки, используется метод:

int getGameAction(int key)

Он возвращает код действия (коды определены как константы в классе Canvas на пример FIRE). Есть и обратный ему метод:

int getKeyCode(int gameAction)

Для каждого объекта класса Displayable может быть задан набор команд, определенных пользователем. Каждая команда является объектом класса Command и создается при помощи конструктора:

Command(String command, int type, int priority)


Для добавления и удаления команд в классе Displayable предусмотрены методы:

void addCommand(Command c)

void removeCommand(Command c)

Команды, в зависимости от их типа, могут закрепляться за кнопками под экраном телефона или заноситься в экранное меню (это делается автоматически). При этом над соответствующей кнопкой отображается имя команды.

Для того, чтобы мидлет мог обрабатывать команды, он должен объявлять (implements) интерфейс CommandListener. У этого интерфейса есть единственный метод: void commandAction(Command c, Displayable d), который вызывается после того, как пользователь выберет команду c.

Для того, чтобы объявить в объекте класса Displayable обработчик команд listener, используется метод этого класса:

void addListener(CommandListener listener)

Приложение 1. Примеры создания MIDP приложений

Давайте создадим простейшее MIDP приложение-заготовку для нашей игры, на основе игры «червяк».

package example.wormgame;

import java.lang.Thread;

// подключаем требуемые нам компоненты

import javax.microedition.midlet.MIDlet;

import javax.microedition.midlet.MIDletStateChangeException;

import javax.microedition.lcdui.Form;

import javax.microedition.lcdui.Item;

import javax.microedition.lcdui.Gauge;

import javax.microedition.lcdui.Display;

import javax.microedition.lcdui.Displayable;

import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener;

/**

* Основной класс нашего мидлета

*/

public class WormMain extends MIDlet implements CommandListener {

/** Класс описывающий "червяка" */

private WormPit theGame;

/** Кнопка выхода из игры. */

private Command exitCmd = new Command("Exit", Command.EXIT, 3);

/** Элемент меню, поменять уровень сложности. */

private Command levelCmd = new Command("Change Level", Command.SCREEN, 2);

/** Элемент меню, начать новую игру. */

private Command startCmd = new Command("Start", Command.SCREEN, 1);

/** Элемент меню, перезапустить игру. */

private Command restartCmd = new Command("Restart", Command.SCREEN, 1);

/** Элемент меню, вернутся в игру без извенений. */

private Command cancelCmd = new Command("Cancel", Command.ITEM, 1);

/** Элемент меню, для подтвержждения выбранных установок. */

private Command OKCmd = new Command("OK", Command.OK, 1);

/**

* Конструктор по умолчанию, в котором создаются графические вомпоненты и

* устанавливается command listener.

*/

public WormMain() {

theGame = new WormPit();

theGame.addCommand(exitCmd);

theGame.addCommand(levelCmd);

theGame.addCommand(startCmd);

theGame.addCommand(audioOnCmd);

theGame.setCommandListener(this);

}

/**

* Деструктор для очистки памяти занятой приложением.

*/

protected void destroyApp(boolean unconditional) {

theGame.destroyGame();

Display.getDisplay(this).setCurrent((Displayable)null);

}

/**

* Приостановка работы приложения

*/

protected void pauseApp() {

}

/**

* Запуск приложения

*/

protected void startApp() {

Display.getDisplay(this).setCurrent(theGame);

try {

// Запуск игры в отдельном потоке

Thread myThread = new Thread(theGame); // создаём новый поток

myThread.start(); // запуск потока

} catch (Error e) {

destroyApp(false);

notifyDestroyed();

}

}

/**

* Выполнения функций приложения в ответ на действия пользователя.

*/

public void commandAction(Command c, Displayable d) {

if (c == restartCmd) {

theGame.restart();

} else if (c == levelCmd) {

Item[] levelItem = {

new Gauge("Level", true, 9, theGame.getLevel())};

Form f = new Form("Change Level", levelItem);

f.addCommand(OKCmd);

f.addCommand(cancelCmd);

f.setCommandListener(this);

Display.getDisplay(this).setCurrent(f);

} else if (c == exitCmd) {

destroyApp(false);

notifyDestroyed();

} else if (c == startCmd) {

theGame.removeCommand(startCmd);

theGame.addCommand(restartCmd);

theGame.restart();

} else if (c == OKCmd) {

Form f = (Form)d;

Gauge g = (Gauge)f.get(0);

theGame.setLevel(g.getValue());

Display.getDisplay(this).setCurrent(theGame);

} else if (c == cancelCmd) {

Display.getDisplay(this).setCurrent(theGame);

}

}

Теперь необходимо создать меню и прочие графические компоненты на экране мобильного устройства.

public class WormPit extends Canvas implements Runnable {

/** Очки в игре. */

private int score = 0;

/** Уровень сложности. */

private int level = 5;

/** Ширина экрана в пикселях. */

static int CellWidth;

/** Длина экрана в пикселях. */

static int CellHeight;

/** Высота шрифта для вывода на экран счёта. */

private static final int SCORE_CHAR_HEIGHT;

/** Ширина шрифта для вывода на экран счёта. */

private static final int SCORE_CHAR_WIDTH;

/** Время по умолчанию между перерисовкой червя (400 milliseconds) */

private static final int DEFAULT_WAIT = 400;

/** Цвет шрифта. (0xff0000) */

static final int TEXT_COLOUR = 0x00ff0000;

/** Размер клетки червя. */

public static final int CELL_SIZE = 5;

// Установка размера шрифта

static {

Font defaultFont = Font.getDefaultFont(); // взять шрифт по умолчанию

SCORE_CHAR_WIDTH = defaultFont.charWidth('S');

SCORE_CHAR_HEIGHT = defaultFont.getHeight();

SCORE_HEIGHT = SCORE_CHAR_HEIGHT * 2;

}

/**

* Конструктор. Задания ширины и высоты червя.

*/

public WormPit() {

width = round(getWidth());

height = round(getHeight()-SCORE_HEIGHT);

WormPit.CellWidth = (width-(START_POS*2)) / WormPit.CELL_SIZE;

WormPit.CellHeight = (height-(START_POS*2)) / WormPit.CELL_SIZE;

myWorm = new Worm(this);

/**

* Обработчик событий от нажатия клавишь на мобильном устройстве.

* Стрелки(джойстик) на мобильном устройстве (UP, DOWN, LEFT, RIGHT)

*/

public void keyPressed(int keyCode) {

switch (getGameAction(keyCode)) {

case Canvas.UP:

myWorm.setDirection(Worm.UP);

break;

case Canvas.DOWN:

myWorm.setDirection(Worm.DOWN);

break;

case Canvas.LEFT:

myWorm.setDirection(Worm.LEFT);

break;

case Canvas.RIGHT:

myWorm.setDirection(Worm.RIGHT);

break;

case 0:

// можно использовать клавиши с номерами 2,4,6,8

switch (keyCode) {

case Canvas.KEY_NUM2:

myWorm.setDirection(Worm.UP);

break;

case Canvas.KEY_NUM8:

myWorm.setDirection(Worm.DOWN);

break;

case Canvas.KEY_NUM4:

myWorm.setDirection(Worm.LEFT);

break;

case Canvas.KEY_NUM6:

myWorm.setDirection(Worm.RIGHT);

break;

}

break;

}

}

/**

* Перерисовка экрана и всех объектов.

*/

private void paintPitContents(Graphics g) {

try {

myWorm.update(g); // update worm position

/* логика проверки съел ли червь объект или нет и подсчсёт очков

для вывода на экран */

g.setColor(WormPit.ERASE_COLOUR);

g.fillRect((width - (SCORE_CHAR_WIDTH * 3))-START_POS,

height-START_POS,

(SCORE_CHAR_WIDTH * 3),

SCORE_CHAR_HEIGHT);

g.setColor(WormPit.DRAW_COLOUR);

// Отобразить новый счёт

g.drawString("" + score,

width - (SCORE_CHAR_WIDTH * 3) - START_POS,

height - START_POS, g.TOP|g.LEFT);

} catch (WormException se) {

gameOver = true;

}

}

/**

* Вывод на экран всех компонентов

*/

public void paint(Graphics g) {

if (forceRedraw) {

// Перерисовать весь экран

forceRedraw = false;

// Очистить задний план

g.setColor(WormPit.ERASE_COLOUR);

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

getHeight());

// Нарисовать границы поля

g.setColor(WormPit.DRAW_COLOUR);

g.drawRect(1, 1, (width - START_POS), (height - START_POS));

// Отобразить текущий счёт

g.drawString("L: " + level, START_POS, height, g.TOP|g.LEFT);

g.drawString("" + score,

(width - (SCORE_CHAR_WIDTH * 3)),

height, g.TOP|g.LEFT);

// Отобразить наивысший счёт на этом уровне

g.drawString("H: ",

(width - (SCORE_CHAR_WIDTH * 4)),

(height + SCORE_CHAR_HEIGHT),

g.TOP|g.RIGHT);

g.drawString("" + WormScore.getHighScore(level),

(width - (SCORE_CHAR_WIDTH * 3)),

(height + SCORE_CHAR_HEIGHT),

g.TOP|g.LEFT);

// Нарисовать червя и еду

g.translate(START_POS, START_POS);

g.setClip(0, 0, CellWidth*CELL_SIZE, CellHeight*CELL_SIZE);

myWorm.paint(g);

myFood.paint(g);

} else {

// Нарисовать червя и еду

g.translate(START_POS, START_POS);

}

/**

* Вызывает перерисовку экрана и компонентов при съёме паузы

*/

protected void hideNotify() {

super.hideNotify();

forceRedraw = true;

if (!gameOver) {

gamePaused = true;

}

}

/**

* Основной цикл выполнения MIDP приложения

*/

public void run() {

while (!gameDestroyed) {

try {

synchronized (myWorm) {

/* логика вычислений очков двидения червя и действий пользователя*/

repaint();

}

}

} catch (java.lang.InterruptedException ie) {

}

}

}

/**

* Вызывает событие уничтожения приложения

*/

public void destroyGame() {

synchronized (myWorm) {

gameDestroyed = true;

//myWorm.notifyAll();

myWorm.notifyAll();

}

}

}

Приложение 2. Примеры создания MIDP приложений

Для выполнения задания номер 2 потребуется создать TCP соединение с помощью сокетов и форму вводу передаваемых значений.

Для начала создадим MIDP приложение.

/**

* Основной класс MIDP приложения

*/

public class SocketMIDlet extends MIDlet implements CommandListener {

private final static String SERVER = "Server";

private final static String CLIENT = "Client";

private static String[] names = {SERVER, CLIENT};

private static Display display; // дисплей

private Form f; // форма

private ChoiceGroup cg;

private boolean isPaused;

private Server server;

private Client client;

// левая функциональная кнопка на мобильном устройстве

private Command exitCommand = new Command("Exit", Command.EXIT, 1);

// правая функциональная кнопка на мобильном устройстве

private Command startCommand = new Command("Start", Command.ITEM, 1);

/**

* Конструктор. создаёт графические компоненты на экране.

* И устанавливает обработчики событий.

*/

public SocketMIDlet() {

display = Display.getDisplay(this);

f = new Form("Socket Demo");

cg = new ChoiceGroup("Please select peer",

Choice.EXCLUSIVE, names, null);

f.append(cg);

f.addCommand(exitCommand);

f.addCommand(startCommand);

f.setCommandListener(this);

display.setCurrent(f);

}

public boolean isPaused() {

return isPaused;

}

/**

* Запуск приложения

*/

public void startApp() {

isPaused = false;

}

/**

* Приостановка приложения

*/

public void pauseApp() {

isPaused = true;

}

/**

* Остановка приложения

*/

public void destroyApp(boolean unconditional) {

if (server != null) {

server.stop();

}

if (client != null) {

client.stop();

}

}

/**

* Обработчик событий.

*/

public void commandAction(Command c, Displayable s) {

if (c == exitCommand) {

destroyApp(true);

notifyDestroyed();

} else if (c == startCommand) {

String name = cg.getString(cg.getSelectedIndex());

if (name.equals(SERVER)) {

server = new Server(this);

server.start();

} else {

client = new Client(this);

client.start();

}

}

}

}

Для создания соединения с сервером с помощью сокетов потребуется следующая конструкция:

// Установить сокет соединение на 5000 порту с localhost

SocketConnection sc = (SocketConnection) Connector.open("socket://localhost:5000");

// Входной поток для записи онформации в сокет

InputStream is = sc.openInputStream();

// Выходной поток для чтения информации из сокета

OutputStream os = sc.openOutputStream();

Для открытия соединения для ожидания соединения потребуется следующая конструкция:

// Установить сокет на 5000 порту

ServerSocketConnection scn = (ServerSocketConnection) Connector.open("socket://:5000");

// Ожидать соединения от других машин

SocketConnection sc = (SocketConnection) scn.acceptAndOpen();

Литература.

1. Кен Арнольд, Джеймс Гослинг, Дэвид Холмс. Язык программирования Java™.

2. Официальный сайт Java - http://java.sun.com/ (есть раздел на русском языке с учебником).

3. Java™ 2 SDK, Micro Edition Documentation – http://java.sun.com/products/midp/index.jsp