// рисуем уровень с левого верхнего угла дисплея ■
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 < pole.length; 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();
}
Для перехода к следующей странице статьи перейдите по вы подающему меню