пятница, 3 августа 2012 г.

Шаблон проекта HaxeFlixel для FlashDevelop

Одной из особенностей FlashDevelop, упрощающих жизнь разработчика, является возможность создания собственных шаблонов проектов. Я давно хотел создать такой для HaxeFlixel, но руки дошли только сегодня (шаблон доступен здесь).
Сам процесс оказался несложным, пришлось лишь немного погуглить и покопаться во внутренностях стандартных шаблонов. За основу были взяты следующие материалы:
Интересным фактом оказалось то, что установочный файл шаблона (файл с расширением .fdz), является простым zip-архивом, у которого изменено расширение.


воскресенье, 29 июля 2012 г.

NME и HTML5: ready or not?

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

В начале этой недели я в очередной раз попытался скомпилировать простую демку для HaxeFlixel в html5 и сразу же наткнулся на проблему: метод draw() класса BitmapData не учитывал параметры matrix (трансформация положения и формы) и colorTransform (цветовая трансформация), в то время как отрисовка графики в движке полностью строится на двух методах (draw() и copyPixels()). Но за что я люблю NME, так это за отзывчивость разработчиков, и буквально за три дня описанная проблема была исправлена. После этого я занялся непосредственно попыткой скомпилировать демку FlxInvaders в js-код. Сам процесс занял около 6 часов и состоял в основном в дописании параметров условной компиляции (ничего сложного), сам код практически не изменился. И вот, наконец, мне удалось запустить ее, но результат не впечатлил: всего 15-16 фпс против желаемых 30.
После этого началось небольшое исследование + экспериментрирование:
  • где-то полгода назад я услышал о Jangaroo -- специальном SDK, позволяющем компилировать AS3-код в JS, примерно тогда же встретил демку Jumper -- платформер, написанный на AS3 с использованием Flixel и портированный с помощью Jangaroo на html5. То есть успешные попытки портирования Flixel на html5 уже есть, и довольно давно. Так вот, вспомнив об этой технологии, решил поискать еще примеров по ней. Гугл выдал мне следующую страницу, содержащую несколько ссылок по данному предмету, в том числе и на демку FlxInvaders, которая у меня в Хроме выдает в среднем 42-43 фпс, т.е. почти в три раза быстрее.
  • увидев такую разницу в производительности, у меня возникло две мысли: а) мой порт тормозной и б) Jeash тормозной. С первой я спорить не стану, т.к. Flixel использует отрисовку всей графики в одну битмапдату (что является аналогом использования только одного элемента Canvas в JS), а это не самая эффективная техника (но Jangaroo умудряется выдавать при этом гораздо лучший результат), то вторая требовала более подробного изучения.
  • и один день я посвятил данному вопросу. Написал несколько пару простых демок, суть их такова: имеем приложение размером 800х600, в него рисуются спрайты, в каждый из которых вложена битмапа с одним и тем же изображением (30х30 px). В итоге имеем, что при 30 фпс я могу отрисовать 110-120 таких спрайтов, а при 60 — только 45. И это в Хроме, в ФайрФоксе и IE все хуже. Мне такие результаты совсем не нравятся, и Jeash (я так считаю) еще не готов для написания "серьезных" игр (под серьезными здесь я понимаю игры с большим количеством движущихся и трансформируемых объектов).
В итоге родилась следующая, так сказать, "мысль": переписать под себя класс BitmapData (ориентируясь на его текущую реализацию и версию Jangaroo), т.к. практически весь вывод графики в HaxeFlixel зависит от него. Но это, опять же, в отдаленной перспективе, т.к. в приоритете система слоев для C++, которая все так же находится в ранней стадии разработки, а затем stage3D-версия.

UPD: Совершенно забыл приложить скомпилированную версию демки и исходники теста производительности отрисовки спрайтов

среда, 25 июля 2012 г.

Happy Birthday to HaxeFlixel

В этот день год назад я создал на гитхабе репозиторий для HaxeFlixel. За прошедшее время было многое сделано, но в планах на будущее проекта у меня запасено еще на столько же времени, и даже больше. Спасибо Адаму Солтсману за оригинальный Flixel, спасибо Николя Каннасcу за язык Haxe и спасибо Хью Сандерсону, Джошуа Гранику и другим разработчикам за библиотеку NME!!!

среда, 18 июля 2012 г.

О возможном решении проблемы порядка отрисовки графики в HaxeFlixel

В одном из предыдущих сообщений я писал об одном из вариантов решения проблемы порядка отрисовки графики (draw order problem) -- для этого планировалось использование текстурных атласов и введение идеи слоев. Как уже было сказано, у данного решения есть существенное достоинство -- сокращение вызовов методов отрисовки графики, когда число вызовов таких операций за кадр будет равно числу слоев. Это значит, что если все используемые в игре изображения могут уместиться в одном атласе (размером, например, 1024*1024 пикселя), то метод drawTiles() будет вызываться только один раз за кадр. Кроме достоинств есть, конечно же, и недостатки -- повышенное потребление видеопамяти, т.к. 100% упаковка графики в атласы (когда используется вся площадь атласа и нет пустых "пятен") практически недостижима и требует от разработчиков дополнительного внимания (Возможно, что для упрощения работы с атласами, позже будут внедрены парсеры распространенных форматов, например, формат фреймворка Sparrow).
Для реализации данного способа решения уже имеются некоторые наработки -- класс для генерации текстурных атласов на лету я уже портировал на Haxe. Так что, скорее всего, данный метод будет реализован в первую очередь.
После некоторых экспериментов и размышлений я пришел ко второму возможному решению данной проблемы, не требующему использования текстурных атласов. Дело в том, что когда я только начинал портировать Flixel на Haxe, класс TileSheet у меня работал несколько иначе, чем сейчас. Возможно, что у меня тогда руки были кривее и я неправильно его использовал, или что поведение данного класса действительно изменилось. Но факт остается фактом: открылись некоторые новые для меня стороны данного класса, а именно то, что за один кадр можно неоднократно вызывать метод drawTiles() для одного и того же экземпляра TileSheet без появления артефактов. А когда я пытался сделать так в конце прошлого года, то переставали работать цветовые трансформации тайлов.
Теперь же есть возможность вызывать для каждого из изображений в слое метод drawTiles(), и, таким образом, достичь (или почти достичь) желаемого эффекта. Конечно же, при таком решении будет использоваться пакетная отрисовка графики, но в пределах каждого из слоев, иначе эффект от использования класса TileSheet будет равен нулю (т.к. чем больше вызовов метода drawTiles(), тем ниже производительность).
Возможно, что конечный результат будет комбинировать оба решения проблемы, я еще не решил окончательно. Но в первую очередь, как уже писал, я займусь вариантом с использованием атласов.

UPD:  Вспомнил еще об одной особенности работы класса TileSheet, о которой я раньше не знал (или она появилась позже, чем я с ней экспериментировал). Оказывается, что после создания экземпляра TileSheet, возможно изменять его битмапдату-источник, и данные изменения будут отображаться при отрисовке. Раньше же я такого не мог достичь (может быть это было еще одним проявлением моей криворукости). Эта особенность значительно упрощает работу с атласами, т.к. теперь нет необходимости пересоздавать их каждый раз при добавлении в них новых изображений (здесь, конечно же, опять возникает проблема неэффективного использования атласов, т.к. при создании атласов желательно сортировать по размеру входящие в них изображения, иначе в атласе будет полно "белых пятен").

вторник, 17 июля 2012 г.

Хорошее начало недели

Вчера, в понедельник, вышла новая версия Haxe 2.10. Главными ее нововведениями являются:
- поддержка языков C# и Java (пока что в состоянии бета-версии);
- уменьшение размера сгенерированного Javascript-кода;
- C++ дебаггер, о котором авторы обещают скоро написать поподробнее;
- переработка макросов, которые должны стать более понятными новичкам;
- множество улучшений в языке;
- и, конечно же, багфиксы.
Интересным фактом, связанным с этой версией, является то, что за период ее разработки (примерно 3 месяца) было сделано 693 ревизии.
Что ж, теперь будем ждать следующего релиза, на этот раз уже версии 3.0.
А сегодня, во вторник, вышла новая версия библиотеки NME 3.3.4 с улучшенной поддержкой BlackBerry, iOS и HTML5, а также с множеством исправлений ошибок.
К этим событиям я решил приурочить выход небольшого обновления для HaxeFlixel, содержащего:
- новый логотип;
- порт плагина FlxKongregate, позволяющего работать с API данного сервиса (только для Flash);
- порт плагина StarfieldFX - эффект звездного неба (фона);
- исправление нескольких ошибок.
И теперь я с уверенностью могу сказать, что HaxeFlixel поддерживает Haxe 2.10.
Скоро напишу о том, что я пытаюсь улучшить в движке. А пока что это все, о чем хотел рассказать вам сегодня.

суббота, 14 июля 2012 г.

Новый логотип для HaxeFlixel

Хочу поделиться небольшой новостью (и большой радостью для меня): наконец-то у HaxeFlixel появился свой логотип:
Flixel + Haxe = HaxeFlixel
Я давно думал о создании чего-нибудь подобного, но мои художественные способности и лень мешали реализации. Данный логотип придумал и нарисовал австралийский программист Крис, скрывающийся под ником Impaler.

Огромное спасибо тебе, Крис!

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

В ближайшее время ждите новых новостей!

суббота, 7 июля 2012 г.

HaxeFlixel 1.05

С момента записи о планах на версию 1.02 прошло уже два месяца. За это время успело выйти несколько обновлений, о которых я, к сожалению, не писал, а сегодня вышла 1.05. Что же мы имеем на текущий момент:
- все, что было запланировано для версии 1.02;
- исправлено несколько ошибок (самой важной из которых считаю исправление работы звука под android);
- классу FlxSprite добавлен метод loadFrom(), позволяющий использовать в текущем спрайте графику из другого спрайта. Этот метод является еще одним шагом к решению проблемы порядка отрисовки графики. О дальнейшем ходе возможного решения данной проблемы напишу чуть позже в этом посте;
- интрегрирована система tween-анимации из HaxePunk -- теперь у всех подклассов FlxBasic доступны методы addTween(), removeTween() и clearTweens(), а также у класса FlxG появилось статическое свойство tweener, которое может использоваться как глобальный инструмент для анимации. Базовым классом для таких анимаций является класс org.flixel.tweens.FlxTween (в оригинале назывался просто Tween), его возможные вариации (подклассы) находятся в пакетах org.flixel.tweens.*. Для справки о применении tween-анимаций посмею направить вас изучать соответствующие туториалы FlashPunk'а. Если же кому-нибудь будет интересно рассмотреть данный вопрос отдельно, то пишите о этом в комментариях
- добавлена базовая поддержка мультитача и джойстиков. Джойстики поддерживаются только на c++ и толком еще не тестировались, поэтому мне нужна ваша помощь в этом деле (опять же заинтересовавшихся прошу писать в комменты -- тестовый пример вышлю);
- поддержка новой версии языка Haxe 2.10. На самом деле я еще не совсем уверен, что закончил ее, т.к. иногда приложение вылетает с ошибкой, но эта проблема может быть вызвана еще и нестабильностью SVN-версии HXCPP и возможной неполной совместимостью с NME. Так что здесь надо будет подождать их официального выхода, там посмотрим.
Об остальных менее важных изменениях можно прочитать в списке изменений.
Теперь о дальнейших планах. Если вы иногда просматриваете список текущих проблем на ГитХабе, то уже сами все знаете:
- решение проблемы порядка отрисовки графики для c++. Здесь, я думаю, поможет использование текстурных атласов, о реализации которых я писал в одном из предыдущих постов, а также внедрение идеи "слоев", когда у каждого из слоев будет свой атлас. В каждом из таких атласов может находиться одно или несколько изображений для спрайтов и прочих графических классов (их будет нужно добавлять на этапе создания текущего стейта). Сам класс слоя будет подклассом FlxGroup (я думаю дать ему имя FlxLayer). Таким образом, спрайты в слое будут отрисовываться в таком же порядке, как они находятся внутри группы (их порядок в группе можно менять), также можно будет менять порядок отрисовки слоев. Графика в каждом слое будет отрисовываться за один присест. Такая "концепция" может помочь уменьшить вызов операций отрисовки графики, но также может иметь и отрицательные стороны, например, повышенное использование графической памяти.
- о создании stage3d версии я все еще думаю, но теперь мне эта идея не кажется такой простой. Так что ее вы увидите еще не скоро.
- также все чаще думаю о поддержке платформы html5, но пока что особых успехов не достиг. Буду пробовать дальше после выхода новой версии NME.
- добавление новых фич классу FlxTilemap, например, поддержки масштабирования (данная фича может быть полезна для использования тайловой карты в качестве фона)
- портирование экспортеров из редактора карт Dame для их использования с HaxeFlixel. Это должно облегчить создание уровней для игр, не прибегая каждый раз к ручному редактированию классов, получившихся на выходе из редактора.
- создание github-сайта для проекта, но эта идея пока что из разряда мечтаний.
- доработка поддержки мультитача -- касается классов, поддерживающих события мыши (FlxButton, FlxExtendedSprite и др.).
- небольшая кучка других изменений / "улучшений".
Как видно работы еще полно, этого развлечения мне надолго хватит. Ежели вам захочется увидеть реализованной какую-либо еще фичу, прошу запостить ее все там же или написать о ней в комментариях здесь.
На этом смею закончить. Надеюсь, в следующий раз напишу что-нибудь поинтереснее.

Обновление компонента BitmapFont

Наконец-то у меня дошли руки до доработки компонента для работы с растровыми шрифтами. Итак, что же нового было добавлено:
- самое главное изменение -- это добавление поддержки широко распространенного формата AngelCode. А самое важное это то, что для создания шрифтов в таком формате существует ряд специализированных программ (так что добавление нового шрифта значительно упрощается). Самой простой из них является BMFont (бесплатная, работает под Windows), позволяющий создавать шрифты на основе установленных в системе. К сожалению, настроек внешнего вида шрифтов в ней "кот наплакал" (размер, толшина обводки, сглаживание, использовать ли курсив или полужирное начертание), но это лучше чем ничего. Есть еще гораздо более продвинутая программа под Mac OS - Glyph Designer, но за нее просят порядка 30 американских президентов. Эти программы наиболее распространенные, но можно найти и другие.
- вторым, но уже совсем небольшим, изменением является добавление опции "useColor" (для AS3-blit и Haxe версий), или "useTextColor" (для AS3-Flixel версии) объектам класса PxTextField. Данное свойство имеет смысл использовать, если вы загружаете шрифт, созданный в программе Glyph Designer. Дело в том, что в этой программе есть возможность задавать основной цвет символов шрифта, а также задавать его обводку другим цветом. Но если загрузить такой шрифт в мой компонент когда свойство "useColor" имеет значение "true" (устанавливается по-умолчанию), то цвет шрифта будет трансформирован в соответствии со значением свойства "color" объекта PxTextField. Установив значение свойства "useColor" в "false", такой трансформации происходить не будет и шрифт будет выглядеть так, как вы это настраивали в программе.
- Так как в описываемый компонент была добавлена поддержка нового формата, то пришлось изменить немного способ работы со шрифтами. Если раньше, чтобы создать шрифт, нужно было писать код подобный следующему:
_font = new PxBitmapFont(fontBitmapData, fontString);
то теперь, в зависимости от того, в каком формате загружается шрифт, используется следующий синтаксис:
_font = new PxBitmapFont().loadPixelizer(fontBitmapData, fontString); // для загрузки шрифта в старом формате, взятом из движка Pixelizer,
или
_font = new PxBitmapFont().loadAngelCode(fontBitmapData, xmlFontData); // для загрузки шрифта в формате AngelCode, где xmlFontData -- XML данные шрифта.
(Если что-то непонятно, то рекомендую посмотреть пример, там все предельно просто и понятно)

В заключение хочу обратить внимание, что поддержка формата AngelCode в компоненте имеет некоторые ограничения / накладывает некоторые требования:
- как видно из используемого синтаксиса, все символы встраиваемого шрифта должны быть в одном графическом файле;
- поддерживается только xml формат *.fnt файлов (как самый простой для разбора);
- если вы планируете использовать свойство "color / textColor" для цветовой трансформации текста, то в опциях эспорта шрифта используйте опцию "White text with alpha" ("Белый текст с програчным фоном").


Теперь о дальнейших планах:
- планирую добавить поддержку "типов" текстовых полей. Думаю, что будет два типа -- динамические (как сейчас) и поля ввода. За основу возьму эту серию уроков по созданию компонентов для FlashPunk.
- возможно, что сделаю поддержку stage3D, но это в крайне отдаленной перспективе, т.к. еще очень много планов по развитию HaxeFlixel, но о них в следующий раз.
На этом все. До скорых встреч :)


P.S.: скачать компонент BitmapFont вы можете с github-репозитория "проекта"

воскресенье, 20 мая 2012 г.

Отчет за первую половину мая 2012

В предыдущем сообщении я писал о планах на следующий релиз HaxeFlixel. А спустя две недели, наконец, доделал все что планировалось. Дата официального релиза на haxelib пока остается открытой, так как для работы новой версии требуются новые фишки класса TileSheet из библиотеки NME, присутствующие только в SVN-версии. Так что ждем выхода следующей версии NME. А пока что для использования новой версии придется самостоятельно компилировать NME (инструкцию по компиляции можно найти здесь)
Теперь же собираюсь заняться переводом flash-версии Flixel на Stage3D. При работе буду ориентироваться на axel2d, благо что его структура практически совпадает со структурой Flixel. Еще одним инструментом будет портированный на Haxe ассемблер AGAL'а -- наконец-то без ошибок!!!

Следующей новостью является обновление движка Pixelizer до версии 0.4.3 (в основном содержит исправления ошибок). Haxe-порт был обновлен в тот же вечер, что и релиз, и лежит здесь. На него тоже есть некоторые планы -- добавление рендерера на основе класса TileSheet для нативных платформ.

И заметка для себя: покопаться с библиотекой nme-tilelayer от Philippe Elsass -- это обертка для класса TileSheet, предоставляющая базовые методы для работы со списком отображения (display-list), анимациями и трансформациями тайлов. Кроме нативных платформ, она работает на Flash и HTML5 (для этого используются битмапы). Пример использования -- nme-runnermark -- портированный с AS3 на Haxe бенчмарк производительности stage3d-фреймворков (результаты впечатляют).

пятница, 11 мая 2012 г.

Flixel for Monkey

В этом коротком сообщении хотелось бы рассказать о существовании проекта Flixel for Monkey. Это порт многократно здесь упоминаемого движка Flixel на язык Monkey. О том, что это за язык, вы можете узнать из статьи "О Monkey, откровенно" (автор этой статьи как раз и занимается данным портом). Я хотел бы поблагодарить его за проделанную им работу и за его советы по оптимизации движка. Как оказалось, процесс обнаружения и разрешения столкновений в оригинальном Flixel'e требует некоторой оптимизации -- в классах FlxQuadTree и FlxObject  создается много мусора (объектов типа FlxQuadTree, FlxList и FlxRect), что повышает потребление памяти приложением. Решение данной проблемы простое: кеширование и повторное использование объектов вместо создания новых. Пользуясь этой наводкой, а также сверяясь с исходным кодом порта (синтаксис языка Monkey оказался очень простым и понятным), описанная проблема была решена.
Еще раз хочу сказать спасибо товарищу Devolonter и надеюсь, что он не бросит свою работу.

воскресенье, 6 мая 2012 г.

Планы для версии HaxeFlixel 1.02

На прошлой неделе вышло обновление порта Flixel на haxelib до версии 1.01. Основными изменениями в данном релизе были портирование прелоадера (наконец-то) и совместимость с Haxe 2.09.  А сейчас я хотел бы поделиться планами на будущий релиз:
  1. В оригинальной версии движка поддерживается неоднородное масштабирование спрайтов, т.е. спрайту можно задать один масштаб по оси x и другой по оси y. При создании специального рендерера (для C++) на основе класса TileSheet пришлось отказаться от такой фичи, т.к. данный класс поддерживал только однородное масштабирование. Недавно такой функционал был добавлен (пока что только в SVN-репозитории библиотеки), причем теперь можно задавать не просто масштабные коэффициенты и угол поворота каждого тайла, а значения коэффициентов матрицы трансформации, т.е. мы можем еще и зеркально отразить тайл, скосить (skew) его, или совместить все эти трансформации вместе. Пользуясь новым функционалом я хочу вернуть неоднородное масштабирование, а также заново реализовать зеркальное отражение спрайтов (свойство flipped), которое сейчас реализовано путем изменения исходного изображения для спрайта.
  2. В текущей версии движка для C++ наблюдаются проблемы с отрисовкой спрайтов -- для повернутых или масштабированных спрайтов появляются графические артефакты. Эта проблема может быть решена простой модификацией изображения для спрайта -- вставкой "пустых" пикселей между изображениями кадров.
  3. Как я уже писал в предыдущем сообщении, реализация класса FlxText довольно неудачна для C++, и я начал работу над компонентом для работы с растровыми шрифтами. Текущая версия данного компонента для HaxeFlixel пока что работает только на Flash и уже лежит на гитхабе (класс FlxBitmapTextField), остается только реализовать отрисовку на C++ (с этим не должно возникнуть особых сложностей, т.к. подобную задачу я уже решал).
  4. "Улучшение" класса FlxButton. Может быть достигнуто заменой кода, отвечающего за отрисовку текста на кнопке, т.к. сейчас он выводится с помощью класса FlxText, это можно исправить используя разрабатываемый класс FlxBitmapTextField (хотя данное изменение еще под вопросом).
  5. Закончить портирование класса FlxBar (нужен, например, для отрисовки полоски здоровья у героя или врагов) из библиотеки Flixel Power Tools. Хотя данный класс и работает на всех поддерживаемых платформах, есть необходимость его оптимизации для C++, т.к. каждый раз при изменении отображаемого значения создается много мусора, что значительно замедляет работу приложения.
  6. Небольшой рефакторинг: замена объектов типа Dynamic на соответствующие типизированные объекты (там, где это возможно). Например, у кнопок есть свойство onUp, представляющее собой функцию, вызываемую при отпускании левой кнопки мыши, данное свойство должно вместо Dynamic быть Void->Void, т.е. быть функцией без аргументов и возвращаемого значения.
Вот и все планы на следующий релиз (на данный момент). Жду ваших предложений и всегда готов обсудить их в комментариях.

 

 

четверг, 3 мая 2012 г.

Компонент для работы с растровыми шрифтами

Продолжая работу над портом движка Flixel на Haxe, столкнулся с необходимостью оптимизации работы с текстом. Проблема заключается в следующем: стандартный класс движка FlxText сильно завязан на использование метода draw(), и при обновлении текста создается новый экземпляр класса BitmapData, еще одним недостатком является то, что для каждого такого текстового объекта создается свой экземпляр класса TileSheet (если в качестве целевой платформы установлен c++, neko или android). В общем видно, что такая реализация класса для отображения текста довольно неудачна и нужно искать другие решения. И тут на сцену выходят растровые шрифты -- каждый символ такого шрифта представляет собой по-сути простое изображение и работать с ними можно точно также, как и с обыкновенными изображениями. В наборе классов Flixel Power Tools как раз есть такой класс FlxBitmapFont и я его уже давно портировал, но в нем также присутствует довольно раздражающее меня ограничение -- он поддерживает только моноширинные шрифты (все символы таких шрифтов должны иметь одинаковую ширину), а мне же хотелось чего-нибудь более универсального. И недавно мне на глаза попался движок Pixelizer (упоминал его в одном из предыдущих сообщений), в котором очень понравилась реализация такого компонента: в нем уже был такой функционал, как изменение цвета шрифта, обводка и тени, поддержка многострочного текста и др. Встала задача по переводу этого добра на другие рельсы:
  1. Реализация в виде отдельного компонента, не завязанного ни на какой из движков -- такой класс нужен был для того, чтобы наконец-то закончить портирование прелоадера Flixel.
  2. Реализация в виде плагина для Flixel, которую можно использовать непосредственно в играх.
Самая первая версия порта была готова через 1-2 дня, но сразу же вылезли проблемы с производительностью: для отрисовки текста использовался метод draw(), позволяющий задавать тексту цветовую трансформацию и прочие параметры. Нужно было искать другой способ отрисовки. Подумав немного и посмотрев на реализацию спрайтов в Flixel, пришел к следующему решению: на входе имеем набор растровых изображений, представляющих собой исходные изображения символов растрового шрифта, а для того, чтобы отображать масштабированный и "окрашенный" текст создается дополнительный массив трансформированных изображений символов, таким образом, мы можем использовать уже гораздо быстрый метод copyPixels() (после такого преобразования нагрузка на процессор при отрисовке текста снизилась в 2-4 раза).
Завершив с оптимизацией, я приступил к реализации дополнительных "фишек":
  • настройка размера шрифта
  • настройка расстояний как между символами, так и между строками текста
  • настройка переноса слов
На это ушло еще несколько дней, скачать и посмотреть что получилось можно со странички репозитория - https://github.com/Beeblerox/BitmapFont
На данный момент там присутствуют три различные версии описываемого компонента:
  • кросс-платформенная версия под Haxe (данная версия используется в порте класса FlxPreloader). Работает на flash, c++ и neko; должно также работать  на iOS и Android, но не проверялось.
  • версия на AS3
  • версия для Flixel, также на AS3. В ней отсутствует возможность задания фона у текста, от этого функционала пришлось отказаться из-за проблем, которые возникнут при портировании на Haxe. Может быть, когда у метода drawTiles() класса TileSheet появиться возможность задавать масштаб тайлов по обеим осям (данный реквест можете помочь продавить в данной теме на форуме haxenme.org), я введу такой функционал, но пока оставлю так.
В каждой из папок есть примеры использования, так что проблем не должно возникнуть.
Версия для Flixel на Haxe находится в работе (на данный момент работает только под flash) и должна быть готова в течение недели (надеюсь, что так и будет :) ).

Напоследок расскажу как создать свой растровый шрифт, для этого вам понадобятся две вещи:
Пример изображения для растрового шрифта
  1.  Графический файл (обычно в формате png), содержащий изображения символов шрифта. Для того, чтобы программа смогла распознать границы изображений символов шрифта, изображение должно иметь фоновую заливку, а изображения символов не должны содержать данного цвета, плюс между символами дожен быть минимум 1 пиксел и каждый ряд изображений символов должен начинаться с одного уровня (см. рисунок выше) 
  2. Строку, содержащую символы, соответствующие изображению. Например, для приведенного выше изображения данная строка будет иметь вид: " !\"#$%&'()*+,-./" + "0123456789:;<=>?" + "@ABCDEFGHIJKLMNO" + "PQRSTUVWXYZ[]^_" + "abcdefghijklmno" + "pqrstuvwxyz{|}~\\"
Чтобы создать сам шрифт нужна всего одна строчка:
_font = new PxBitmapFont(fontBitmapData, fontString);
где fontBitmapData - изображение символов шрифта, а fontString - строка с символами шрифта.
Для создания текстового поля обязательными являются две строки:
_text = new PxTextField(_font); // непосредственно создание текстового поля
_text.setWidth(100); // задание ширины поля, по-умолчанию равна единице


Думаю, что разобраться со свойствами создаваемого таким образом текстового поля не составит особых затруднений (их названия говорят сами за себя и должны быть знакомы, если вы уже работали со стандартными текстовыми полями), поэтому на этом и заканчиваю. А если возникнут какие вопросы - то добро пожаловать в комменты :)

UPD: Стоило мне вчера написать, что не хватает в методе drawTiles() аргументов, задающих масштабные коэффициенты по обеим осям, как уже сегодня в svn-репозитории NME была добавлена эта возможность -- теперь каждому тайлу можно задавать матрицу 2d-преобразований, т.е. не только масштабы и поворот, но и отражение по оси, наклоны и т.д. Вот такие дела. 

понедельник, 16 апреля 2012 г.

Первая игра на FlixelNME

Вот и вышла первая игра на FlixelNME -- Pakkuman's Defense -- это своего рода смесь Pac-man с Tower Defence. Автор игры - Ido Yehieli (Tametick)
Вот вольный перевод отрывка отзыва об игре с сайта http://www.indiegamemag.com:
А вы знали, что первоначально игра Pac-Man должна была называться Puck-Man - производное от японского “паку-паку” - хлопать ртом. А знаете ли вы также, что эта игра станет в сотни раз лучше, если в ней будут элементы товер дефенса? Pakkuman Defense - это одна из таких ретро-игр, в которых намешаны разные элементы. Но кроме обаяния, китча и чувства удовлетворения от уничтожения проклятых привидений в ней есть стратегическая глубина.
Смысл прост: вы играете в Pac-Man, но собираемые точки используются в качестве местной валюты для покупки башен, уничтожающих привидения. И такой простой прием резко меняет всю игру. Так как на поле расположено ограниченное число точек, то вы можете построить строго ограниченное число башен, поэтому важно выбирать наиболее эффективное расположение башен, так как привидения бесконечно респавняться. Случайный дизайн карт более сложный, нежели в оригинале, на них могут быть и тупики и множество мест, где вас могут окружить, поэтому размещение башен вдвойне важно. Другим ключевым моментом является то, что собранные на одном уровне точки переносятся на другой, и если вы потратите все свои деньги на одном уровне, то на следующем вас может ждать катастрофа.
По мнению автора обзора у игры есть два основных недостатка: это отсутствие жизней у главного героя (даже оригинальный Pac-Man не был так жесток в этом отношении) и немного "привередливое" управление, которое иногда не срабатывает. Хотя эти проблемы и вносят свой вклад в общую сложность игры, все-таки они не являются решающими.
Pakkuman Defense - это полностью новое и успешное осмысление идеи Pac-Man.

Игру Pakkuman Defense можно приобрести на сайте http://www.indiebuskers.net/ в составе Buskers Bundle. Данный комплект из 5 инди-игр продается по модели Pay-what-you-want (плати сколько хочешь) и на момент публикации этого поста было продано всего 435 бандлов.

UPD: Оказалось, что Pakkuman Defense - не первая игра на FlixelNME, до нее Ido Yehieli написал игру Fuel, повествующую об астронавте, вынужденном приземлиться на астероиде в поисках топлива для своего корабля:
Эта игра была создана в рамках конкурса 7DRL (Seven Day Roguelike Challenge) и поиграть в нее можно совершенно бесплатно (ссылки для скачивания доступны на странице игры).


суббота, 7 апреля 2012 г.

Обзор интересностей за март-начало апреля

Прошедший месяц был довольно насыщен событиями, связанными с flash-разработкой: это и выход flash player 11.2 и AIR 3.2 (добавившим поддержку stage3D на мобильных платформах), и публикация планов корпорации Adobe o премиум-фичах flash player (данная новость вызвала множество негативных отзывов у разработчиков). Но об этом Вы и сами наверняка знаете (если интересуетесь этой технологией). А в этом посте я хотел бы выделить несколько наиболее интересных для меня релизов:
1. Pixelizer - это фреймворк для написания игр на AS3, в основе которого лежит идея компонентов. Как пишет о нем сам автор, этот движок имеет гибкую структуру и легко расширяем. Текущая версия (0.4.2) для вывода графики использует блиттинг и включает компоненты для:
  • работы с текстом (который мне очень понравился и я собираюсь его внедрить в свой порт flixel);
  • систему обнаружения и разрешения столкновений; 
  • систему ввода данных (мышь и клавиатура);
  • поддержка вложенности компонентов;
  • spritesheets, animations and tilemaps;
  • звуковой менеджер;
  • систему кеширования объектов и т.д. 
 По моему мнению, он довольно перспективен, а его разработчик не намерен прекращать разработку и на страничке репозитория проекта можно увидеть дальнейшие планы по развитию проекта.
2. Molehill-версия известного теста производительности BunnyMark (на момент публикации сайт был недоступен, но скоро должен заработать) + серия уроков по созданию игры в жанре SHMUP. Эти статьи будут полезны тем, кто хочет разобраться и понять основы работы со stage3D для разработки двумерных игр. Ну а тем, кому неинтересна техническая сторона вопроса, а охота сразу приступить к созданию игр с поддержкой 3D-ускорителей, можно посоветовать обратиться к уже существующим фреймворкам (Starling, ND2D, Genome).
3. Axel2D - библиотека для создания 2D-игр с поддержкой 3D-ускорителей. Главной особенностью считаю то, что API этого движка практически один-в-один повторяет API Flixel, отличающегося исключительной простотой использования. Кроме этого в данном движке мне понравилась реализация систем частиц, позволяющая отображать одновременно сотни тысяч частиц при 60 fps.
Но так как этой библиотеке всего неделя, то есть и слабые стороны, а именно - отрисовка спрайтов, которая ведется отдельно для каждого из них, а не пакетно, что, конечно же, не позволяет работать одновременно с большим их количеством. Плюс имеются некоторые недоработки (по словам автора) с обработкой ошибок и инициализацией движка. Однако, как мне кажется, движок очень интересный и при некоторой доработке может стать преемником flixel (или может быть интрегрирован в него).
Это были главные для меня новости из области flash-разработки за прошедший месяц. А какие были для Вас?

четверг, 5 апреля 2012 г.

Динамическая генерация текстурных атласов

Давно задумываюсь: "А не попытаться ли перевести Flixel на Stage3D?" Сам автор движка обещал, что когда новая версия flash-плеера с аппаратной поддержкой 3D получит достаточно широкое распространение, то он добавит эту фичу. Но новостей от него пока не слышно; тема на форуме фликселя, посвященная планам по разработке новой версии, тоже довольно давно не обновлялась. Поэтому и мысли такие. Кроме того, в сети появилось несколько очень хороших уроков по stage3D, в которых рассматривается использование нового API для разработки двумерных игр. Из них можно вынести очень полезные сведения, связанные с оптимизацией графики:
  • необходимо минимизировать количество вызовов метода drawTriangles(), т.к. он довольно ресурсоемок;
  • также следует использовать как можно меньше текстур, т.к. размеры текстур могут иметь строго определенные значения (64х64, 128х128, 256х256, 512х512, 1024х1024 или 2048х2048). И если в Вашей игре используется множество маленьких изображений, для каждого из которых Вы будете создавать новую текстуру, то видеопамять будет расходоваться нерационально (в каждой такой текстуре будет много "пустого места") и довольно быстро закончится.
 Для решения этих проблем рекомендуется использовать "пакетный рендеринг" (не знаю, правильный ли я использую термин, на английском он пишется batch-rendering), при котором мы за один вызов метода drawTriangles() пытаемся отрисовать все полигоны, использующие одну и ту же текстуру. Для этого нам и понадобится генерация текстурных атласов, вынесенная в заголовок статьи и позволяющая значительно уменьшить количество текстур (о пакетном рендеринге я скорее всего напишу в следующей статье). Суть его в следующем: на входе мы имеем множество мелких изображений, а на выходе -- одно (это в идеале) большое. На русском языке уже есть, по крайней мере, одна статья от flash-сообщества, посвященная этому вопросу -- класс для генерации текстурных атласов, в ней дается исходник класса, использующий рекурсивный метод построения атласа. Данный класс мне показался не слишком понятным, а так хотелось самому разобраться в алгоритме, благо что в статье приведена ссылка на англоязычную статью по данному вопросу, из которой и становится ясен общий принцип.
Для хранения данных о субтекстурах (вставляемых в атлас изображениях) строится специальное дерево, в узлах (объекты класса Node) которого хранятся размеры, положение и прочая нужная информация. При этом каждый узел может иметь не более двух поддеревьев (левое и правое). Первоначально, когда наше дерево пустое, в нем имеется только один пустой корневой узел root. При попытке добавить в дерево новое изображение производится проверка, не превышает ли размер вставляемого изображения размера всего атласа. Затем осуществляется поиск подходящего по размерам пустого узла, в который мы можем вставить новую картинку, для этого должны выполняться 2 условия: узел должен быть "пустым" (не содержать в себе изображение и не иметь вложенных в него других узлов -- т.е. вставлять картинку мы можем только в "листья" дерева) и его размеры не должны быть меньше вставляемого изображения. Поиск таких узлов ведется с помощью нисходящего обхода в глубину, данный метод отличается тем, что он не является рекурсивным. О данном методе я прочитал в книге А.А. Кубенского "Структуры и алгоритмы обработки данных...", эта книга, к сожалению, уже нигде не продается (я бы купил себе эту книгу только ради диска с исходниками, которых не найти), но в сети можно легко найти отсканированный вариант. Поиск в дереве начинается с корневого узла и опускается ниже к "листьям", при этом приоритет отдается левым поддеревьям нашего дерева. Если в дереве находится отвечающий условиям поиска узел, то с ним проводятся следующие действия:
  1. В него вставляются два узла, общий размер которых равен размеру данного (родителя). При этом, как мы понимаем, узел может делится или по горизонтали, или по вертикали. Для того чтобы решить, как нам делить узел, мы находим разницу между ширинами и высотами этого узла и вставляемого изображения. Если разница по ширине окажется больше, то узел мы делим по горизонтали, в противном случае -- по вертикали (как на иллюстрации ниже).
  2. Берем первый из вставленных таким образом узлов и делим его снова на два узла. Размер первого такого "внука" будет равен размеру вставляемого изображения, а второй "внук" будет занимать оставшееся место (также см. иллюстрацию).
Вставка нового изображения в атлас
В общем, алгоритм не сложен, но требует понимания базовых структур данных и принципов работы с ними. Так что крайне рекомендую почитать какой-нибудь из соответствующих учебников.
Мою реализацию текстурного атласа (на as3) можно скачать здесь.