// рисуем уровень с левого верхнего угла дисплея ■
lm.paint(g, 0, 0);
// двойная буферизация
ElushGraphicsO ;
}
} .
Листинг 8.1 состоит из двух классов MainCanvas и MyGameCanvas, находящихся в файлах Main.Canvas.java и MyGameCanvas.java. Анализ листинга начнем с класса MyGameCanvas. В первнх строках кода этого класса объявляются два объекта классов TiledLayer и LayerManager, а так же логическая переменная z.
■ Объект fonPole класса TiledLayer будет отвечать за фоновое изображение. Объект 1т класса LayerManager является менеджером уровней. Логическая переменная z не обходима для прерывания цикла в методе run () и для окончания системного потока, в котором происходит работа всего игрового цикла.
В конструкторе MyGameCanvas происходит инициализация объекта f onPole класса TiledLayer и объект Im класса LayerManager. Инициализированный объект f опРо1еДобавляется менеджером уровней к текущему уровню для
int[]
pole -
1
{
5,
5, 5,
5,
5,
5,
5,
5,
5,
5,
1,
5, 5,
5,
5,
5,
5,
5,
5,
5,
1,
1, 5,
5,
5,
5,
5,
5,
5,
5,
1,
1, 1,
1,
5,
5,-
5,
1,
1,
5,
1,
1, 1,
1,
1,
5,
5,
1,
1,
1,
1,
1, 1,
1,
1,
1,
1,
1,
6,
6,
1,
1, 1,
1,
1,
1,
6,
6,
6,
6,
2,
'4, 4,'
4,
4,
4,
з,
3,
3,
3,
*
2,
2, 2,
4,
4,
4,
з,
з,
з,
з,
2,
2, 2,
4,
4,
4,
з,
з,
з,
з,
};
Все строки и столбцы со стоят из элементов. Отсчет ячеек происходит от единицы и выше. Присвоение номера ячейки исходного изображения одному из элементов и организует разметку игрового поля, которое в последствии будет рисоваться на экране. .Единственное о чем нельзя забывать - это о размере дисплеев реальных телефонов. Если вы имеете десять столбцов и размер каждой ячейки 15 пикселей по ширине, то в итоге ваше игровое поле в ширину будет 10x15 -= 150 пикселей. Не каждый телефон может похвастаться таким разрешением, поэтому при создании игрового поля нужно учитывать эти нюансы. Вслед за разметкой игрового поля в методе Fon () происходит считывание всех элементов с помощью цикла for.
представления на экране телефона. Обратите внимание, объект fonPole ини-.циализируется с помощью метода Fon (>.
Image im = Image.createlmage("/fon.prig") ; fonPole= new TiledLayer(/*столб*/10,/*строки*/10, im,
/*ширина*/15,/*высота*/15);
В этих двух строках происходит загрузка исходного изображения из файла ресурса и создание объекта fonPole с помощью конструктора класса Tiled-Layer.
Вся разметка игрового поля выполнена в виде десяти строк и десяти столбцов. Первые два параметра конструктора класса TiledLayer как раз и отвечают за количество столбцов и строк Третий параметр конструктора - это исходное изображение, выполненное в виде шести ячеек, каждая размером 15x15 пикселей. Два последних параметра конструктора класса TiledLayer определяют ширину и высоту ячейки. При создании объекта класса TiledLayer не обходимо быть внимательным и указывать реальные размеры одной ячейки. Если размер одной ячейки будет, предположим 20x20 пикселей, а вы обозначите как 15x15 пикселей, то в итоге ячейки изображения загружены не будут.
Дальше в методе Fon (> происходит разметка игрового поля выполненного в виде десяти столбцов и десяти строк.
Обработка событий с клавиш телефона (IIIIHBI
for(inti = 0; i
{ * ,
• fonPole.setCell(i % 10, i / 10, pole[i]>;
Присвоение номера ячейки определенному элементу происходит при помо- ' щи метода setCell ( . В этом методе первый параметр —номер столбца, второй - номер строки и последний - номер ячейки изображения. Здесь главное не запутаться, потому что номера столбцов и строк начинаются с нуля из-за того,* что это обычный массив данных, а все массивы, как вы знаете, ведут свой отсчет с нуля, тогда как ячейка исходного изображения начинается с единицы. Сразу возникает вопрос, а почему не произвести отсчет тоже с нуля, чтобы не было путаницы? Дело в том, что отсчет и производится с нуля, но число ноль - это своего рода зарезервированное значение для ячеек изображения. Нулевое значение может использоваться, но оно не загружает ничего, поэтому отсчет ячеек ведется с единицы. С методом Fon ( 1 мы разобрались, перейдем к методу ini t
g.setColor(Oxffffff} ;
g.fillRect (0, 0, getwidth(), getHeight () ) ;
В этих строках кода происходит постоянная перерисовка фона экрана. Эти действия вы производили в главе 7, когда разбирали механизм отсечения.
С помощью метода paint () рисуется уровень. Начало точки вывода уровня задано точкой 0,0, что соответствует началу системы координат.
И последний метод flushGraphics() осуществляет двойную буферизацию, копируя графические элементы из внеэкранного буфера на экран.
В методе run () происходит остановка игрового цикла. Перед тем как цикл создается с помощью оператора while, методом getGraphics() происходит получение графического контекста, что и является одним из достоинств механизма игрового цикла в профиле MIDP 2.0.
В файле MainGame.java создается основной класс мидлета MainGame. В методе startApp () производится создание объекта рассмотренного класса MyGameCanvas, добавляется команда выхода, запускается системный поток и отражается текущий дисплей. В методе destroyApp {) происходит остановка потока методом stop () класса MyGameCanvas.
8.7. Обработка событий с клавиш телефона
В профиле MIDP 2.0 предусмотрена улучшенная обработка событий получаемых с клавиш телефона. Используя метод getKeyState () можно определять состояние клавиш телефона и действовать адекватным образом. В демонстрационном примере к этому разделу мы выведем на экран мячик, созданный при помощи класса MySprite являющимся подклассом класса Sprite. В листинге 8.2 представлен код примера, в котором на экране рисуется синий мяч, а с помощью клавиш телефона Up, Down, Left и Right этот мяч можно передвигать по экрану. Листинг 8.2 состоит из трех классов: MainGame, MyGameCanvas и MySprite,
{
I / обрабатываем исключительную ситуацию try{
/ / инициализируем объект класса MyGameCanvas mr = new MyGameCanvas ( ) ;
// запускаем поток mr.start
// добавляем команду выхода mr.addCommand(exitMidlet) ; mr.setCommandListener(this);
// отражаем текущий дисплей
Display.getDisplayfthis).setCurrent(mr) ;
}catch (java.io.IOExceptionzxz) {} ;
public void pauseApp ( ) {}
public void destroyApp (boolean unconditional)
{
// останавливаем поток if(mr != null) mr.stopO;
}
public void commandAct ion (Command с, Displayable d) {
расположенных в трех разных файлах MainGame Java, MyGameCanvasjava и MySprite Java.
public class MyGameCanvas extends GameCanvas implements Runnable {
// создаем объект класса MySprite private MySprite bol;
// создаем объект класса LayerManager private LayerManager lm; /7 логическая переменная boolean Z;
public MyGameCanvas () throws IOException
{
// обращаемся к конструктору суперкласса Canvas super(true);
// загружаем изображение
Image im = Image.createlmage("/bol.png");
. // инициализируем объект bol bol = new MySprite (im, 23, 23); // выбираем позицию в центре экрана bol.setPosition(getWidth() /2, getHeightO /2) ; // инициализируем менеджер уровней lm = new LayerManager ( > j // добавляем объект bol к уровню lm.append(bol);
}
public void start ( )
z = true,- i
// создаем и запускаем поток Thread t = new Thread (this) ; .1 t. start О ;
}
// останавливаем поток
public void stop(){ z = false; }
public void run С > {
// получаем графический контекст Graphics g = getGraphics ( ) ; while (z) {
/ / обрабатываем события с клавиш телефона inputKey() ;
// рисуем графические элементы init(g);
// останавливаем цикл на 20 миллисекунд try { Thread, sleep (20) ; }
// обращаемся к конструктору суперкласса super(image, fw, fh) ;
>
// метод для клавиши Left public voidmoveLeft ( )
( //
// передвигаем спрайт move(-1,0);
}
// метод для клавиши Right public void moveRight() { ■
// передвигаем спрайт move(1,0);
}
// метод для клавиши Up public void moveUp ( ) {
// передвигаем спрайт move (0 , -1) ; } ■
// метод для клавиши Down public' voidmoveDown ( )
// передвигаем спрайт move(0,1);
В файле MySpritc.java находится класс MySprite, с которого и начнем рассмотрение листинга. Конструктор класса MySprite обращается к конструктору своего суперкласса Sprite.
super(image, fw, fh);
Этот конструктор имеет три параметра — это исходное изображение спрайта, ширина и высота фрейма. Спрайт, как вы помните, может иметь анимационную последовательность, поэтому необходимо точно знать ширину и высоту одного фрейма, при обязательном условии, что все фреймы спрайта должны быть одного размера. В этом примере мы не используем анимационной последовательности, и можно было обойтись и более простым конструктором суперкласса Sprite.
Для передвижения спрайта по экрану телефона созданы методы moveLef t (), moveRight (), moveUp () и moveDown ( ■, в основу которых положены вызовы метода move (1 Метод move () имеет два параметра - это координаты по осям X и Y. Задавая необходимое смешение на 1, 2, 3 и более пикселей по одной из осей, вы будете производить движение объекта по экрану.
Класс MyGameCanvas работает по схеме, использованной в разделе 8.6, с той лишь разницей, что вместо фонового изображения загружается спрайт в виде мячика. В конструкторе класса MyGameCanvas происходит загрузка исходного
„--Д--U„l „л л „--„--™ „„--vw, Г'„--vw,--„_______■->?„■->?
11 *\ ' I ,'| M/T\L 1111 >i I'UJ-I'llf;, • 1 V 1 11 ID 11.1111 14 Л'(11К 11.111 L 111M11 1 . \ 111M11 1 JJiUmCJJUIVL iJAiJ
пикселя. При создании объекта bol класса MySprite
bol = new MySprite(im, 23, 23)
используется изображение bol.png, затем в конструкторе класса MyGameCanvas происходит выбор позиции для первоначальной отрисовки спрайта на экране с помощью метода setPosition(). Мячик рисуется в центре экрана и добавляется методом append () к уровню.
В методе run() в игровом цикле происходит вызов двух методов. Метод ini t () производит рисование всех графических элементов с помощью менеджера уровней, а метод inputKey ) осуществляет обработку нажатий клавиш телефона.
private void inputKeyО {
int keyStates = getKeyStates () ,-
if ((keyStates & LEFTPRESSED) !.= 0) bol .moveLeft () ; if ((keyStates & RIGHTV PRESSED) != 0) bol.moveRight(); if ((keyStates & UP_PRESSED) != 0) bol. moveUp (> ;" if ((keyStates & DOWN_PRESSED) !=0) bol.moveDown();
}
Для перехода к следующей странице статьи перейдите по вы подающему меню