Страница:
Пакет javax.microedition.midlet включает поддержку класса MIDlet, в то время как пакет javax.microedition.lcdui включает поддержку классам и интерфейсам GUI, которые используются для создания GUI-мидлета, например, класс Display. Импортировав эти два пакета, вы можете объявить класс SkeletonMIDlet, производный от MIDlet:
public class SkeletonMIDlet extends MIDlet implements CommandListener }
Не удивительно, что класс SkeletonMIDlet расширяет MIDlet, но вот реализация интерфейса CommandListener может показаться весьма странной. Этот интерфейс необходим для создания команды Exit, которая позволяет пользователю выходить из мидлета. Если говорить более подробно, то интерфейс CommandListener реализован таким образом, чтобы мидлет мог отвечать на командные события.
Единственная переменная, член класса SkeletonMIDlet, – это объект SCanvas, который представляет главный экран:
private SCanvas canvas;
Класс SCanvas – это особый класс мидлета, производный от класса Canvas. Холст инициализируется в методе startApp():
public void startApp() {
if (canvas == null) {
canvas = new SCanvas(Display.getDisplay(this));
Command exitCommand = new Command("Exit", Command.EXIT, 0); //Создаем команду EXIT и добавляем ее в
canvas.addCommand(exitCommand); //класс Canvas. Теперь canvas сможет отвечать на эту команду
canvas.setCommandListener(this);
}
// Start up the canvas
canvas.start();
}
Метод startApp() вызывается при переходе мидлета в состояние Active, первым шагом является создание холста. Объект Display мидлета создается и передается при создании холста. Команда Exit создается путем передачи конструктору трех параметров: названия команды, ее типа и приоритета. Имя команды определяется пользователем и появляется как экранная кнопка на дисплее устройства в зависимости от приоритета и количества доступных кнопок. Тип команды должен быть определен одной из трех предопределенных констант – EXIT, OK или CANСEL.
Команда добавлена на холст, поэтому она становится активной. Но все еще необходимо настроить приемник команд для перехвата и обработки командных событий. Для этого вызывается метод setCommandListener(), которому передается параметр this, в результате класс мидлета (SkeletonMIDlet) становится приемником команд. Это замечательно, потому как ранее вы указали для имплементации класса интерфейс CommandListener().
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
destroyApp(true);
notifyDestroyed();
}
}
Методу commandAction() передаются два аргумента – команда и экран, на котором будет сгенерирована команда. В рассматриваемом примере интересна лишь команда. Объект Command сравнивается с константой Command.EXIT, таким образом осуществляется проверка, действительно ли выполняется команда Exit. Если да, то вызывается метод destroyApp() и мидлет разрушается. Аргумент true означает, что разрушение безусловно, то есть мидлет разрушается в любом случае, даже если возникла ошибка. Затем вызывается метод notifyDestriyed(), который сообщает менеджеру приложений о том, что мидлет перешел в состояние Destroyed.
Мидлет Skeleton не работает с методами pauseApp() и destroyApp(), но вы должны реализовать их в любом случае:
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
Хотя вы уже видели все фрагменты кода, полное содержимое файла SkeletonMIDlet.java представлено в листинге 3.1.
import javax.microedition.lcdui.*;
public class SkeletonMIDlet extends MIDlet implements CommandListener {
private SCanvas canvas;
public void startApp() {
if (canvas == null) {
canvas = new SCanvas(Display.getDisplay(this));
Command exitCommand = new Command("Exit", Command.EXIT, 0);
canvas.addCommand(exitCommand);
canvas.setCommandListener(this);
}
// инициализация холста
canvas.start();
}
public void pauseApp() {} //В данном примере эти методы не используются вовсе, однако все равно
public void destroyApp(boolean unconditional) {} //необходимо предоставить пустые реализации, чтобы удовлетворить требованиям класса MIDLET
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
destroyApp(true); //В конце следует вызвать метод destroyApp(), хотя на самом деле
notifyDestroyed(); //работу мидлета завершает метод notifyDestroyed()
}
}
}
Оставшаяся часть кода мидлета Skeleton связана с классом SCanvas и представлена в листинге 3.2.
public class SCanvas extends Canvas {
private Display display;
public SCanvas(Display d) {
super();
display = d;
}
void start() {
display.setCurrent(this); //Это весьма важный код, так как он устанавливает текущий холст для мидлета
repaint();
}
public void paint(Graphics g) {
// очистить холст
g.setColor(0, 0, 0); // черный //Прежде чем начинать
g.fillRect(0, 0, getWidth(), getHeight()); //рисование на холсте,
g.setColor(255, 255, 255); // белый //необходимо очистить фон
// вывести размер экрана
int y = 0;
String screenSize = "Screen size: " + Integer.toString(getWidth()) + " x " + Integer.toString(getHeight());
g.drawString(screenSize, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести число цветов дисплея
y += Font.getDefaultFont().getHeight();
String numColors = "# of colors: " + Integer.toString(display.numColors());
g.drawString(numColors, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести число доступных альфа-уровней
y += Font.getDefaultFont().getHeight();
String numAlphas = "# of alphas: " + Integer.toString(display.numAlphaLevels());
g.drawString(numAlphas, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести полный объем памяти и объем свободной памяти
Runtime runtime = Runtime.getRuntime();
y += Font.getDefaultFont().getHeight();
String totalMem = "Total memory: " + Long.toString(runtime.totalMemory() / 1024) + "KB";
g.drawString(totalMem, 0, y, Graphics.TOP | Graphics.LEFT);
y += Font.getDefaultFont().getHeight();
String freeMem = "Free memory: " + Long.toString(runtime.freeMemory() / 1024) + "KB";
g.drawString(freeMem, 0, y, Graphics.TOP | Graphics.LEFT);
}
}
Класс SCanvas – производный от класса Canvas, его конструктор принимает единственный параметр Display. Конструктор просто определяет переменную display, после чего дисплей мидлета доступен в любом месте кода холста. Метод start() вызывает метод setCurrent() объекта Display и устанавливает холст в качестве экрана. Мидлет может иметь несколько экранов, в этом случае для переключения между ними вы можете использовать метод setCurrent(). Метод start() вызывает метод repaint(), выполняющий перерисовку холста.
Метод начинается с очистки холста и заполнения его черным цветом. Затем изменяется цвет точки на белый и выводится текст. Сначала определяется размер экрана, этот параметр выводится по центру в верхней части экрана. Далее определяется число доступных цветов и альфа-уровней, эта информация тоже выводится на экран. И, наконец, выводится информация об общем количестве памяти и объеме свободной памяти.
Подготовка мидлета для распространения
Сборка и тестирование завершенного приложения
Резюме
Еще немного об играх
Часть II
Глава 4
В этой главе вы узнаете:
► о системах координат MIDP;
► почему цвет так важен для MIDP-графики;
► как применять классы Graphics и Canvas;
► как построить графические мидлеты, отображающие примитивы, текст и картинки.
Основы мобильной графики
Понятие о графической системе координат
Понятие о цветах
public class SkeletonMIDlet extends MIDlet implements CommandListener }
Не удивительно, что класс SkeletonMIDlet расширяет MIDlet, но вот реализация интерфейса CommandListener может показаться весьма странной. Этот интерфейс необходим для создания команды Exit, которая позволяет пользователю выходить из мидлета. Если говорить более подробно, то интерфейс CommandListener реализован таким образом, чтобы мидлет мог отвечать на командные события.
Единственная переменная, член класса SkeletonMIDlet, – это объект SCanvas, который представляет главный экран:
private SCanvas canvas;
Класс SCanvas – это особый класс мидлета, производный от класса Canvas. Холст инициализируется в методе startApp():
public void startApp() {
if (canvas == null) {
canvas = new SCanvas(Display.getDisplay(this));
Command exitCommand = new Command("Exit", Command.EXIT, 0); //Создаем команду EXIT и добавляем ее в
canvas.addCommand(exitCommand); //класс Canvas. Теперь canvas сможет отвечать на эту команду
canvas.setCommandListener(this);
}
// Start up the canvas
canvas.start();
}
Метод startApp() вызывается при переходе мидлета в состояние Active, первым шагом является создание холста. Объект Display мидлета создается и передается при создании холста. Команда Exit создается путем передачи конструктору трех параметров: названия команды, ее типа и приоритета. Имя команды определяется пользователем и появляется как экранная кнопка на дисплее устройства в зависимости от приоритета и количества доступных кнопок. Тип команды должен быть определен одной из трех предопределенных констант – EXIT, OK или CANСEL.
Команда добавлена на холст, поэтому она становится активной. Но все еще необходимо настроить приемник команд для перехвата и обработки командных событий. Для этого вызывается метод setCommandListener(), которому передается параметр this, в результате класс мидлета (SkeletonMIDlet) становится приемником команд. Это замечательно, потому как ранее вы указали для имплементации класса интерфейс CommandListener().
Совет РазработчикуКоманда Exit мидлета Skeleton обрабатывается методом commandAction():
Приоритет команды используется для определения доступности команды пользователю. Это необходимо из-за того, что большинство устройств имеет ограниченный набор клавиш для использования мидлетами. Следовательно, только самые важные команды могут быть связаны с экранными кнопками. Другие команды используются через меню, доступ к которому мидлету получить не так уж и просто. Чем важнее команда, тем меньше номер ее приоритета. Например, значение 1 соответствует команде с наивысшим приоритетом, а в примере Skeleton команде Exit присвоен приоритет 2, что соответствует высокой важности команды. Конечно, значения приоритетов относительны, и поскольку в рассматриваемом примере не используются другие команды, то численное значение приоритета в данном случае не существенно.
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
destroyApp(true);
notifyDestroyed();
}
}
Методу commandAction() передаются два аргумента – команда и экран, на котором будет сгенерирована команда. В рассматриваемом примере интересна лишь команда. Объект Command сравнивается с константой Command.EXIT, таким образом осуществляется проверка, действительно ли выполняется команда Exit. Если да, то вызывается метод destroyApp() и мидлет разрушается. Аргумент true означает, что разрушение безусловно, то есть мидлет разрушается в любом случае, даже если возникла ошибка. Затем вызывается метод notifyDestriyed(), который сообщает менеджеру приложений о том, что мидлет перешел в состояние Destroyed.
Мидлет Skeleton не работает с методами pauseApp() и destroyApp(), но вы должны реализовать их в любом случае:
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
Хотя вы уже видели все фрагменты кода, полное содержимое файла SkeletonMIDlet.java представлено в листинге 3.1.
Листинг 3.1. Код класса SkeletonMIDlet, расположенный в файле SkeletonMIDlet.java
import javax.microedition.midlet.*;import javax.microedition.lcdui.*;
public class SkeletonMIDlet extends MIDlet implements CommandListener {
private SCanvas canvas;
public void startApp() {
if (canvas == null) {
canvas = new SCanvas(Display.getDisplay(this));
Command exitCommand = new Command("Exit", Command.EXIT, 0);
canvas.addCommand(exitCommand);
canvas.setCommandListener(this);
}
// инициализация холста
canvas.start();
}
public void pauseApp() {} //В данном примере эти методы не используются вовсе, однако все равно
public void destroyApp(boolean unconditional) {} //необходимо предоставить пустые реализации, чтобы удовлетворить требованиям класса MIDLET
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
destroyApp(true); //В конце следует вызвать метод destroyApp(), хотя на самом деле
notifyDestroyed(); //работу мидлета завершает метод notifyDestroyed()
}
}
}
Оставшаяся часть кода мидлета Skeleton связана с классом SCanvas и представлена в листинге 3.2.
Листинг 3.2. Класс SCanvas служит как настраиваемый холст мидлета Skeleton
import javax.microedition.lcdui.*;public class SCanvas extends Canvas {
private Display display;
public SCanvas(Display d) {
super();
display = d;
}
void start() {
display.setCurrent(this); //Это весьма важный код, так как он устанавливает текущий холст для мидлета
repaint();
}
public void paint(Graphics g) {
// очистить холст
g.setColor(0, 0, 0); // черный //Прежде чем начинать
g.fillRect(0, 0, getWidth(), getHeight()); //рисование на холсте,
g.setColor(255, 255, 255); // белый //необходимо очистить фон
// вывести размер экрана
int y = 0;
String screenSize = "Screen size: " + Integer.toString(getWidth()) + " x " + Integer.toString(getHeight());
g.drawString(screenSize, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести число цветов дисплея
y += Font.getDefaultFont().getHeight();
String numColors = "# of colors: " + Integer.toString(display.numColors());
g.drawString(numColors, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести число доступных альфа-уровней
y += Font.getDefaultFont().getHeight();
String numAlphas = "# of alphas: " + Integer.toString(display.numAlphaLevels());
g.drawString(numAlphas, 0, y, Graphics.TOP | Graphics.LEFT);
// вывести полный объем памяти и объем свободной памяти
Runtime runtime = Runtime.getRuntime();
y += Font.getDefaultFont().getHeight();
String totalMem = "Total memory: " + Long.toString(runtime.totalMemory() / 1024) + "KB";
g.drawString(totalMem, 0, y, Graphics.TOP | Graphics.LEFT);
y += Font.getDefaultFont().getHeight();
String freeMem = "Free memory: " + Long.toString(runtime.freeMemory() / 1024) + "KB";
g.drawString(freeMem, 0, y, Graphics.TOP | Graphics.LEFT);
}
}
Класс SCanvas – производный от класса Canvas, его конструктор принимает единственный параметр Display. Конструктор просто определяет переменную display, после чего дисплей мидлета доступен в любом месте кода холста. Метод start() вызывает метод setCurrent() объекта Display и устанавливает холст в качестве экрана. Мидлет может иметь несколько экранов, в этом случае для переключения между ними вы можете использовать метод setCurrent(). Метод start() вызывает метод repaint(), выполняющий перерисовку холста.
Совет РазработчикуРисование на холсте – это большая часть кода мидлета Skeleton, выполняется методом paint(). Сейчас не очень важно внедряться во все тонкости этого кода, потому как следующая глава посвящена мобильной графике. Тем не менее я сделаю небольшое описание на тот случай, если вы хотите заглянуть немного вперед.
Несмотря на то что класс SCanvas мидлета Skeleton произведен от класса Canvas, в большинстве примеров, рассматриваемых в книге, этот класс является производным от GameCanvas, который предоставляет специальные возможности, как дважды буферизованная графика и эффективная обработка ввода с клавиатуры. Эти возможности не нужны для создания приложения Skeleton.
Метод начинается с очистки холста и заполнения его черным цветом. Затем изменяется цвет точки на белый и выводится текст. Сначала определяется размер экрана, этот параметр выводится по центру в верхней части экрана. Далее определяется число доступных цветов и альфа-уровней, эта информация тоже выводится на экран. И, наконец, выводится информация об общем количестве памяти и объеме свободной памяти.
В копилку ИгрокаТеперь, когда написание кода завершено, вы почти готовы к сборке и тестированию мидлета Skeleton. Вам осталось только создать пару важных файлов поддержки, необходимых для упаковки мидлета для его распространения.
Число альфа-уровней, поддерживаемых телефоном, определяет возможность управления прозрачными областями изображений. Например, телефоны поддерживают как минимум два альфа-уровня, поэтому пиксель может находиться в двух состояниях: прозрачном и непрозрачном.
Подготовка мидлета для распространения
Подготовка игрового мидлета включает в себя сжатие нескольких файлов, используемых мидлетом, в JAR-файл. Кроме включения предварительно верифицированного файла класса в JAR-архив, вы также должны включить файлы ресурсов, ассоциированных с мидлетом, а также файл манифеста, который описывает содержимое JAR-файла.
В нашем примере единственным ресурсом является пиктограмма, отображаемая рядом с мидлетом на экране устройства. Чуть позже я поясню все, что касается пиктограмм. А пока давайте рассмотрим файл манифеста. Файл манифеста – это специальный текстовый файл, который содержит перечень свойств мидлета и их относительных значений. Эта информация очень важна, поскольку определяет название, пиктограмму и классовое имя каждого мидлета из JAR-файла, а также особые версии CLDC и MIDP, используемыми мидлетом. Помните, что в одном JAR-файле может храниться несколько мидлетов, при этом такой JAR-файл называется пакетом мидлетов.
MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
Первая строка файла манифеста определяет имя мидлета, а также его пиктограмму и имя выполняемого файла класса. Вы, вероятно, заметили, что свойство называется MIDlet-1. Если вы включите дополнительные мидлеты в пакет, то ссылаться на них следует MIDlet-2, MIDlet-3 и т. д. Свойства MIDlet-Name, MIDlet-Description, MIDlet-Vendor и MIDlet-Properties относятся ко всему пакету мидлетов. Однако в нашем случае мидлет Skeleton – единственный мидлет в пакете, поэтому нет ничего плохого в именовании всего пакета Skeleton. Два последних свойства определяют версию используемых мидлетом конфигурации и профиля: CLDC 1.0 и MIDP 2.0.
Ранее я упоминал, что наряду с файлами класса и файлом манифеста в JAR-архив необходимо включить файлы ресурсов. Как минимум мидлет должен иметь пиктограмму. Пиктограмма – изображение размером 12 12 пикселей, сохраненное в формате PNG. В зависимости от экрана телефона это может быть как цветное изображение, так и черно-белое. Я создал маленькое изображение черепа для мидлета Skeleton и сохранил его в файле Skeleton_ion.png.
Одно небольшое замечание касательно пиктограммы мидлета: она должна храниться в папке icons внутри JAR-архива. Подобно ZIP-файлам, вы можете помещать папки с файлами внутрь JAR-архивов. Чтобы поместить такой файл в JAR-архив, вы должны сослаться на этот файл из вложенной папки. Это что-то вроде неофициального соглашения помещать ресурсы мидлета в папку res, расположенную в папке с основным кодом приложения. Зная это, пиктограмму проще всего разметить внутри папки res в папке icon.
Говоря о структуре папок и мидлетах, нужно отметить, что существует стандартный способ организации файлов. На рис. 3.2 показана структура папок, которой необходимо придерживаться, организуя файлы мидлета.
Рис. 3.2. Придерживаясь простых правил организации данных внутри архива мидлета, вы сможете легко организовать все файлы
Папки на рисунке используются для хранения следующих файлов:
► src – файлы кода Java;
► bin – файл манифеста, JAD-файл и JAR-файл;
► classes – компилированные файлы байт-кода Java;
► tmpclasses – компилированные фалы байт-кода Java, прошедшие предварительную верификацию;
► res – файлы всех ресурсов, кроме пиктограмм (изображения, звуки и т. п.);
► res/icons – файлы пиктограмм.
MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0 //Это ваша версия мидлета
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
MIDlet-Jar-Size: 2491 //Если это значение не равно размеру JAR-файла, мидлет не запустится
MIDlet-Jar-URL: Skeleton.jar
За исключением двух последних строк, JAD-файл содержит информацию, с которой вы уже знакомы. Две последние строки определяют размер JAR-файла мидлета (в байтах) и его имя. Очень важно обновлять информацию о размере JAR-файла каждый раз, когда вы заново упаковываете мидлет, поскольку его величина скорее всего изменится при очередной сборке.
В нашем примере единственным ресурсом является пиктограмма, отображаемая рядом с мидлетом на экране устройства. Чуть позже я поясню все, что касается пиктограмм. А пока давайте рассмотрим файл манифеста. Файл манифеста – это специальный текстовый файл, который содержит перечень свойств мидлета и их относительных значений. Эта информация очень важна, поскольку определяет название, пиктограмму и классовое имя каждого мидлета из JAR-файла, а также особые версии CLDC и MIDP, используемыми мидлетом. Помните, что в одном JAR-файле может храниться несколько мидлетов, при этом такой JAR-файл называется пакетом мидлетов.
Совет РазработчикуМанифест пакета мидлетов должен иметь имя Manigfest.mf и размещаться в JAR-архиве вместе с ресурсами и классами мидлета. Ниже приведен код файла манифеста, ассоциированном с мидлетом Skeleton.
Примеры, рассматриваемые в книге, используют MIDP 2.0 и CLDC 1.0. Хотя некоторые мобильные телефоны поддерживают CLDC 2.0, версия CLDC 1.0 в большинстве случаев достаточна для программирования игр. Однако профиль MIDP 2.0 очень важен, поскольку в API было добавлено несколько возможностей, очень полезных для разработки мобильных игр.
MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
Первая строка файла манифеста определяет имя мидлета, а также его пиктограмму и имя выполняемого файла класса. Вы, вероятно, заметили, что свойство называется MIDlet-1. Если вы включите дополнительные мидлеты в пакет, то ссылаться на них следует MIDlet-2, MIDlet-3 и т. д. Свойства MIDlet-Name, MIDlet-Description, MIDlet-Vendor и MIDlet-Properties относятся ко всему пакету мидлетов. Однако в нашем случае мидлет Skeleton – единственный мидлет в пакете, поэтому нет ничего плохого в именовании всего пакета Skeleton. Два последних свойства определяют версию используемых мидлетом конфигурации и профиля: CLDC 1.0 и MIDP 2.0.
Ранее я упоминал, что наряду с файлами класса и файлом манифеста в JAR-архив необходимо включить файлы ресурсов. Как минимум мидлет должен иметь пиктограмму. Пиктограмма – изображение размером 12 12 пикселей, сохраненное в формате PNG. В зависимости от экрана телефона это может быть как цветное изображение, так и черно-белое. Я создал маленькое изображение черепа для мидлета Skeleton и сохранил его в файле Skeleton_ion.png.
Одно небольшое замечание касательно пиктограммы мидлета: она должна храниться в папке icons внутри JAR-архива. Подобно ZIP-файлам, вы можете помещать папки с файлами внутрь JAR-архивов. Чтобы поместить такой файл в JAR-архив, вы должны сослаться на этот файл из вложенной папки. Это что-то вроде неофициального соглашения помещать ресурсы мидлета в папку res, расположенную в папке с основным кодом приложения. Зная это, пиктограмму проще всего разметить внутри папки res в папке icon.
Говоря о структуре папок и мидлетах, нужно отметить, что существует стандартный способ организации файлов. На рис. 3.2 показана структура папок, которой необходимо придерживаться, организуя файлы мидлета.
Рис. 3.2. Придерживаясь простых правил организации данных внутри архива мидлета, вы сможете легко организовать все файлы
Папки на рисунке используются для хранения следующих файлов:
► src – файлы кода Java;
► bin – файл манифеста, JAD-файл и JAR-файл;
► classes – компилированные файлы байт-кода Java;
► tmpclasses – компилированные фалы байт-кода Java, прошедшие предварительную верификацию;
► res – файлы всех ресурсов, кроме пиктограмм (изображения, звуки и т. п.);
► res/icons – файлы пиктограмм.
Совет РазработчикуДля распространения мидлета необходим не только файл манифеста, включаемый в JAR-файл, но и специальный дескриптор. Дескриптор приложения (application descriptor), или файл JAD, содержит информацию, подобную той, что хранится в файле манифеста. JAD-файл используется эмулятором J2ME при тестировании мидлета. Ниже приведено содержание дескриптора мидлета Skeleton:
Примеры мидлетов, включенных в состав J2ME Wireless Toolkit (среди них вы можете найти и игры, которые вы видели в предыдущей главе), построены согласно этому правилу.
MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0 //Это ваша версия мидлета
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
MIDlet-Jar-Size: 2491 //Если это значение не равно размеру JAR-файла, мидлет не запустится
MIDlet-Jar-URL: Skeleton.jar
За исключением двух последних строк, JAD-файл содержит информацию, с которой вы уже знакомы. Две последние строки определяют размер JAR-файла мидлета (в байтах) и его имя. Очень важно обновлять информацию о размере JAR-файла каждый раз, когда вы заново упаковываете мидлет, поскольку его величина скорее всего изменится при очередной сборке.
Сборка и тестирование завершенного приложения
В предыдущей главе вы познакомились с инструментом визуальной среды разработки KToolbar, который позволяет собирать и запускать мидлеты, затрачивая минимум усилий. Чтобы собрать мидлет Skeleton с помощью инструмента KToolbar, вы должны полностью скопировать в папку apps, расположенную в папке установки J2ME Wireless Toolkit. После того как Skeleton скопирован, вы можете открыть это приложение в KToolbar, для чего на инструментальной панели щелкните по кнопке Open Project (Открыть проект).
После того как проект открыт, щелкните по кнопке Build (Собрать), и мидлет Skeleton будет собран. Чтобы запустить приложение в эмуляторе J2ME, щелкните по кнопке Run (Запустить), расположенной на панели инструментов. На рис. 3.3 показан мидлет Skeleton, готовый к запуску в эмуляторе.
Рис. 3.3. Мидлет Skeleton можно запустить с помощью менеджера приложений в эмуляторе J2ME
Поскольку Skeleton – это единственный мидлет в пакете, он уже подсвечен и готов к запуску. Чтобы запустить приложение, на клавиатуре устройства щелкните по кнопке Action (Действие), расположенной между кнопками, или по экранной кнопке Launch (Запустить), или просто нажмите клавишу Enter (Ввод). На рис. 3.4 показан мидлет Skeleton в эмуляторе.
Рис. 3.4. Мидлет Skeleton выводит информацио о ресурсах мобильного телефона: размер экрана, число отображаемых цветов и т. д.
Чтобы выйти из приложения Skeleton, щелкните по экранной кнопке Exit (Выход). Вызовется команда Exit, и мидлет будет разрушен. Чтобы завершить работу мидлета, вы также можете нажать кнопку End (Конец), которая используется в реальных телефонах для прекращения телефонного звонка.
После того как проект открыт, щелкните по кнопке Build (Собрать), и мидлет Skeleton будет собран. Чтобы запустить приложение в эмуляторе J2ME, щелкните по кнопке Run (Запустить), расположенной на панели инструментов. На рис. 3.3 показан мидлет Skeleton, готовый к запуску в эмуляторе.
Рис. 3.3. Мидлет Skeleton можно запустить с помощью менеджера приложений в эмуляторе J2ME
Поскольку Skeleton – это единственный мидлет в пакете, он уже подсвечен и готов к запуску. Чтобы запустить приложение, на клавиатуре устройства щелкните по кнопке Action (Действие), расположенной между кнопками, или по экранной кнопке Launch (Запустить), или просто нажмите клавишу Enter (Ввод). На рис. 3.4 показан мидлет Skeleton в эмуляторе.
Рис. 3.4. Мидлет Skeleton выводит информацио о ресурсах мобильного телефона: размер экрана, число отображаемых цветов и т. д.
Чтобы выйти из приложения Skeleton, щелкните по экранной кнопке Exit (Выход). Вызовется команда Exit, и мидлет будет разрушен. Чтобы завершить работу мидлета, вы также можете нажать кнопку End (Конец), которая используется в реальных телефонах для прекращения телефонного звонка.
Резюме
В этой главе вы, наконец, написали первый Java-код реального мидлета. Хотя мидлет не был игрой, вы создали его по принципу построения игры и подготовили мидлет для распространения. Эта глава познакомила вас с общей структурой мидлета, а также дала представление об устройстве J2ME API. Также вы узнали о жизненном цикле мидлета и методах класса мидлета, управляющих его жизненным циклом.
В этой главе вы познакомились с несколькими классами и интерфейсами, которые уникальны для программирования мобильных приложений. В следующей главе вы сделаете очень важный шаг на пути познания программирования мобильных игр – изучите мобильную графику.
В этой главе вы познакомились с несколькими классами и интерфейсами, которые уникальны для программирования мобильных приложений. В следующей главе вы сделаете очень важный шаг на пути познания программирования мобильных игр – изучите мобильную графику.
Еще немного об играх
Прежде чем завершить эту главу, я хочу описать еще пару шагов, чтобы вы увереннее чувствовали себя, разрабатывая мидлеты. Выполните следующие шаги, чтобы изменить пиктограмму мидлета Skeleton:
1. создайте другую пиктограмму для мидлета Skeleton, убедитесь, что она сохранена в файле формата PNG, ее размер 12 12, и она размещена в папке res/icons;
2. измените манифест и JAD-файлы так, чтобы мидлет мог использовать другой файл с пиктограммой;
3. перестройте мидлет и протестируйте его, используя KToolbar.
Если все сделано верно, то при запуске приложения в эмуляторе, вы увидите новую пиктограмму.
1. создайте другую пиктограмму для мидлета Skeleton, убедитесь, что она сохранена в файле формата PNG, ее размер 12 12, и она размещена в папке res/icons;
2. измените манифест и JAD-файлы так, чтобы мидлет мог использовать другой файл с пиктограммой;
3. перестройте мидлет и протестируйте его, используя KToolbar.
Если все сделано верно, то при запуске приложения в эмуляторе, вы увидите новую пиктограмму.
Часть II
Основы программирования мобильных игр
Глава 4
Мобильная графика 101
Архив АркадКомпьютерная игра состоит из многочисленных кусочков, которые составляют единое целое, и результат их единения должен развлекать игрока. Вероятно, один из самых важных элементов игры – это графика. Она используется для отображения персонажей и существ в игре, а также фоновых миров и прочих объектов, составляющих игровой мир. Конечно, существуют игры с великолепным сюжетом и звуком, но такие игры, скорее, редкость. Кроме того, сегодня игроки ожидают от игры высококачественной графики, а также высококлассных спецэффектов, как в голливудских фильмах. Это касается и мобильных игр, воспроизводимых на миниатюрных экранах мобильных устройств. Поэтому важно понять сущность программирования графики и научиться ее грамотному использованию в играх.
В 1979 году компания Atari совершила первую попытку создания аркады с векторной графикой и выпустила игру Lunar Lander. Хотя эта игра была не столь успешна, как Asteroids, вышедшая вскоре, тем не менее она занимает важное место в истории видеоигр. Lunar Lander была переделана во множестве форматов на различных компьютерных системах. Первую версию игры отличает продуманное управление двигателями, используемыми при посадке аппарата на лунную поверхность.
В этой главе вы узнаете:
► о системах координат MIDP;
► почему цвет так важен для MIDP-графики;
► как применять классы Graphics и Canvas;
► как построить графические мидлеты, отображающие примитивы, текст и картинки.
Основы мобильной графики
За исключением простейших и текстовых игр, даже самые простые игры применяют графику. К счастью, использование графики в мидлетах не представляет и малейшего труда. Прежде чем начать детальное изучение работы графики в J2ME и ее использовании при программировании мобильных телефонов, необходимо усвоить несколько основных правил и понять, как работает компьютерная графика. Если говорить более подробно, то вы должны понять, что такое координатная система, а также как представляется цвет на компьютере. В следующих разделах вы узнаете об этом и подготовитесь применить полученные знания на практике.
Понятие о графической системе координат
Все графические системы используют какие-либо системы координат, чтобы определить расположение точки в окне или на экране. Обычно графические системы координат имеют начало – точку (0,0), а также определяют направления каждой из осей. Если вы далеки от математики, важно просто понять, что система координат определяет способ указания точки на экране с помощью двух координат X и Y. Традиционная математическая система координат, которая знакома многим из нас, показана на рис. 4.1.
Рис. 4.1. Традиционная система координат XY, широко применяемая в математике
Графика MIDP использует похожую систему координат для определения, как и где будут выполняться графические построения. Поскольку подобные построения в мидлете происходят в рамках холста, то система координат связана именно с ним. Начало системы координат MIDP располагается в верхнем левом углу холста, положительное направление оси X – вправо, а оси Y – вниз. Все координаты в MIDP-системе – положительные целые числа. На рис. 4.2 показан вид такой системы координат.
Рис. 4.2. Координатная система MIDP XY похожа на традиционную математическую систему координат за исключением того, что она связана с игровым холстом мидлета
Важно отметить одну интересную деталь, касающуюся координатной системы MIDP. Система представляет расстояние между пикселями, а не сами пиксели. Иначе говоря, верхний левый угол пикселя, расположенного в верхнем левом углу холста, имеет координаты (0,0), а его правый нижний угол – (1,1). Это помогает избежать путаницы при заливке графических примитивов, например, прямоугольников. Координаты прямоугольника являются границами области заливки.
Рис. 4.1. Традиционная система координат XY, широко применяемая в математике
Графика MIDP использует похожую систему координат для определения, как и где будут выполняться графические построения. Поскольку подобные построения в мидлете происходят в рамках холста, то система координат связана именно с ним. Начало системы координат MIDP располагается в верхнем левом углу холста, положительное направление оси X – вправо, а оси Y – вниз. Все координаты в MIDP-системе – положительные целые числа. На рис. 4.2 показан вид такой системы координат.
Рис. 4.2. Координатная система MIDP XY похожа на традиционную математическую систему координат за исключением того, что она связана с игровым холстом мидлета
В копилку ИгрокаЕсли у вас возникли сложности с пониманием графической системы координат MIDP, представьте классическую игру «Морской бой». В этой игре вы стараетесь подбить корабли противника, посылая торпеду в определенную точку игровой сетки. Корабли используют собственные системы координат, позволяющие определять их местоположение на игровом поле. Аналогично, когда вы создаете графику в мидлете, вы указываете положение на холсте, которое представляет не что иное, как маленький квадрат – пиксель.
Область холста, доступная для рисования, не включает строку заголовка и меню мидлета. Размер экрана, возвращаемый приложением Skeleton, рассмотренным в предыдущей главе, устанавливает максимальный размер холста, доступный для рисования. В случае игр вы можете думать о холсте мидлета как об экране игры.
Важно отметить одну интересную деталь, касающуюся координатной системы MIDP. Система представляет расстояние между пикселями, а не сами пиксели. Иначе говоря, верхний левый угол пикселя, расположенного в верхнем левом углу холста, имеет координаты (0,0), а его правый нижний угол – (1,1). Это помогает избежать путаницы при заливке графических примитивов, например, прямоугольников. Координаты прямоугольника являются границами области заливки.
Понятие о цветах
Тема, вероятно, связанная со всеми аспектами графики, это цвет. К счастью, большинство компьютерных игр работает с цветом аналогичным образом. В компьютерных системах основной функцией цвета является точная передача физической природы цвета в условиях ограничений компьютерных средств. Физическую природу несложно понять. Каждый, кто когда-либо экспериментировал с палитрой, может сказать, что разные комбинации цветов дают различные результаты. Подобно палитре, компьютерная система цветов должна обладать возможностью смешивания цветов с целью получения нужных предсказуемых результатов.
Цветные мониторы компьютеров, вероятно, лучше всего дают понять, как компьютерное программное обеспечение реализует работу с цветом. Цветной монитор имеет три электронные пушки: красную, зеленую и синюю. Лучи каждой трубки покрывают все пиксели экрана, заставляя фосфор создавать нужный цвет. Суммарная интенсивность потока каждой трубки определяет результирующий цвет пикселя. Такое смешивание различных лучей из пушек аналогично смешиванию красок на палитре. Хотя работа LCD-экранов мобильных телефонов основана на других физических принципах, идея смешивания цветов по-прежнему заложена в основу.
В таблице 4.1 показаны числовые значения красного, зеленого и синего компонентов некоторых основных цветов. Обратите внимание, что значение каждого из компонентов лежит в диапазоне от 0 до 255.
Стоит отметить, что графический API MIDP не включает знакомый класс Color, являющийся частью стандартного Java Advanced Windowing Toolkit (AWT). Исключение класса Color – это результат стремления сделать MIDP API как можно более компактным. На самом деле класс Color служит лишь организационной структурой для красного, зеленого и синего компонентов цвета. В программировании MIDP-графики вы работаете с этими компонентами как с отдельными целочисленными переменными, а не как с объектом класса Color.
Во многих приложениях для редактирования изображений можно экспериментировать с компонентами RGB и получать новые цвета. Например, чтобы узнать соотношение компонентов цвета, в стандартной программе Paint для Windows в цветовой палитре дважды щелкните по интересующему вас цвету. В диалоговом окне Edit Colors (Редактор цвета) щелкните по кнопке Define Custom Colors (Определить цвет) и в полях Red (Красный), Green (Зеленый) и Blue (Синий) введите числовые значения интенсивности компонентов (рис. 4.3).
Цветные мониторы компьютеров, вероятно, лучше всего дают понять, как компьютерное программное обеспечение реализует работу с цветом. Цветной монитор имеет три электронные пушки: красную, зеленую и синюю. Лучи каждой трубки покрывают все пиксели экрана, заставляя фосфор создавать нужный цвет. Суммарная интенсивность потока каждой трубки определяет результирующий цвет пикселя. Такое смешивание различных лучей из пушек аналогично смешиванию красок на палитре. Хотя работа LCD-экранов мобильных телефонов основана на других физических принципах, идея смешивания цветов по-прежнему заложена в основу.
В копилку ИгрокаЦветовая система Java очень похожа на физическую систему, применяемую цветными мониторами. Так цвета формируются, используя различные интенсивности красного, зеленого и синего цветов. Следовательно, цвета в Java реализуются указанием численной интенсивности трех цветов (красного, зеленого и синего). Такая цветовая система известна как RGB (Red Green Blue) и является стандартом для большинства компьютерных систем.
С технической точки зрения, результат смешивания цветов на мониторе отличается от смешивания цветов на палитре. Дело в том, что на мониторе смешивание цветов обладает свойством аддитивности. Это означает, что при смешивании всех цветов в результате будет получен белый цвет. А смешивание цветов на палитре субстрактивно; это означает, что смешивание всех цветов в результате даст черный цвет. То, каким свойством обладает смешивание цветов (аддитивным или субстрактивным), определяется физическими свойствами средства.
В таблице 4.1 показаны числовые значения красного, зеленого и синего компонентов некоторых основных цветов. Обратите внимание, что значение каждого из компонентов лежит в диапазоне от 0 до 255.
Таблица 4.1. Числовые значения компонентов RGB наиболее часто используемых цветов
Обратите внимание, что интенсивность каждого цветового компонента варьируется в диапазоне от 0 до 255. Это означает, что каждый из цветов занимает 8 бит памяти, а результат смешения трех цветовых компонентов – 24 бита. Поэтому цветовая система MIDP является 24-битной. Конечно, это не имеет отношения к большому числу применяемых черно-белых дисплеев, но имеет огромное значение, когда речь идет о программировании мобильных игр.Стоит отметить, что графический API MIDP не включает знакомый класс Color, являющийся частью стандартного Java Advanced Windowing Toolkit (AWT). Исключение класса Color – это результат стремления сделать MIDP API как можно более компактным. На самом деле класс Color служит лишь организационной структурой для красного, зеленого и синего компонентов цвета. В программировании MIDP-графики вы работаете с этими компонентами как с отдельными целочисленными переменными, а не как с объектом класса Color.
Во многих приложениях для редактирования изображений можно экспериментировать с компонентами RGB и получать новые цвета. Например, чтобы узнать соотношение компонентов цвета, в стандартной программе Paint для Windows в цветовой палитре дважды щелкните по интересующему вас цвету. В диалоговом окне Edit Colors (Редактор цвета) щелкните по кнопке Define Custom Colors (Определить цвет) и в полях Red (Красный), Green (Зеленый) и Blue (Синий) введите числовые значения интенсивности компонентов (рис. 4.3).