Перейти к содержанию
Old Phone Forum
  • Вход

    Вы сейчас не залогинены на форуме.

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

Создание своих Java приложений


Рекомендуемые сообщения

Я давно загорелся мыслю, создать свое jаva приложение. Но в этом деле я 0 :(. В нете ничего подходящего не нашел....подскажите, как и что делать:)если такая тема уже есть, то не судите строго:) я не нашел:)

ЕНТО Я!!!

Совесть не отвечает или временно не доступна

ICQ=373775451

Ссылка на комментарий
Поделиться на другие сайты

:) Можешь ссылки дать? :):132:

ЕНТО Я!!!

Совесть не отвечает или временно не доступна

ICQ=373775451

Ссылка на комментарий
Поделиться на другие сайты

Создание аркадных Java Игр для мобильного телефона.

 

 

Введение

 

В этой статье будут рассмотрены все основные аспекты разработки игр на Java. Вы сможете узнать, как правильно проектировать, программировать и настраивать Java-игры, например, для сотовых телефонов. Мы начнем с краткого обзора основных типов игр, а затем продолжим разговор уже о проблемах, возникающих в процессе разработки игровых программ. После этого приступим к работе над двумя примерами игр, которые будем разрабатывать в рамках этой серии, состоящей из двух статей. Начнем с разработки простой автономной игры, а после приступим к куда более сложной задаче — разработке игры с поддержкой возможности игры по сети. Для каждой из этих игр будет подробно описана непосредственно игровая часть (т.е. игровая логика), будут приняты некоторые дизайнерские решения, и в завершение мы погрузимся в детальное рассмотрение всех подробностей реализации этих игр на Java.

Исходный код игр, которые мы будем разрабатывать в этой статье, можно найти и скачать здесь: http:// developer.java.sun.com/developer/releases/wireless_gaming_blueprints

 

Типы игр

 

У многих людей, которые когда-либо играли в игры на мобильных телефонах, обязательно складывается некоторое мнение о типах таких игр. Среди них можно выделить основные:

• Стратегические игры (Mine Sweeper, Reversi, Bejeweled).

• Карточные игры (Solitaire, Black Jack, Poker).

• Двухмерные (2D) аркадные игры (Galaxian, PacMan, Defender, Asteroids).

• Трехмерные (3D) аркадные игры (Doom, Quake, Tony Hawk Pro Skater).

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

 

Основные трудности

 

В список основных трудностей, с которыми сталкиваются разработчики игр для мобильных устройств, входят следующие: аппаратные ресурсы устройств, удовлетворенность пользователя и отладка на этих устройствах.

 

Аппаратные ресурсы

 

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

JAR-файл, содержащий вашу игру, должен быть достаточно мал (хорошим вариантом будет размер в пределах от 10 до 40 килобайт на одну игру), а количество потребляемой памяти во время выполнения игры должно быть ограничено в разумных пределах. Чтобы удовлетворить этим руководящим принципам, следует учитывать количество создаваемых вами объектов и частоту их создания. MIDP Wireless Toolkit 2.0 (WTK) — это эмулятор устройств, который при установке некоторых параметров может предоставить вам полную информацию об используемой памяти. Однако примите во внимание, что MIDP может самостоятельно создавать объекты без вашего на то согласия. Таким образом, не все объекты, которые вы сможете наблюдать при мониторинге памяти, обязательно создаются вашей игрой.

 

Процессоры, используемые в мобильных устройствах, обычно слишком маломощны по сравнению с теми высокопроизводительными гигантами, которые находятся в ваших десктопах или PDA. Частота работы процессоров мобильных устройств может быть даже 15-20 MHz. Кроме того, зачастую мобильные устройства не имеют никаких графических ускорителей. Медленные процессоры и относительно медленная графика должны заставить вас задуматься и всерьез обратить свое внимание, на что ваша программа тратит больше всего времени. Но это не значит, что вы должны полностью отдаваться проблеме предупреждения всякого рода задержек в вашей игре. Вместо этого лучше следовать проверенному временем подходу при написании программ, для которых производительность — основная причина головной боли (это могут быть не только игры): сначала сделайте так, чтоб работало, после сделайте так, чтоб работало правильно, а уже после этого сделайте так, чтоб работало быстро.

Этот подход работает не всегда. Например, если ваша игра — полноценная 3D-аркада с множеством объектных преобразований, поворотов, масштабированием и тысячами полигонов, которые нужно прорисовывать для каждого фрейма, то для того, чтобы заставить это работать быстро на небольших устройствах, потребуется гигантский труд и огромное количество времени (хотя JSR 184 позволяет разрешить некоторые проблемы посредством использования аппаратных возможностей устройств). Что касается 2D-игр, то здесь вы можете не заботиться на начальном этапе о стратегии перерисовки. (Конечно же, если вы уверены, что сможете произвести необходимые действия по оптимизации позже.) Возможные действия по оптимизации не обязательно должны включать полную перерисовку для каждого фрейма. Вкратце проанализируйте проектировку вашей игры и свободно определите для себя, какие улучшения производительности (графические, естественно) вы сможете привнести позже; но ни в коем случае не забивайте себе голову какими-либо конкретными деталями по реализации этих улучшений. Помните, что улучшение производительности кода часто оказывается намного более сложным процессом, чем непосредственное кодирование приложения. Именно по этой причине мы разделяем секции оптимизации для обеих из рассматриваемых нами игр: сначала мы определяем, в какой именно части нашей реализации проявляются явные задержки (низкая производительность) и как выбрать наиболее оптимальный и быстрый вариант решения этой проблемы.

 

Удовлетворенность пользователя

 

Играть в игры должно быть интересно, иначе бы люди просто в них не играли. В случае с калькулятором или текстовым редактором, которые не всегда так уж интересны, мы вынуждены ими пользоваться, поскольку значимость этих приложений намного перевешивает неудобность и непривлекательность их использования. Совсем иначе обстоит дело с играми. Здесь нет видимой выгоды или других причин тратить свое время и нервы на игру, если только она не интересна и не доставляет удовольствия пользователю. Таким образом, целевое назначение любой игры — быть интересной и понравиться пользователю. А в ситуации с сотовыми телефонами существует ряд факторов, которые могут очень негативно повлиять на мнение пользователя о вашей игре.

Во-первых, мы имеем слишком малый экран, на котором достаточно сложно уместить все, что необходимо, и именно так, как задумывалось. Клавиши слишком малы и неудобны в использовании. Это особенно важно в играх, для которых по игровому контексту нажатие клавиши должно быть обработано в пределах одной десятой доли секунды, чтобы игрок смог преуспеть в игре. Звуковые возможности также могут быть чрезвычайно ограничены: звука может не быть вовсе либо он будет, но всего лишь в виде небольшого набора бип-сигналов или же обычного тонального генератора. В любом случае этого недостаточно, чтобы предоставить своей игре хорошее звуковое оформление. Чтобы привлечь пользователей, игра должна иметь достойный внешний вид и удобное управление. Это означает, что различные игровые экраны (сцены в игре) должны выглядеть как часть одной игры. Это можно осуществить за счет использования постоянной гаммы цветов, фоновых изображений и узоров, иконок и прочего. Пользователи не должны видеть сообщений об ошибках во время игры, не считая критических (например: "HTTP 404: not found"). Графическое и звуковое оформление игры в идеале должно создаваться людьми с художественными и эстетическими наклонностями.

 

Отладка

 

Процесс отладки на самих мобильных устройствах очень трудоемкий. Лучше всего воспользоваться эмулятором, например, WTK, где это возможно, поскольку эмуляторы позволяют вам получить доступ к консоли, на которую вы без труда сможете выводить сообщения с помощью метода System.out.println(). Также очень хорош прием перегрузки или определения методов toString() для всех ваших объектов. С их помощью вы сможете получать полную информацию о состоянии любого объекта на конкретный момент времени. Вы также сможете просто закомментировать эту часть кода, чтобы предотвратить попадание ее в релиз игры. При этом вы оставляете за собой возможность отладки до следующих релизов. Можно, конечно, воспользоваться встроенным отладчиком вашей любимой среды разработки (IDE) на Java, но это может повлечь за собой множество проблем. Пока для нас будет вполне удобным метод println().

Другой вариант отладки — демонстрационные режимы в вашей игре. Идеально демо-режим должен вовлекать в демонстрационный процесс игры всю ее функциональность, насколько это возможно. Это позволит вам не только продемонстрировать конечному пользователю, на что способна ваша игра, но и проверить, не рухнет ли приложение при возникновении каких-либо внештатных ситуаций. Это сделает процесс отладки ошибок очень легким. Вместо того, чтобы часами сидеть и нажимать на клавиши, пытаясь проверить все возможные варианты игры, вы просто сидите и смотрите, как игра делает всю самую сложную работу (для выполнения которой она, собственно, и была написана) за вас. Вместе с выводом небольших полезных отладочных сообщений вы получаете очень мощный отладочный инструмент.

 

Автономный вариант игры

 

Описание

В качестве примера автономной игры была выбрана очень распространенная версия аркады типа арканоид. Элементами игры являются блоки разного цвета, доска и шарик. Игрок управляет доской, которую он может передвигать вправо или влево. Шарик летает в пределах игрового поля, в то время как игрок должен придерживаться двух целей, чтобы выиграть. Игровое поле ограничено стенками слева, справа и сверху. Нижняя стенка, по которой передвигается доска, открыта. Чтобы предотвратить падение шарика вниз, игрок должен передвигать доску к тому месту, куда собирается упасть шарик, который, оттолкнувшись от доски, полетит по рассчитываемой траектории. Игра организована в несколько уровней. На каждом из них на игровом поле находится определенное количество блоков. Некоторые из этих блоков сразу распадаются при попадании в них шарика, другие ведут себя более сложно. Игрок должен, воспользовавшись шариком, сбить все сбиваемые блоки на игровом поле, чтобы перейти к следующему уровню. Если шарик падает на нижнюю границу экрана, и игрок не успевает отбить его с помощью доски, то игрок теряет одну жизнь. При старте игрок получает три жизни. Как только пользователь истратил все свои жизни, игра заканчивается, и он проигрывает. Во время игры на экране отображаются индикаторы, показывающие статистическую информацию о текущей игре: количество оставшихся жизней, количество заработанных очков и рекордное количество очков.

Поскольку это сравнительно простая игра, мы не будем сохранять рекордное количество очков постоянно, а только на текущий сеанс работы программы. Игра также содержит экран-заставку, которая отображает название игры и имя ее автора. Помимо этого, есть еще и экран, который выводится при проигрыше. И, наконец, она имеет демонстрационный режим, в котором доска контролируется самой игрой. Это очень полезно как для демонстрационных целей, так и для тестирования и отладки.

 

 

Проектирование

 

Из приведенного выше описания мы можем выделить несколько сущностей, которые будут играть ключевую роль в проектировании игры. Это шарик, доска и блоки. Причем все эти сущности имеют общие свойства: положение, размер, графическое представление, а также обработчик столкновений с другими объектами (сущностями). Все это свойственно спрайтам (sprite). Поскольку в MIDP 1.0 нет поддержки работы со спрайтами (в MIDP 2.0 она уже есть), нам придется делать все самим. Это не страшно, так как необходимая функциональность наших спрайтов сравнительно мала.

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

Чтобы реализовать модель определения столкновений объектов, воспользуемся упрощенческим методом прямоугольников. В этом случае каждый из объектов на игровом поле будет определяться следующими параметрами: координатой X, координатой Y, а также высотой и шириной. Для доски и блоков эти параметры полностью определяют их фактический размер. Однако для шарика такое представление — достаточно грубое приближение его натуральной формы. Чтобы достичь более натурального поведения шарика при таком представлении, нужно немного уменьшить его размеры (например, 75% диаметра шарика в качестве одной стороны его прямоугольника). По определению два объекта считаются столкнувшимися, если их прямоугольники перекрываются, т.е. накладываются друг на друга.

Для того чтобы придать нашей игре более привлекательный вид, мы нарисовали объекты в псевдотрехмерной форме. Каждый объект отбрасывает тень, которая передвигается вместе со своим объектом. Кроме того, объекты подвержены эффекту освещения. Верхние края, откуда предположительно светит источник света, более светлые, тогда как нижние немного затемнены.

 

Теперь на стадии проектирования введем в нашу игру еще три сущности (это очень упростит реализацию игры). Первая сущность будет группировать блоки на всех уровнях. Назовем ее "списком блоков" (brick list). Этот список представляет собой контейнер объектов, но помимо этого он будет выполнять и функции видимости объектов. Например, вместо того, чтобы перерисовывать каждый блок, мы просто даем команду списку перерисовать все блоки данного уровня. Так же и в случае с обработкой столкновений. Чтобы не определять индивидуально, не столкнулся ли шарик с каким-то из блоков, мы возлагаем эту задачу на список, который и осуществит эту проверку за нас. Второй вводимой сущностью будет "экран" (screen). Эта сущность будет координировать любые действия, происходящие на игровом поле (т.е. что нужно рисовать, и в каком порядке). Стратегию перерисовки мы обсудим далее в секциях Реализация и Оптимизация. Наконец, нам нужна сущность, которая связала бы все это вместе — что-то, что могло бы привести в действие нашу игру. По вполне понятным причинам назовем эту сущность движком (engine).

Игра на данный момент спроектирована так, что имеет всего четыре уровня. Однако их количество можно очень легко увеличить в будущем. Для того чтобы сделать функцию по расширению уровней максимально простой, мы выносим представление уровней в виде данных вне исходного кода. Если сделать так, то новые уровни могут быть прочитаны из базы данных устройства или даже загружены из сети без проблем с безопасностью. Это означает также, что уровни может разрабатывать любой желающий, а не только программист. Но для этого, естественно, нужно будет написать немного лишнего кода, который будет осуществлять чтение/загрузку уровней из внешних источников.

Другим объектом, на который нужно обязательно обратить внимание на этапе проектирования, — это размер экрана. Спецификация MIDP не устанавливает какой-то определенный размер экрана и даже не задает возможный минимальный его размер. Здесь все зависит от разработчиков устройств. Именно они устанавливают разрешение для своих устройств. Общее решение данной проблемы — допускать очень малый размер экрана. Таким образом, у большинства устройств размер экрана совпадет либо почти совпадет с выбранным вами. В случае, если разрешения совпадут, игра будет занимать все пространство экрана устройства. Если же разрешение устройства окажется больше, то игра будет центрирована внутри физической области экрана. Наша игра — типичный пример простой игры, когда можно выбрать более искушенный подход для решения этой проблемы. Поскольку размеры всех объектов кодировать не так уж сложно, мы можем вычислять их при старте игры, первоначально определив фактический размер и разрешение экрана устройства. Это значит, что наша игра всегда будет использовать максимум доступного ей экранного пространства.

 

Реализация

 

Как сказал Дональд Кнут: "Предварительная оптимизация — это источник всех зол". Всецело доверяя этому высказыванию, мы начнем с обычной реализации, чтобы не усложнять себе жизнь. Как только игра начнет работать, мы определим части программы, которые необходимо будет оптимизировать. Далее будут приведены довольно интересные элементы кода, иллюстрирующие подробности идей реализации. Эти элементы представлены по принципу "снизу-вверх". Это означает, что части более низкоуровневого кода будут рассматриваться раньше, чем высокоуровневый код.

 

Класс ThreeDColor

 

Этот класс реализует безопасный шаблон перечислений, который был ранее представлен в знаменитой книге "Эффективное программирование на Java" ("Effective Java Programming"). Все цвета, которые можно использовать, представлены в виде экземпляров переменных с модификатором public.

Private-конструктор данного класса предотвращает установку других значений этих переменных. Методы brighter() и darker() используются для выбора подходящего цвета для освещения и затемнения соответственно. Метод getRGB() возвращает целое RGB-значение цвета, который был установлен с помощью метода Graphics.setColor(int).

 

Класс Sprite

 

Этот класс является суперклассом для классов Ball и Brick. Каждый объект класса Sprite имеет координаты X и Y, ширину, высоту, определяющие прямоугольник, а также смещение тени. Смещение тени задает, насколько далеко от объекта будет рисоваться его тень. Оно также показывает, насколько высоко над экраном будет "парить" объект. Прямоугольник, который определяется в этом классе, как мы уже говорили выше, используется для "отлова" столкновений объектов. Он создается в конструкторе, в котором также определяется значение смещения тени согласно фактическому размеру экрана. Данный класс также определяет абстрактные методы для рисования объектов и теней у спрайтов. Реализация этих методов предполагается уже в классах Ball и Brick.

Код класса Sprite: http://java.sun.com/blueprints/code/bricks...bricks/Sprite.j ava.html.

 

Класс Ball

 

Этот класс занимается движением и прорисовкой шарика. Радиус шарика (или его размер) определяется на основе текущих размеров экрана.

Каждый экземпляр шарика имеет ряд переменных, которые задают его скорость (dx, dy), случайные скоростные помехи (xo, yo), а также его цветовую схему (цвет, яркость и затемнение). Конструктор создает экземпляры переменных класса Sprite width (ширина) и height (высота) на основе значения радиуса шарика и, помимо этого, устанавливает цвет.

Этот класс содержит четкие инструкции по поводу того, как нужно прорисовывать шарик. Метод move() устанавливает новое положение шарика на игровом поле с учетом текущей скорости и помех. bounceHorizon-tal() и bounceVertical() подбирают и вычисляют подходящий коэффициент скорости после столкновения шарика с другим объектом или стенкой. Чтобы предотвратить тупиковую ситуацию, когда шарику некуда больше двигаться либо когда он начинает циклично двигаться по одной и той же траектории (замкнутому пути), методы bounce Horizontal() и bounceVertical() каждый раз в цикле привносят немного помех при вычислении пути. Это позволяет избежать зацикливания игры. Методы paint() и paintShadow() используются для прорисовки шарика.

Код класса Ball: http://java.sun.com/blueprints/code/bricks...ks/Ball.java.ht ml.

 

Класс Brick

 

Класс Brick определяет ряд основных атрибутов блоков: width (ширина), height (высота), step (шаг), gap (разрыв). Атрибуты width и height представляют собой ширину и высоту блоков по умолчанию, step — это количество движений блока при анимации, а gap — это расстояние до смежных с ним блоков. Все эти значения тоже вычисляются согласно текущему размеру экрана. Кроме того, в этом классе присутствуют определения для символических имен для каждого типа блоков: zombie (для несуществующих блоков), standart (обычные блоки), fixed (неразрушимые блоки) и slide (блоки, которые могут перемещаться на место своих соседей, если такое место еще не занято). Наконец, каждый блок имеет ряд атрибутов, касающихся его позиционирования на игровом поле, типа, цветовой схемы, количества очков, которое дается за разрушение этого блока и ссылки на список блоков, к которому он принадлежит.

Большинство атрибутов блока инициализируется конструктором. Метод clear() удаляет блок с игрового поля, hit() знает, как текущий блок должен отреагировать на следующее столкновение с шариком. IsFixed() возвращает true, если этот блок нельзя разрушить (тип fixed). Как и в предыдущем классе, методы paint() и paintShadow() предназначены для прорисовки объекта.

Код класса Brick: http://java.sun.com/blueprints/code/bricks...icks/Brick.java .html.

 

Класс BrickList

 

BrickList — это первый класс, относящийся к высокоуровневым классам нашей игры. Этот класс занимается размещением блоков на игровом поле. Он знает, как нужно расположить блоки с учетом всех их параметров, а также с расстановкой цветов. Конструктор BrickList использует вариант расположения по умолчанию. Метод moveBrick() перемещает блок с одной позиции на другую, checkForCollision() возвращает значение — число больше нуля, если произошло столкновение шарика с одним из блоков из текущего списка блоков. Возвращаемое значение — это количество очков, которое получает игрок за сбитый блок. Это значение берется из свойства соответствующего сбитого блока. После этого количество заработанных игроком очков увеличивается на это значение. Обратите внимание, каким образом метод checkCollision() заново использует тот же прямоугольник для проверки на столкновение, тем самым исключив из процесса проверки на столкновения любой ненужный мусор (да, это есть оптимизация).

Метод isClean() возвращает true, если на игровом поле (и, соответственно, в списке) не осталось больше стандартных блоков. Таким образом, это означает, что уровень успешно пройден; в противном случае этот метод возвращает false. getNeighbor() возвращает соседствующий блок для блока, передаваемого в качестве аргумента и в соответствующем направлении. Если для этого блока по указанному направлению нет больше соседей, то этот метод возвращает null. Методы paint() и paintShadow() отображают все блоки текущего листа, поочередно вызывая методы paint() и paintShadow() для каждого из своих элементов-блоков.

Код класса BrickList: http://java.sun.com/blueprints/code/bricks.../jbricks/BrickL ist.java.html.

 

Класс Screen

 

Этот класс заправляет всеми высокоуровневыми операциями по рисованию, которые необходимы нашей игре. Он знает, как рисовать различные экраны, которые мы обсуждали в секции Описание этой статьи, а также может запрашивать состояние у класса Engine, чтобы знать, какой экран прорисовывать. В заглавном экране на имя автора наложена простенькая анимация, так что имя автора поднимается из нижней границы экрана. Для анимации этот класс использует переменную wildcard_y. Кроме того, методы keyPressed() и keyReleased() пересылают события, поступающие от клавиатуры, в класс Engine.

Код класса Screen: http://java.sun.com/blueprints/code/bricks.../jbricks/BrickL ist.java.html.

 

Класс Engine

 

Этот класс можно смело именовать сердцем нашей игры. Он хранит все шаблоны уровней в переменной pattern_list (представленные таким образом, что, посмотрев на исходные данные, можно без особого труда представить себе, что собой будет представлять тот или иной уровень) и определяет ряд различных состояний, в которых может пребывать игра. Это состояния title, play, over и demo. Игра стартует, начиная с состояния title, когда отображается заставочный экран. Если в течение определенного промежутка времени была нажата какая-нибудь клавиша, игра переходит в нормальное игровое состояние play. Иначе она стартует демонстрационный режим (состояние demo). В этом состоянии игра играет сама в себя. Выйти в обычный режим play можно, нажав любую клавишу. В случае, когда игрок теряет все выделенные ему жизни, игра переходит в состояние over. Если в течение определенного времени игрок нажимает какую-либо клавишу, игра переходит в режим play, иначе стартует режим demo. Основной цикл программы определен в методе run(). Здесь движок игры "засыпает" на некоторое время, после чего анимирует все объекты и, наконец, перерисовывает экран. Такой подход используется в огромном количестве аркадных игр и обычно называется игровым циклом.

В этом цикле игра прежде всего обновляет свое состояние. Среди элементов, которые игре нужно обновить, — пользовательский ввод, таймеры, генераторы случайных чисел и вражеский AI (Artificial Intelligence — искусственный интеллект). После того, как состояние игры было обновлено, экран перерисовывается. После перерисовки движок "спит" некоторое время и потом начинает весь этот процесс заново. Чтобы дать игре возможность работать независимо от него, модуль движка запускается в своем собственном потоке. Это реализовано посредством использования в классе Engine реализованных методов интерфейса Runnable. После чего создается новый объект класса Thread, и его конструктору передается объект нашего движка. При этом объект thread первым делом запускает сам движок посредством вызова метода run() класса Engine.

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

Это означает, что для того, чтобы переместить доску в другой край экрана, игроку не потребуется несколько раз нажимать на клавишу. Он ее просто удерживает до тех пор, пока доска не переместится в нужное ему место.

Код класса Engine: http://java.sun.com/blueprints/code/bricks.../jbricks/Engine .java.html.

 

Оптимизация

Как только мы запускаем игру в среде WTK или на самом устройстве, сразу бросается в глаза тот факт, что наш подход к прорисовке экрана слишком медленный. Анимация слишком резкая и рывковая. В игру совершенно невозможно играть.

Надо что-то срочно менять. В нашем случае мы просто перерисовывали весь экран для каждого фрейма. Согласно природе нашей игры понятно, что это просто абсолютно нелогичный подход, поскольку в игре у нас от фрейма к фрейму происходит изменение только двух вещей: текущей позиции шарика и доски (если пользователь активно ее перемещает). Изредка наш мячик соударяется со стандартным блоком, который после этого исчезает, либо со скользящим (slide) блоком, который может переместиться на место своего соседа, а может и не переместиться. В этом случаем нам придется перерисовывать еще и весь список блоков. Однако после более близкого изучения мы замечаем, что можно, собственно говоря, весь список и не перерисовывать. Можно просто стереть сбитый стандартный блок из списка или, если это slide-блок, удалить его в старой позиции и нарисовать в новой. Таким образом, имеет смысл рисовать список блоков в отдельном буфере изображения и только потом копировать этот буфер на экран во время перерисовки. Так, во время изменения списка (из-за сбитого или перемещенного блока) мы перерисовываем изменившуюся часть списка в отдельном буфере изображения.

В общем, оптимизация имеет смысл в нескольких областях. Графическая производительность — это одна из наиболее важных областей, и мы должны иметь это в виду. Однако перегруженность в вычислениях также очень критична для вашей игры. Если ваша игра тратит слишком много времени на прохождение игрового цикла, нужно обратить внимание на такие вещи, как проверка на столкновения и другие вычислительные расчеты игры. Для начала попробуйте отключить все кажущиеся вам полезными внутренние особенности реализации и проследите, насколько это уменьшит или увеличит нагрузку на процессор. WTK 2.0 имеет встроенный инструмент для мониторинга загруженности процессора эмулятором. Но будьте внимательны: его цифры не всегда отражают реальную картину происходящего на настоящих устройствах. Как только вы найдете что-то, что нужно исправить, сначала убедитесь, действительно ли ваша реализация обновленного кода оптимизирует работу приложения. Если нет, то вам следует поискать другой, более быстрый подход к решению этой проблемы. Также обязательно обратите внимание на элементы управления. Нет ничего более отталкивающего, а в играх особенно, чем медленное и инертное управление, которое не дает пользователям игры проявить свои игровые способности.

 

Возможные расширения

 

При мысли о расширениях на ум приходят две вещи. Первое — привнести в игру новые типы блоков. Например, блок-бомба, который взрывается при соударении с шариком и сбивает все окружающие его блоки в определенном радиусе, причем даже фиксированные блоки. Другой пример — блок-зеркало. При попадании в него шарика происходит инверсия клавиш управления игроком доски. При попытке игроком двигать доску влево доска движется вправо, и наоборот. Вторая вещь, которую хотелось бы добавить в игру, — сделать ее сетевой. Это позволит загружать из сети новые уровни с определенного сервера. Эти изменения сильно улучшат и приукрасят нашу игру, тем более, что для этого не потребуется сильно менять существующий код.

 

Вывод

 

Самый главный урок, который вы должны были извлечь из этой статьи: рисование — занятие очень ресурсоемкое. Если вы посмотрите на код изначальной реализации, а потом на оптимизированный код, то не увидите между ними большого различия. Между тем, различия в производительности игры очень велики. Если вы собираетесь действительно использовать, а тем более продавать, свою игру, вам обязательно нужно опробовать ее в действии на реальном устройстве. Хоть WTK — это и великолепный инструмент для разработки, но в игре существуют моменты, которые можно обнаружить, лишь запустив ее на реальном мобильном устройстве.

В следующий раз мы рассмотрим сетевой вариант игры для мобильных устройств и еще раз поговорим про проектирование, реализацию и оптимизирование игр на Java.

 

Автор: Алексей Литвинюк

Источник: Компьютерная газета

  • Like 1
Ссылка на комментарий
Поделиться на другие сайты

Слушай, а где это все надо делать? Ну там прога какая-нибудь........:)

ЕНТО Я!!!

Совесть не отвечает или временно не доступна

ICQ=373775451

Ссылка на комментарий
Поделиться на другие сайты

Ну это я уже хз...)) погуглить не пробовал?

пробовал....ниче нормального не выдает....:(

ЕНТО Я!!!

Совесть не отвечает или временно не доступна

ICQ=373775451

Ссылка на комментарий
Поделиться на другие сайты

В этой теме будем рассматривать основы програмирования на платформе J2ME

 

1. Технология J2ME

Ситуация, сложившаяся сегодня в мире мобильного программирования во многом напоминает обстановку конца 80-х, когда на рынке ПК существовало несколько практически несовместимых между собой устройств. Стараясь выжать из железа максимум и как можно быстрее запустить в продажу новые модели, производители не особо заботятся даже о совместимости собственных устройств, что уж говорить о совместимости между устройствами разных производителей. Когда мобильные телефоны являлись просто средством коммуникации, несовместимость не вызывала особых проблем. С течением времени телефоны стали превращаться в сложные функционально насыщенные устройства. Возникла потребность в разнообразном и качественном софте. Осознавая, что сторонние разработчики не будут тратить время на написание программы для единственной модели телефона, производители стали создавать платформы, позволяющие запускать одну и ту же программу на различных устройствах. В настоящее время существует несколько решений, но в России по настоящему большое распространение получила только Java 2 Platform Micro Edition (J2ME).

 

Основная идея J2ME проста: программист компилирует программу в промежуточный код, который затем выполняется специальным эмулятором – виртуальной Java машиной (VJM). VJM выступает посредником между программой и прошивкой телефона. Таким образом, основную часть работы по адаптации приложений к конкретной модели берет на себя производитель. Кроме того, VJM решает проблему безопасности, поскольку приложения не имеют прямого доступа к памяти и ресурсам телефона.

 

На практике VJM разных производителей не всегда выдают одинаковый результат. Из других недостатков J2ME можно отметить неспособность ее работать с вещественными числами (не актуально для CDLC 1.1), а также проблему с исходными кодами. Поскольку в результате компиляции получаются промежуточный, а не машинный код, он легко может быть переведен обратно в java исходник.

 

2. Рабочая среда

Для того чтобы начать разрабатывать мидлеты (так принято называть J2ME приложения для мобильных телефонов) Вам необходимы три вещи:

 

Java 2 Standard Edition (J2SE) SDK version 1.4.2 или выше - компилятор и утилиты для создания Java архивов;

J2ME Wireless Toolkit (WTK) 2.2 - набор утилит и эмуляторов для создания и отладки мидлетов;

текстовый редактор или IDE.

Все эти компоненты абсолютно бесплатны.

 

2.1 Создание нового проекта

Запустите WTK KToolbar. Для создания нового проекта выберите пункт меню File>New Project. В появившемся окне заполните поля "Project Name" и "MIDlet Class Name". Введите, например, SampleSuite и SampleMIDlet. После заполнение этих полей Вам будет предложено настроить параметры проекта. Ничего не меняйте, просто нажмите кнопку OK. В папке [WTK]\apps\ будет создан новый каталог SampleSuite. Каждый проект содержит стандартный набор каталогов:

 

bin - сюда попадают .jar и .jad файлы после упаковки проекта;

lib - сюда следует поместить файлы подключаемых библиотек;

res - файлы ресурсов (например, .png, .txt);

src - файлы .java с исходным текстом программы;

Название .java файла должно соответствовать имени расположенного внутри него класса. Не забудьте, что язык Java чувствителен к регистру букв.

 

2.2 Открытие и запуск примера

После написания кода программы, как правило, наступает этап тестирования. Сначала приложение отлаживается на эмуляторе, а затем непосредственно на телефоне. Давайте откроем один из стандартных примеров (например, UIDemo). Чтобы запустить проект в окне эмулятора, нужно его откомпилировать (кнопка Build), а затем нажать Run на панели инструментов.

 

Для переноса приложения на телефон, необходимо его упаковать. Для этого после компиляции надо выбрать пункт меню Project>Package. В папке bin проекта появятся файлы .jar и .jad. Файл jar является Java архивом, содержащим файлы проекта, а jad - так называемым дескриптором приложения. Дескриптор содержит вспомогательную информацию о классах архива. Эта информация используется телефоном для эффективного управления ресурсами. Именно эти два файла нужно копировать в телефон.

 

3. Простейшее приложение

Особенностью программной модели мидлета является возможность вмешательства операционной системы в ход выполнения программы. Работа приложения может быть в любой момент прервана каким-нибудь внешним событием, например входящим телефонным звонком. Это обстоятельство требует постоянного контроля системы над ходом выполнения программы. Реализуется этот контроль с помощью специального управляющего софта, называемого AMS (Application-Management Software).

 

Каждый Java программист знает, что работа программы начинается с запуска метода main(). В J2ME этот метод недоступен. Вместо него предлагается использовать startApp().

 

Запущенное приложение может находиться в трех возможных состояниях: paused: мидлет запущен, но не активен; active: мидлет активен и destroyed: мидлет остановлен и готов к завершению.

 

Рассмотрим жизненный цикл мидлета. Сразу после запуска он находится в состоянии paused. Прежде чем перейти в активный режим, он должен выполнить инициализацию. Мидлет не имеет специального инициализационного метода и все необходимые действия выполняются внутри startApp(). Через некоторое время после запуска программы, AMS вызывает метод startApp(), в результате приложение переходит в состояние active. Если при запуске возникли какие-нибудь ошибки, управление передается методу javax.microedition.midlet.MIDletStateChangeException, который переводит мидлет в состояние destroyed.

 

В любое время AMS может прервать выполнение мидлета и перевести его в состояние paused. При этом AMS вызывает метод pauseApp(). Для того чтобы перевести приложение в состояние destroyed и закрыть его, AMS вызывает метод destroyApp().

 

Мидлет не способен перевести сам себя из одного состояния в другое. Он может только послать соответствующий запрос AMS, воспользовавшись одним из методов: notifyDestroyed() - запрос на завершение работы; notifyPaused() - запрос на дезактивацию и переход в состояние паузы; resumeRequest() - запрос на реактивацию и переход в активное состояние. AMS решает, нужно ли удовлетворить запрос, и если нужно, то когда это сделать. После запроса resumeRequest() ASM вызывает метод startApp(). В ответ на notifyPaused() и notifyDestroyed() AMS напрямую переводит мидлет в требуемое состояние.

 

Ниже приведен код простого мидлета-каркаса. Я рекомендую сохранить его где-нибудь на диске и использовать в качестве шаблона для новых приложений.

 

//файл SampleMIDlet.java

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

 

public class SampleMIDlet extends MIDlet {

private Display display;

public SampleMIDlet(){}

 

protected void destroyApp( boolean unconditional ) throws MIDletStateChangeException

{

exitApp(); // вызывает уборщик мусора

}

 

protected void pauseApp()

{

// Сюда следует добавить код, который надо выполнять непосредственно

// перед переводом приложения в режим паузы.

}

 

protected void startApp() throws MIDletStateChangeException

{

if( display == null )

{

// Этот код выполняется при запуске мидлета

initApp();

}

// Сюда следует добавить код, который надо выполнять непосредственно

// перед переводом приложения в активный режим.

}

 

private void initApp()

{

display = Display.getDisplay( this );

// Сюда добавляется код инициализации приложения

}

 

public void exitApp()

{

// Сюда следует добавить код, который будет выполняться

// при закрытии приложения.

notifyDestroyed(); // уничтожение MIDlet-а

}

}

 

4. Пользовательский интерфейс высокого уровня

В состав J2ME входит пакет javax.microedition.lcdui, в котором реализованы классы пользовательского интерфейса. Принято различать низкоуровневые и высокоуровневые классы. В рамках данной статьи мы рассмотрим только последние. Программы, написанные с использованием только высокоуровневого интерфейса, практически не требуют адаптации при переносе на различные модели телефонов.

 

Разработка программ на основе высокоуровневого интерфейса сводятся к двум этапам: созданию окон и настройке команд.

 

4.1 Создание окон

Высокоуровневый интерфейс определяет четыре типа окон: Alert, TextBox, List и Form.

 

Alert - окно служебных сообщений. При создании требует четыре параметра: заголовок окна, текстовое сообщение, рисунок и тип сообщения (ALARM, CONFIRMANTION, ERROR, INFO, WARNING). С помощью метода setTimeout можно установить время (в миллисекундах), через которое окно будет закрыто.

 

Alert myAlert = new Alert("Заголовок сообщения","сообщение",image,AlerType.ALARM);

myAlert.setTimeout(1000);

 

TextBox - окно-редактор текста. При создании требует, чтобы ему передали заголовок, начальный текст, максимальный размер текста и ограничения. В качестве ограничений можно использовать константы: ANY - ограничений на текст нет, EMAILADDR - ввод e-mail адресов, NUMERIC - ввод чисел, PASSWORD - ввод пароля, PHONENUMBER - ввод телефонных номеров, URL –ввод URL адресов.

 

Для получения введенного текста можно воспользоваться либо методом getChars(char[] chAr), который записывает текст в переданный массив символов chAr; либо getString(), который возвращает строку. С помощью метода size() можно узнать размер введенного текста.

 

TextBox myTb= new TextBox("Введите текст", "", 255,TextBox.ANY);

...

String strRes=myTb.getString();

List - окно-список элементов. При создании список требует четыре параметра: заголовок списка, тип списка, массив строк и массив картинок для элементов списка. Два последних параметра можно опустить, но тогда для формирования списка нужно использовать метод append(String str, Image img).

 

В J2ME реализованы четыре типа списков. Тип EXCLUSIVE предназначен для пометки одного элемента из списка (соответствует TRadioButton в Delphi); MULTIPLE предназначен для пометки нескольких элементов (соответствует TCheckBox); IMPLICIT позволяет выбрать один элемент из списка (cоответствует TListBox).

 

Чтобы узнать, какие элементы выбрал или пометил пользователь, нужно воспользоваться одним из следующих методов. getSelectedIndex() - возвращает номер выбранного элемента. getSelectedFlags(boolean[] selArr) - записывает в переданный массив selArr состояние всех элементов списка.

 

String st={"Элемент 1", "Элемент 2", "Элемент 3"};

List myList=new List("Элементы",Choice.IMPLICIT,st,null);

...

int index=myList.getSelectedIndex();

Form. Форма - это контейнер, куда можно помещать различные визуальные элементы управления. Если элементы формы не умещаются на экране телефона, создается вертикальная полоса прокрутки. Для добавления элемента на форму используется метод append(). В качестве единственного параметра ему нужно передать либо строку, либо картинку, либо один из визуальных компонентов класса Item.

 

ChoiceGroup - группа элементов для выбора. Этот элемент аналогичен List. Как и List он позволяет создавать EXCLISIVE и MULTIPLE списки. Вместо типа IMPLICIT нужно использовать POPUP, который создает список в виде выпадающего меню.

 

DateField - элемент предназначен для установки даты и времени. При создании требуется передать три параметра: заголовок, режим даты (DATE, TIME или DATE_TIME) и часовой пояс. Последний параметр можно опустить.

 

TextField - поле для ввода текста. Этот элемент очень похож на TextBox, но, в отличие от последнего, не занимает весь экран.

 

StringItem - элемент предназначен для добавления на форму статических строк текста, кнопок и гиперссылок. При создании требуется передать три параметра: строку-метку, строку текста и форматирование текста. В качестве последнего параметра используются константы: BUTTON - для создания кнопки, HYPERLINK - для гиперссылки, LAYOUT_BOTTOM, LAYOUT_CENTER, LAYOUT_TOP, LAYOUT_LEFT, LAYOUT_RIGHT - для определения положения текста на экране.

 

Spacer - элемент предназначен для создания свободного пространства указанного размера. Используется для позиционирования других элементов на форме. В качестве параметров при создании задаются ширина и высота области.

 

ImageItem - элемент предназначен для размещения изображения на форме. При создании требуется передать пять параметров: текст над рисунком, объект класса Image с загруженным рисунком, расположение рисунка (LAYOUT_LEFT, LAYOUT_RIGHT, LAYOUT_CENTER), текст под рисунком и форматирование. Последний параметр аналогичен рассмотренному в StringItem и также может быть опущен.

 

J2ME гарантированно умеет работать с рисунками в формате PNG. Все рисунки проекта должны быть расположены в папке res. Код загрузки и использования рисунка нужно обязательно помещать в try{…}catch{…} скобки, в противном случае при сборке проекта возникнут ошибки. Для загрузки изображения из файла используется метод Image.createImage("/файл.png").

 

Guage - элемент для отображения полос состояния. При создании требуется передать три параметра: метку, флаг типа boolean, указывающий на то должна ли полоса быть интерактивной; значение, соответствующее заполненной полосе, и начальное значение. Для установки текущего положения используется метод setValue(int value).

 

Помимо указанных элементов, под заголовком окон TextBox, List и Form можно поместить бегущую строку с текстом. Для этого нужно создать объект класса Tricker и вызвать метод setTricker окна, указав в качестве параметра созданный объект.

 

ChoiceGroup myCG=new ChoiceGroup("Элементы",Choice.POPUP);

DateField myDF=new DateField("Дата и время",DateField.DATE_TIME);

TextField myTF=new TextField("Введите текст", "", 20,TextField.ANY);

StringItem mySI1=new StringItem("Ф.И.О.", "Иванов Иван Иванович");

StringItem mySI2=new StringItem("URL",

"www.MobiLab.ru",Item.HYPERLINK);

StringItem mySI3=new StringItem("OK", "", Item.BUTTON);

Spacer mySp=new Spacer(50,0);

Gauge myG=new Gauge("Идет процесс",true,100,45);

try{

Image img=Image.createImage("/mobilab.png");

ImageItem myII=new

ImageItem("Логотип",img,ImageItem.LAYOUT_CENTER,"www.mobilab.ru");

myForm.append(myII);

}catch(java.io.IOException ex){}

myForm.append(myCG);

myForm.append(myDF);

myForm.append(mySp);

myForm.append(myTF);

myForm.append(mySp);

myForm.append(mySI1);

myForm.append(mySI2);

myForm.append(mySI3);

myForm.append(myG);

Tricker myTR=new Tricker("Это бегущая строка...");

myForm.setTricker(myTR);

 

4.2 Создание и настройка команд

Для перехода между окнами используется метод Display.setCurrent(Displayable d). Обычно переход выполняется после какого-то действия пользователя. Для настройки реакции на действие, необходимо:

1. создать команду;

2. связать ее с экраном или элементом управления;

3. связать с экраном или элементом класс, реализующий обработчик событий;

4. внутри метода commandAction запрограммировать реакцию на данную команду;

 

 

Для создания команды необходимо создать объект класса Command

 

private Command MyCommand=new Command("Моя команда",Command.SCREEN,2);

Первый параметр определяет строковое представление команды, второй - тип команды, третий - ее приоритет. В качестве типа используется одна из: BACK, CANCEL, EXIT, HELP, ITEM, OK, SCREEN, STOP. Тип команды лишь указывает ее предполагаемое назначение и не влияет на функциональность.

 

Для связи команды с экраном используется метод Displayable.addCommand(Command cmd), а для связи с элементом управления - Item.setDefaultCommand(Command cmd).

 

Если с экраном связаны две команды, то для них создаются соответствующие подэкранные кнопки. Если команд больше, то для одной из них создается кнопка, а остальные помещаются в меню, вызываемое при нажатии второй кнопки. Система решает, какую из команд поместить на экран, ориентируясь на их тип. Например, если среди команд есть команда типа EXIT, то именно с ней будет связана подэкранная кнопка.

 

Класс может обрабатывать команды, только если он реализует интерфейсы CommandListener и ItemCommandListener:

 

public class Navigator extends MIDlet implements CommandListener, ItemCommandListener{…}

Для связи обработчика с экраном используется метод Displayable.setCommandListener(CommandListener cl); для связи с элементом формы - Item.setItemCommandListener(ItemCommandListener cl). В качестве параметра нужно указать объект, реализующий обработчик событий. Если обработка команд выполняется внутри класса, откуда вызывается метод, то в качестве параметра можно использовать слово this.

 

При выполнении команды система вызывает метод commandAction(Command c, Displayable d) для окна и commandAction(Command c, Item i) для элементов формы. Вызвавшая метод команда передается в параметр c. Внутри этого метода необходимо идентифицировать команду и написать код ее обработки:

 

//Обработка команд от окна.

public void commandAction(Command c, Displayable d){

if (c==command1) {

//Сюда помещаем код, выполняющийся при

//возникновении команды command1

}

if (c==command2) {... }

...}

 

//Обработка команд от формы

public void commandAction(Command c, Item i){

if (c==comForm1) {

//Сюда помещаем код, выполняющийся при

//возникновении команды comForm1

}

...}

В данной момент Вы располагаете всей необходимой информацией для написания полноценного мобильного приложения. Давайте в качестве упражнения разработаем небольшую программу-тестирование. Программа будет иметь окна четырех типов: заглавное окно с логотипом программы, окно для ввода информации о пользователе, окна с вопросами и окно с результатом теста. Исходный код с комментариями и откомпилированное приложение прикреплены внизу сообщения.

 

Коды - пиши в любимом текстовом редакторе...

Хоть Виндовом Блокноте.

 

mirpc2_289.rar

 

Еще можешь СЮДА слазать - много чего полезного есть...

 

http://www.mobilab.ru — сайт о мобильном программировании + тематический форум.

http://www.juga.ru — портал Java-разработчиков.

 

  • Like 1
Ссылка на комментарий
Поделиться на другие сайты

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

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйте новый аккаунт в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти


×
×
  • Создать...