Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > С миру по строчке

Рейтинг: 5.00. Голосов: 4.

из Flash на HaXe, из HaXe во Flash при участии NME

Запись от СлаваRa размещена 13.04.2013 в 00:43
Обновил(-а) СлаваRa 13.04.2013 в 14:08

...дело было вечером, делать было нечего...

Сейчас я и моя команда занимаемся разработкой своей игры, в которой мы используем DragonBones + Starling + CitrusEngine + Box2D + ...
В какой-то момент получилось так, что команде программистов стало не с чем работать, т.е. арт стал настолько быстро подключаться к игре, что команда художников\аниматоров просто перестала обеспечивать нас нужными ресурсами для работы, и тут появилось время...

Дабы его не терять на просиживание в соц. сетях и т.п., было решено портировать, то что было готово на HaXe, во-первых было интересно сравнить скорость работы, во-вторых разницу в языках, в-третьих HaXe обещал кроскомпиляцию...
Начали.
  1. Очень порадовала работа с терминала, не надо качать swc, следить за версиями, и т.п., haxelib install lib_name, после чего остается подключить библиотеку, указав ее имя в настройках проекта.

  2. #define круто и удобно, в отличии от Flash'ового CONFIG::, имеют огромную свободу в использовании и, иногда, упрощают жизнь, например:
    Код AS3:
    //inline будет использован только в релизе
    private #if !debug inline #end function addTextureAtlas(texAtlas:ITextureAtlas, name:String)...
     
    //в зависимости от платформы определяем "синоним" для сущности, этот пример подробнее описан ниже
    typedef DisplayBridge = #if flash11 dragonbones.display.StarlingDisplayBridge #else dragonbones.display.NativeDisplayBridge #end;
  3. typedef - отличная замена интерфейсам в определенной ситуации. Так получилось, что библиотеки DragonBones не оказалось под HaXe, пришлось портировать... Автор писавший ее, в некоторых ситуациях не смог создать "вменяемых" базовых классов или интерфейсов, пример(я оставил минимальный код, для компактности):

    Код AS3:
    package dragonBones.display {
            //...
    	public interface IDisplayBridge {
                    //...
    		function get display():Object;
    		function set display(value:Object):void;
                    //...
    	}
    }
     
    //в этом классе необходим flash.display.DisplayObject
    public class NativeDisplayBridge implements IDisplayBridge{
            //...
            public function get display():Object	{
    		return _display;
    	}
            public function set display(value:Object):void{
                    ...
            }
            //...
    }
     
    //в этом классе необходим starling.display.DisplayObject
    public class StarlingDisplayBridge implements IDisplayBridge{
            //...
            public function get display():Object	{
    		return _display;
    	}
            public function set display(value:Object):void{
                    ...
            }
            //...
    }
    Использование интерфейса в AS3 не позволяет нам, в данном примере, использовать разные классы для "объектов" реализующих интерфейс. В HaXe это возможно сделать через typedef, я привел самый просто вариант, мой код Bridge'й выглядит так(необходимо было сохранить типизацию, об этом ниже):

    Код AS3:
    class NativeDisplayBridge{
           ...
           public var display(default, set_display):nme.display.DisplayObject;
           ...
    }
     
    class StarlingDisplayBridge{
           ...
           public var display(default, set_display):starling.display.DisplayObject;
           ...
    }
  4. inline, но необходимо знать об ограничениях, небольшой выигрыш в скорости они дают.
  5. приватные конструкторы, сокращение кол-ва кода на акцессорах для read|write only, по-большей части привычный синтаксис.

Может быть, какие-то “плюшки” я не упомянул(они есть, боюсь не уместиться), из-за того что все рабочую неделю мне пришлось оптимизировать, изучать, тестировать, копаться в исходниках, читать багтрекеры, спрашивать более опытных коллег...
"Грабли" Нижеследующее касается компиляции из HaXe во Flash(мы проводили тесты на максимальных нагрузках, 1000 анимированных клипов на сцене).
  1. нет is, есть Std.is, метод создает анонимные функции после компиляции, что влечет за собой утечки памяти и постоянный вызов GC(Std.int, Std.string туда же).
  2. нет for, есть forin, есть Lambda для обхода коллекций, боже упаси вас использовать Lambda, оно конечно красиво, сравните:

    Код AS3:
    for(i in collection){
           i.someMethod();
    }
     
    //и
     
    Lambda.iter(collection, function(i) i.someMethod());
    но утечки памяти и вызовы GC на наших тестах были просто нереальны, за пару-тройку минут память росла с 40мб до 400.
  3. для массивов нет indexOf, есть Lamdba.indexOf, если сможете обойтись, вам повезло(для удаления, есть Array.remove).
  4. постоянная перезапись в Array тянет GC, используйте Vector(only Flash), но у него нет метода remove.
  5. нам пришлось написать свою реализацию Math.sin, Math.cos(UPD1:проблема не в HaXe).
  6. не используйте Math.isNaN(a), альтернатива (a != a), спасибо @Sync и @deep.
  7. если во Flash в Dictionary, можно использовать строки в качестве ключей, то в HaXe для ключей-объектов ObjectHash, для ключей-строк Hash, для ключей-интов IntHash, если же поступить иначе, проблемы рано или поздно возникнут(я потратил час на понимаем почему могу записать по стринг-ключу в ObjectHash, а при чтении получаю Null).
  8. кешируйте Array::length, я бы не рекомендовал вам его юзать в forin, Scout трубил о постоянном обращении к методу.
  9. при кросскомпиляции, необходимо досконально изучать справку, например для ByteArray указание длины для Flash можно использовать ByteArray::length, для CPP и Neko ByteArray::setLength, проблему с Loader::loadBytes для Neko мы, пока, так и не смогли решить(для всего работает, для Neko "падает" без объяснений).
  10. namespace так и не появились, приходится использовать Reflect;
  11. поддержка e4x нереально ужасна.
  12. битовые операции с флотами не пройдут, придется кастовать к Int;
  13. forin тормознее while.
  14. в if'aх допускается только Bool(запись if(object) не пройдет).
  15. любая красивая "плюшка" типа:
    Код AS3:
    var a = if(true) 1; else 2; 
    //или
    var a = switch(someVar) {case 1: 1;...}
    развернется в анонимную функцию;
  16. не все нативные библиотеки будут вести себя хорошо для Flash.

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

UPD1:
ссылки, которые пригодятся
the haxe magic
haxe language reference

ps
прошу простить меня за кривость изложения, поправляйте, буду редактировать.

ps2
спасибо @Котяре, @DeMoney, @Алексей Мельников, @Sync, @deep, и всем остальным кто мне помогает в работе и публикации накопившегося материала.
Всего комментариев 17

Комментарии

Старый 13.04.2013 12:28 Dima_DPE вне форума
Dima_DPE
По первой пятерке:
2. очень плохой пример дефейна, для отключения инлайна есть --no-inline
3. почему не заюзать дженерик IDisplayBridge<T : (nme.display.DisplayObject, starling.display.DisplayObject)> ?

Дальше:
1. Для флеша есть untyped __is__(a, ClassRef);. Std.int == untyped __int__(i); Std.string действетельно оверхед, но там разворачиваются динамические объекты, что очень удобно для дебага
3. http://try.haxe.org/#14569 или даже http://try.haxe.org/#76f60
5. ну это явно не изза Haxe, там юзается нативный Math
7. В haxe 3 есть удобная обертка, класс Map, не надо помнить какой хеш куда, мап сам решает.
10. В haxe 3 есть мета теги @:access и @:allow
12. операции инта с уинтов тоже не пройдут.
13. форин разворачивается в while, тормознее он может быть только потому, что while ты как то оптимизировал, заранее запомнив arr.length и т.д.
15. на самом деле так в js таргете, для флеша я не декомпилировал и не проверял, просто подозрение.
16. вот тут вообще не понял. что мне не удалось норм подключить в haxe было 2 библиотеки с алхимией, вместе они почему то давали ужастно низкий фпс, хотя отдельно просто летали. Чистые ас3 либы собраные в swc отлично подключаются, знаю точно работают (away3d, starling)
Обновил(-а) Dima_DPE 13.04.2013 в 14:58
Старый 13.04.2013 12:59 Dima_DPE вне форума
Dima_DPE
На самом деле все очень и очень круто! Мелкие прописные истины, которые те кто уже использует haxe не замечает, а новенькие явно сталкиваются с ними.

Но не нашел в статье ссылок на такие нужные статьи как эта http://haxe.org/doc/advanced/magic и тем более эта http://haxe.org/ref
Старый 13.04.2013 13:07 Dima_DPE вне форума
Dima_DPE
по 15. еще раз
Код AS3:
var a = if(true) 1; else 2;
станет обычным тернарным оператором, а вот свитч скорее всего обернут функцией, хотя повторю, я не декомпилировал чтобы проверить и буду признателен тому, кто это сделает.
Старый 13.04.2013 13:53 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
Спс за комментарии, добавил ссылки

Цитата:
13. форин разворачивается в while, тормознее он может быть только потому, что while ты как то оптимизировал, заранее запомнив arr.length и т.д.
мы проверяли на простом прогоне от i in 0...100000
по поводу haxe 3 ты прав, но еще не переехали.
Обновил(-а) СлаваRa 13.04.2013 в 14:09
Старый 13.04.2013 14:09 Dima_DPE вне форума
Dima_DPE
Цитата:
мы проверяли на простом прогоне от i in 0...100000
очень странно на самом деле, давайте проверять http://try.haxe.org/#AfF85
Кстати, обрати внимание, js таргет тут быстрее 0_о
Обновил(-а) Dima_DPE 13.04.2013 в 14:21
Старый 13.04.2013 16:03 RealyUniqueName вне форума
RealyUniqueName
Приветствую.

Вот этот простой тест наглядно демонстрирует, что никаких утечек нет. Проблема скорее всего в вашем коде.
В этом тесте используются Lambda.iter(), Array.length и Std.is(). Память стабильно держится 21-25K (Ubuntu, Chrome, Flash 11.7)

Насколько я знаю, вызов замыканий во флеше - дорогое удовольствие, так что нет ничего удивительного в том, что Lambda.iter() работает медленнее for().

Далее идём сюда и видим, что у Array.length нет ни геттера, ни сеттера, а это значит, что обращение к этому свойству должно быть ничем не дороже обращения к локальной переменной. Хотя, тут я мог что-то упустить, не уверен.

Потом идём сюда и видим, что Std.is() вызывает untyped flash.Boot.__instanceof(v,t); Который, как следует отсюда вызывает untyped __is__(v,t), который и есть обычный экшнскриптовый "is". Оверхед, конечно, есть из-за двух вызовов статических методов и одного if, но я даже не представляю, насколько интенсивно нужно использовать Std.is(), чтобы его оверхед стал значимым.
Зато мы имеем полностью кросплатформенный метод.
Однако если вы всё-таки умудрились написать приложение, которое упирается в Std.is(), то использование вот такого метода вас спасёт (абсолютно нулевой оверхед во флеше):
Код AS3:
    static public inline function is (v:Dynamic,t:Dynamic) : Bool {
        #if flash
            return untyped __is__(v,t);
        #else
            return Std.is(v, t); //или отдельная реализация для каждой платформы
        #end
    }
Про остальное вроде бы уже сказали другие люди )

Извините за возможную излишнюю эмоциональность, просто никак не мог пройти мимо таких оскорбительных обвинений в адрес любимого языка программирования
Я уверен, что утечки памяти в таких очевидных местах были бы сразу замечены и пофиксены разработчиками компилятора.
Старый 13.04.2013 16:13 RealyUniqueName вне форума
RealyUniqueName
И ещё к слову о for() и кэшировании Array.length
Попробуйте это: http://try.haxe.org/#1d956
Старый 13.04.2013 16:22 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
во-первых, я ничего не пытался оскорбить.
во-вторых, я пишу на этом языке.
в-третьих, все тесты были сделаны для 1000 объектов, у которых по 29 детей, на 1 кадр все это обновляется, если вы очень хотите я покажу, когда Array<Dynamic> ведет себя отлично от nme.Vector при a[0] = 1, ... a[n] = n;
все выше написанное относится по-большей части к HaXe->Flash

и то, что я написал, это первая неделя флешера на HaXe.
Старый 13.04.2013 16:36 RealyUniqueName вне форума
RealyUniqueName
Я действительно прошу прощения, со мной иногда бывает.
Я понимаю, что вы ничего не хотели оскорблять, наверное, мне надо было как-то обозначить шутливую интонацию в последнем абзаце
Старый 13.04.2013 16:43 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
я описал часть разговоров и ситуаций, с которыми, возможно, столкнутся, флешеры пересевшие на HaXe, с след. статье, я выложу примеры кода HaXe->Flash, результаты скаута и байткод, а также варианты оптимайзов, и подходы к программированию, которые привычны для "хексера" и не очевидны для AS3 разработчика.

ps
@RealyUniqueName, и вы бы мне помогли в некоторых вопросах
Старый 15.04.2013 01:39 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Вот о чем еще имеет смысл написать - вещь не знакомая флешерам вообще - макросы (т.е. @:macro) - которые позволяют создавать свои синтаксические конструкции / расширения языка.
Я, увы, в последнее время никак до Хекса не доберусь но видел примеры.
Старый 15.04.2013 13:46 Dima_DPE вне форума
Dima_DPE
По макросам я могу много чего написать, есть опыт, есть примеры, но только если ктото возмется проверить грамматику и орфографию.
Старый 16.04.2013 00:00 RealyUniqueName вне форума
RealyUniqueName
Я готов проверить. 100% правильность не гарантирую, но в школе учился хорошо
Старый 16.04.2013 00:03 Dima_DPE вне форума
Dima_DPE
@RealyUniqueName договорились, правда смогу приступить только к концу недели. Спишемся в личке, чтобы ты меня гонял, иначе я забуду. Кстати уверен ты и сам в макросах варишь не слабо.
Старый 16.04.2013 00:16 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
мы тоже поможем
Старый 26.09.2013 10:25 morgenshtern вне форума
morgenshtern
 
Аватар для morgenshtern
А как сейчас дела со старлингом в nme?
Интересно бы портировать проект в haxe (под дроид/исо), сравнить производительность. Но отказываться перьев и скворцов не хотелось бы.
Старый 26.09.2013 11:49 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
есть extern starling под openfl, feathers можно подключить так же, но собирать приложение будет возможно только под flash таргет.
 

 


Часовой пояс GMT +4, время: 17:41.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.