Flex и RIA блоги
2014-04-21 |
Update: запись онлайн-встречи с Adobe 21 апреля прошла онлайн-встреча Adobe Flash Online Conference #9 (спасибо, Сергей Гончар)! Из Adobe участвовали Chris Campbell, Govinda Gupta, Romil Mittal, Ashok Mathew Kuruvilla и Cheng Liao. Появилась запись этой встречи: http://gonchar.me/blog/goncharposts/2279 |
Как отделить мух от колет? Рано или поздно любой flex-разработчик понимает, что нужно что-то сделать с собственным “винегретом” в коде, состоящим из mxml-разметки вперемешку с inline-кодом. А, собственно, что с ним не так? Если кратко, то:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" height="450"> <s:layout> <s:VerticalLayout/> </s:layout> <fx:Script> <![CDATA[ import spark.events.IndexChangeEvent; private function myChangedHandler(event:IndexChangeEvent):void { var selIndices:Vector.<int> = event.currentTarget.selectedIndices; var selItems:Vector.<Object> = event.currentTarget.selectedItems; var numItems:Number = selIndices.length; selIndicesTA.text = ""; selItemsTA.text = ""; for (var i:Number = 0; i<numItems; i++) { selIndicesTA.text = selIndicesTA.text + selIndices[i] + "\n"; selItemsTA.text = selItemsTA.text + selItems[i] + "\n"; } } ]]> </fx:Script> <s:List allowMultipleSelection="true" change="myChangedHandler(event);"> <mx:ArrayCollection> <fx:String>Flex</fx:String> <fx:String>Flash Builder</fx:String> <fx:String>Flash</fx:String> <fx:String>Director</fx:String> <fx:String>Dreamweaver</fx:String> <fx:String>ColdFusion</fx:String> </mx:ArrayCollection> </s:List> <s:Label text="Selected indices"/> <s:TextArea id="selIndicesTA" height="75"/> <s:Label text="Selected items"/> <s:TextArea id="selItemsTA" height="75"/> </s:Application>
Вместо того, чтобы пропагандировать “здоровое кодирование”, а также потому, что не смогла, Не будем о грустном. Так как же можно отделить просо от гречки? Если хорошо поискать, то Adobe предлагает следующие варианты:
<s:Button label="Convert" click="celsius.text=String(Math.round((Number(fahrenheit.text)-32)/1.8 * 10)/10);"/>
Много кода в инлайн обработчике не напишешь. Нельзя использовать операторы сравнения. Да и не похож этот вариант на разделение, скорее наоборот. Проходим мимо. Описывание кода в отдельном as файле ни к чему, кроме головной боли, не ведет. Как минимум, код в пустом (безо всяких package, class и тд) файле выглядит странно, запутывает и приводит в уныние, наверное, все современные IDE. Кто-нибудь сейчас так пишет? Получается, название статьи расходится с её содержанием. Зачем она нужна Вот мы все ругаем Adobe за Flex. Так ведь да, в один прекрасный момент она сама это поняла и переписала часть фреймворка, как надо. Ввела новый жизненный цикл компонентов и отделила логику/поведение компонентов от их внешнего вида и увеличила цифру у фреймворка аж до 4.00. Можно даже почитать, как правильно готовить такие компоненты. Переписать все компоненты сил не хватило, теперь этим занимается Apache Foundation. Что же делать? И как быть? Наверное, многие уже поняли, к чему я клоню, и вспомнили о старом, добром CodeBehind-е. Идея этого архитектурного паттерна проста: всю бизнес-логику пишем на чистом as3 (базовый класс), а расположение и внешний вид контролов, описываем, используя mxml-разметку. Все контролы, которые будут использоваться в коде, должны иметь id и быть описаны в базовом классе как публичные переменные с соответствующим типом. Звучит страшно, но на самом деле все просто. Рассмотрим пример: // BaseControlPanel.as public class BaseControlPanel extends Group { public var stopButton : Button; public var startButton: Button; public function BaseControlPanel() { super(); } /** * @inheritDoc */ override protected function createChildren():void { super.createChildren(); stopButton.addEventListener(MouseEvent.CLICK, onStopButtonClicked); } /** * Обработчик клика по кнопке старт * @param e */ protected function onStartButtonClicked(e:MouseEvent):void { trace("Start"); } /** * Обработчик клика по кнопке стоп * @param e */ private function onStopButtonClicked(e:MouseEvent):void { trace("Stop"); } } // ControlPanelView.mxml <?xml version="1.0"?> <local:BaseControlPanel xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*" xmlns:layouts="spark.layouts.*" xmlns:components="spark.components.*"> <local:layout> <layouts:HorizontalLayout paddingLeft="5" paddingTop="5"/> </local:layout> <!-- Кнопка запуска --> <components:Button id="startButton" label="start" click="onStartButtonClicked(event)"/> <!-- Кнопка остановки --> <components:Button id="stopButton" label="stop"/> </local:BaseControlPanel> В приведенном примере мы видим два варианта подписки на событие клика по кнопке. Стоп-кнопку мы подписываем на клик mxml файле. Для этого необходимо, чтобы обработчик события был виден, т.е. был либо protected либо public. Старт-кнопку мы подписываем в createChildren, сразу после того, как она создастся. Оба варианта приемлемы. Вариант с подпиской в разметке, как нам кажется, короче, но не так универсален. Если нам нужно будет создать еще один вариант разметки, нам придется еще раз подписывать кнопку на это событие, что избыточно и легко может привести к ошибке, если мы забудем это сделать. С другой стороны, если нам нужно подписаться на это событие не сразу, или подписать вообще другой компонент (который также может послать это событие), то сделать это без изменения as3 кода не получится. А так как именно эту проблему мы и решаем, то вариант с подпиской на событие в разметке в данном случае подходит лучше. Используем тот вариант, который решает нашу задачу лучше. Таким образом, мы частично решили поставленные в начале статьи задачи, и даже получили некоторые другие преимущества:
Но, как и у любого другого шаблона, у CodeBehind есть не только плюсы, но и минусы:
Другим вариантом реализации отделения логики от разметки является приём, называемый CodeFront (или code in front). Идея его (вы наверное и сами догадались) так же проста и кристальна, как и в случае с CodeBehind, и заключается в том, что сначала мы реализуем расположение компонентов, и только потом наполняем их жизнью (добавляем логику). Пример: // BaseControlPanelView.mxml <?xml version="1.0"?> <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*" xmlns:layouts="spark.layouts.*" xmlns:components="spark.components.*" xmlns:s="library://ns.adobe.com/flex/spark"> <!-- /** * Внешний вид панели управления * Created 18.04.2014 * Version 1.0 * Copyright (c) 2014 * @author ChessMax (www.chessmax.ru) */ --> <s:layout> <layouts:HorizontalLayout paddingLeft="5" paddingTop="5"/> </s:layout> <!-- Кнопка запуска --> <components:Button id="startButton" label="start"/> <!-- Кнопка остановки --> <components:Button id="stopButton" label="stop"/> </s:Group> // ControlPanel.as public class ControlPanel extends BaseControlPanelView { public function ControlPanel() { super(); } /** * @inheritDoc */ override protected function createChildren():void { super.createChildren(); startButton.addEventListener(MouseEvent.CLICK, onStartButtonClicked); stopButton .addEventListener(MouseEvent.CLICK, onStopButtonClicked); } /** * Обработчик клика по кнопке старт * @param e */ protected function onStartButtonClicked(e:MouseEvent):void { trace("Start"); } /** * Обработчик клика по кнопке стоп * @param e */ private function onStopButtonClicked(e:MouseEvent):void { trace("Stop"); } } Используя CodeFront, нам больше нет необходимости описывать все необходимые переменные в классе, чтобы использовать их в логике. Так как мы наследуемся от mxml-разметки, то компилятор делает это за нас. Но теперь мы лишены возможности назначить обработчик события inline-внутри mxml-разметки, так как описан он будет только в наследнике. Также нет возможности полностью заменить layout получившегося компонента, по понятным причинам. Да и перенести логику в другой проект без layout-а теперь не получится. Возможно, поэтому этот вариант гораздо менее популярен, чем CodeBehind. Заключение. CodeBehind/CodeFront - архитектурный прием, который позволяет относительно легко сделать код чистым и структуированным, что легко дает возможность модифицировать его в будущем. Хотя поначалу довольно непросто привыкнуть писать код так, и это сильно раздражает. Даже кажется, что мы делаем слишком много дополнительной работы. Но, как говорится, стоит только начать, а уж когда втянетесь… Становится легче абстрагировать логику от разметки. Гораздо легче наследоваться от чистых AS3 классов, нежели от MXML классов с необходимостью изменять layout. Попробуйте один из перечисленных приемов в своем проекте. И обязательно оставляйте комментарии о своем положительном/отрицательном использовании перечисленных техник. Почитать: Code Behind |
2014-04-18 |
Александр Письменчук - Flash ActionScript 3 разработчик Ищу постоянную работу в компании с полной занятостью Мое резюме: Кто я:
ActionScript 3 разработчик. Flash занимаюсь с 12.2008 по наст. время (более 5 лет)
На данный момент работаю на фриланс биржах
Чем я занимаюсь:
Программирование функционала flash/air компонентов, сайтов, интерактивов. Больше скажет портфолио.
Портфолио: http://fl.ru/
Все работы: http://www.weblancer.net/
Что я ищу:
Работу в г.Киеве. Достойную оплата, интересный проект (не игровой), слаженный коллектив, удобное рабочее время, бесплатные печеньки :). Плюсом будет считаться помощь при переезде или поиске жилья
Основные навыки:
ActionScript, OOP, Air Desktop
Дополнительные навыки можно узнать по запросу
Достежения:
Интерактивы для Winston, Camel, Dirol, Vertu. Volvo, игры для FixiClub, Nestle
Знание языков:
Английский - начальный, Русский - продвинутый, Украинский - родной
Мои контакты можно посмотерть на сайте http://alexvoz.net/
Минимальная зарплата: $2000 Максимальная зарплата: $2500 |
Кефирам нужен человек в Киеве Kefir Games (тюряга) ищет Требования:
Компания дает хорошую зарплату и там есть куда расти |
2014-04-15 |
Generic Animation Format и оптимизация Adobe AIR: записи докладов 12 апреля в Харькове прошел UAFPUG №46. Доклады были записаны на видео:
Важно: по горячим следам Антон сделал разбор полетов к собственному докладу про AIR. Также во время доклада мы долго обсуждали оптимизацию списков в Adobe AIR, и один из наших онлайн-слушателей, Виталий Кононец прислал ссылку на свой блог по теме: Оптимизация списков в мобильном приложении. Спасибо, Виталий! Фото с UAFPUG-46:Вадим Митин вкратце рассказывает о разработке Generic Animation Format: Нас было немного: Но интересно: Баги Flash IDE достали!На встрече мы собрали список самых назойливых багов Adobe Flash IDE. Причешем его и устроим витруальный майдан Адобу. Присылайте свои жалобы на Flash в комменты или на мою почту rostislav.siryk. Спасибо всем, кто пришел и был с нами онлайн! Гду будет следующий фпуг?Следующая встреча пройдет в городе, жители которого первыми предложат два доклада. Прошу писать в комменты или на почту выше: кто о чем хочет рассказать. Указывайте город. Люблю вас!
|
2014-04-12 |
Агентство помощи социальным стартапам, Киев AIN сообщает о новом проекте помощи социальным стартапам от организаторов IT-палатки. Этот проект называется "Украинское агентство стратегических инициатив" и будет помогать стартапам, делающим социальные или коммерческие проекты для развития Украины. Об этом рассказал один из инициаторов создания организации Юрий Чайка (MoneXy). Под такие проекты практически невозможно найти инвестора, так как они, в основном, неприбыльные. В поле зрения организаторов уже около 200 подобных проектов. Агентство планирует помогать стартапам в привлечении инвестиций, юридическом оформлении, работе с государственными органами, консультациях и т.д. Это — неприбыльная организация, которая финансируется через краудфандинг (презентация агентства). «После Майдана многие компании и граждане хотят участвовать и поддерживать социальные проекты», — поясняет Юрий Чайка. |
Трансляция доклада "Оптимизация Adobe Air для мобильных устройств"UPDATE: записи докладов из онлайн-трансляции:
======================= Идет онлайн-трансляция доклада:
"Оптимизация Adobe Air для мобильных устройств"
|
UAFPUG #46 - онлайн-трансляция Присоединиться к конференции UAFPUG-46 в Харькове онлайн можно здесь: http://adobechats.adobeconnect.com/uafpug-46/ UPDATE: записи докладов из онлайн-трансляции:
|
2014-04-08 |
Вышел Adobe AIR SDK 13Новое в Adobe AIR 13:
Ссылки: Обсуждать возможности новой версии Adobe AIR, а также оптимизацию созданных на Adobe AIR мобильных приложений будем на конференции UAFPUG#46 в Харькове. Готовьте вопросы, а лучше задавайте их прямо здесь в комментариях. Важно: Регистрирация на UAFPUG#46 Тэги: |
2014-03-25 |
Unity Night Odessa — пост гордости за Одессу и Юнити 22 февраля в Одессе прошла "Ночь Юнити" — Unity Night. Были докладчики из Дании и Финляндии. Участие приняли более 100 человек. Краткий обзор того, о чем говорили: Building Quality (Unity3D)Это выступление было посвящено, что мы делаем, чтобы сделать Единство удивительным, давая обзор тестировщиков и инструменты, которые мы используем в нашей изо дня в день работы. Наш подход к ручного тестирования было также упомянуто, подчеркивая тест как творческий и сложной ремесла. Мы также говорили о роли нашего сообщества в построении качественный продукт. Unity Test ToolsЭтот доклад был посвящен созданию игры с гидом по тестам. Это не тривиальная задача, особенно при работе с кодовыми базами, которые не были разработаны с тестируемости в виду. Ведущие обратил на собственном опыте и лучших практиках автоматизации тестирования, и дал демонстрацию недавно выпущенных Unity Test Tools. Automated performance regression testingСекреты производительности регрессионного тестирования. Показано, какие данные собирают тесты производительности, как они используются для идентификации регрессий. Дискуссии продолжились на афтепати. Это была первая ночь Юнити в Одессе и она удалась! Теперь про политику:Флэш Потрошитель будет писать о важном. Важное во флэше — пишем. Важное про Юнити — пишем. Важное про HYML5/JS — пишем. UAFPUG №46Следующая встреча состоится 12 апреля в Харькове. Готовимся. |
2014-03-24 |
Отличия event.target и event.currentTarget У многих новичков as3 возникает вопрос: в чем разница между свойствами targetи currentTargetобъекта события? А разница в следующем. Свойство currentTargetсодержит объект, на которого была совершена подписка (у которого вы вызывали addEventListener). В свою очередь свойство targetсодержит объект, который непосредственно рассылает событие. Посмотрим отличия на примере. Пусть у нас есть подложка cover:Spriteи и несколько кнопок, расположенных на этой подложке. Мы подписываемся на клик по подложке cover.addEventListener(MouseEvent.CLICK, onClick); и обрабатываем событие в слушателе private function onClick(event:MouseEvent):void { // обработка события } Когда пользователь кликает по любой из кнопок, добавленных на cover, вызовется функция onClick(). При этом в event.currentTargetвсегда будет ссылка на cover, вне зависимости от того, на какую из кнопок он кликнул. А вот свойство event.targetкак раз будет содержать ссылку на конкретную кнопку, по которой произошел клик. ПримечаниеОбратите внимание, что в рассмотренном примере имеется ввиду, что сами кнопки не имеют интерактивных вложенных детей и на мышь реагирует только сама кнопка (например, выставлено button.mouseChildren = false;). Вот и всё. Если остались вопросы – прошу задавать в комментариях, это очень поможет улучшить и оптимизировать пост. Не забудьте также ознакомиться с документацией по ActionScript3 |
2014-03-23 |
Разрешить безвизовое посещение США на срок до 90 дней На официальном сайте Белого Дома размещена петиция о том, чтобы позволить гражданам Украины безвизовое посещение США длительностью до 90 дней. Прогресс неплохой: вчера до 100 000 подписей нам не хватало 22 000, а сегодня -- уже всего 12 000. Но и дедлайн недалек: 28 марта 2014. Возможно, вы захотите подписать петицию и распространить ссылку на нее: https://petitions.whitehouse.gov/petition/allow-ukrainian-citizens-90-da... |
2014-03-06 |
Политическая информация Тэги: |
2014-03-03 |
Русские в Украине. Нужна ли им помощь Путина? Внимание: текст написал моим другом. Публикую без изменений. Рост. Меня зовут Андрей Ткачук. Я живу на Украине. Многие из вас знают меня как разработчика популярного менеджера управления делами: http://mylifeorganized.net
Но сегодня речь пойдет не об этом. Речь пойдет о том,что происходит в Украине и почему Россия, пытаясь “помочь”, на самом деле мешает и разрушает мою обновленную страну. И почему я не могу промолчать.
О себе: Я русский, родился в Свердловске (Екатеринбурге), прожил 15 лет на севере России в Норильске, где окончил школу с серебряной медалью. В Харьков приехал учиться на программиста. Закончил с красным дипломом, потом была аспирантура, написал диссертацию. Женился, остался жить в Украине и считаю ее своей страной. В Екатеринбурге живет мой родной брат и родственники.
Я почти не говорю по-украински, хотя хакеры, которые давно пытаются взломать мой продукт, часто называют меня “жадным хохлом”.
Теперь, когда вы поняли, что я не “бандеровец”, позвольте мне рассказать о том, что происходит здесь в Украине, как говорится, из первых уст.
Российское телевидение - информационная война с Украиной По моим личным наблюдениям, федеральные каналы Российского ТВ, перекручивая и даже подтасовывая факты ведут жесткую информационную войну вместо предоставления объективной информации. Цель: создать общественное мнение в России и в русскоговорящих областях Украины, о необходимости “срочной помощи” со стороны России, чтобы спасти нас от “бесчинств бандеровцев” и ввести войска.
Жертвами этой отлично организованной компании стали не только россияне но и некоторые жители Украины которые теперь боятся “бандеровцев”. Но даже они очень настороженно отнеслись к вводу российских войск в Крым.
Я понимаю, что многим Россиянам трудно поверить, что им врут. Ведь вы думаете, что вам показывают голые “факты”. Но вам действительно врут. Я раскрою вам страшную тайну - нет полчищ “бандеровцев”, которые нас терроризируют.
Что происходит в Украине на самом делеЯ с полной ответственностью заявляю, что нам, русскоговорящим украинцам, не нужна помощь России. Мы сами разберемся. За все время моей жизни здесь я НИ РАЗУ не почувствовал себя ущемленным. Я объездил всю Украину от Львова до Днепропетровска. Ни один мой знакомый (а их у меня очень много) не чувствовал себя ущемленным. За все время революции я лично не испытывал никаких притеснений. Мало того, мои знакомые, которые говорят только на русском, участвовали в Майдане в Киеве. Я очень внимательно следил за ситуацией из разнообразных источников и могу уверенно сказать - нет проверенных фактов ущемления русскоговорящих жителей Украины.
Что произошло в феврале 2014, если коротко: Народ сбросил власть бандитов. Другого способа не было. Выборы фальсифицировались. Судьи боялись выносить честные приговоры. В милиции пытали. Бизнес моих друзей отбирали. Страна превращалась в феодальное государство с крупными монополистами и их рабами. Все работали на Семью Януковича. Этим летом (за 3 месяца до Майдана!) во двор нашего многоквартирного дома заехали джипы без номеров, и молодчики на глазах у играющих детей битами и кувалдами разбили все клумбы с цветами во дворе, которые жильцы решили поставить, чтобы ограничить количество машин и чтобы было где играть детям. Милиция отказалась искать виновников. Так мы и жили в нашей стране с ощущением несправедливости и беспомощности. До февраля 2014.
Конечно, после революций трудно сразу установить порядок. Конечно, отмена "языкового" закона была неуклюжей ошибкой правительства (и она уже исправлена). Конечно, есть группы радикалов, но они есть везде, и не они задают законы поведения общества. Напомню, преследований русских — не было, ни одного.
После первоначального хаоса очень быстро все начало налаживаться. Например, здравомыслящие люди в сети начали самоорганизовываться, объединяться в виртуальные комитеты и строить новую страну. Выдвигались идеи. Изучался Грузинский опыт реформы силовых структур. Люди воспряли духом! Люди почувствовали весну (помните Пражскую весну? не прослеживаете аналогий?)
И тут — ввод российских войск. Шок. Я считаю, что Путин после потери влияния в Украине решил разыграть Крымскую карту. Конечно, ущемление русских это ложь, чтобы оправдать агрессию. Почему Россией не было предпринято действенных ПОЛИТИЧЕСКИХ шагов по урегулированию ситуации, начиная с декабря? Почему перед вводом войск не было консультаций с действующим правительством Украины? Цель Путина не в защите русских, и все здесь это понимают. Но цена этих политических игр может быть очень высока. Ценой может быть ВОЙНА! Я считаю, что Россия сейчас цинично убивает мою страну - доведенную до дефолта Януковичем и растерзанную, неокрепшую, но возрождающуюся после революции. Более того, Кремль превращает русских в агрессоров, вторгшихся на территорию суверенного государства. Вдумайтесь: русский народ — захватчик? В глазах всего мира? Это станет черным пятном в истории России!
Крестный отец моего сына стоял на баррикадах и видел смерть. Он адвокат и владелец компании, которая консультирует частных предпринимателей. Он просто больше не мог терпеть того, что происходило в стране. Другие мои знакомые сейчас стоят в Харькове около памятника Ленину, защищая его от “бандеровцев”. Да общество разделилось. Но я считаю, что мы сможем договориться сами. Нам не нужен для этого Путин. Мы его не звали. Я говорю это как русскоязычный гражданин Украины.
Как лично Вы можете нам помочь? И теперь самое важное. Я очень рассчитываю на помощь своих российских коллег. Прошу вас, попробуйте противостоять пропаганде телевидения. Допустите мысль, что на самом деле все может обстоять по-другому. Найдите источники объективной информации (ниже я приведу несколько ссылок). Распространите эту информацию среди Ваших друзей.
Почему это важно? Да потому что игры закончились. Потому что возможно это самый важный проект моей жизни - хоть как то помочь предотвратить эту войну. Да просто потому, что я не хочу стрелять в своего брата из Екатеринбурга из-за игр политиков!!!
Вы можете задать мне вопросы на этом форуме: http://www.mylifeorganized.net/forum-ru/
P.P.S. Ссылки для тех , кто хочет узнать правду:
Андрей Макаревич о войне с Украиной: Борис Гребенщиков: Будьте дальновидны: перестаньте натравливать одних людей на других. и Дорогая редакция телеканала Россия 24.
Помогите донести правду и остановить войну!
|
2014-02-11 |
Unity3D обзор Unity3D – один из самых популярных, кроссплатформенных движков для разработки игр. Что же в нем такого особенного и чем вызвана такая популярность этого движка.
Из всего вышеперечисленного можно сделать вывод, что движок, как нельзя лучше подходит для небольших команд и инди-разработчиков. Впрочем, крупные компании тоже не обделяют Unity вниманием. Что подтверждает долгосрочный контракт Unity Technologies с Electronic Arts (есть уже и плоды – Need for Speed: World, а так же проект EA SPORTS). О производительности и “красивости графики” говорить не буду. Это довольно спорный вопрос, здесь все больше зависит от прямоты рук, профессионализма моделлеров и дизайнеров. В сети много холиваров по поводу того, кто круче CryEngine, UDK или Unity3D, не будем начинать еще один. В любом случае уровень графики приличный. Что, на мой взгляд, несколько нелогично в Unity – это работа с GUI, собственно это то, что я не могу визуально построить окно с кнопками, чекбоксами и прочим. Создавать их возможно только программно. С одной стороны это нормально и даже более привычно. Но кажется мне не совсем логичным, то, что строить трехмерные миры я могу тыкая мышкой, а чтобы собрать какую-нибудь пресловутую панельку с кнопочками надо написать пару десятков строк кода. Пока этот момент решается установкой дополнительных плагинов, будем надеяться, что в будущем прикрутят к редактору по умолчанию. Так же непривычно отсутствие главного класса проекта, так сказать точки входа, и скрипты вешаются непосредственно на объекты. Учитывая, что работа идет с префабами назвать это минусом нельзя, но подход, однако, своеобразный. Из минусов не могу не подметить, что с движком идет очень скудный набор префабов, текстур и скриптов. Я понимаю, что каждая игра уникальна со своими моделями и прочим, но хотя-бы травы, деревьев и текстур земли можно было добавить и побольше, чем по две. Да и, скажем, скрипт симулирующий физику движения транспорта не помешал бы. Зато у нас есть обширный магазин ассетов, доступный прямо из редактора (меню Window -> Asset Store), в котором можно как купить себе готовые вещи, так и выставить свое на продажу. Ну, и что мне режет глаз, это лапша из разношерстного кода. Вот пример, открываю Unity, кидаю на сцену стандартный компонент First Person Controller. И что я вижу, на нем висит три скрипта:
Что это за солянка, половина на JS, вторая на C#, хорошо хоть на Boo нет. Писали бы уж все на одном языке или дублировали, раз движок позиционируется как мультиязычный. Кстати о JavaScript, он тут немного “не тот”, что мы привыкли видеть в браузере. В Unity3D js более “продвинутый” и похож больше на ActionScript. Хотя они все одного поля ягоды, так что проблем с этим возникнуть не должно. И не стоит полагать, что раз JavaScript, то будет все тормозить, как в IE. Скорость исполнения на достойном уровне, хотя и немного проигрывает скриптам на шарпе. Подытожим вышесказанное. Unity3D качественный, мощный игровой движок. Свои недостатки, которых не так уж и много, правят быстро. Еще года два назад их было куда больше. |
2014-02-03 |
Получение минимального или максимального числа из массива Пусть у нас есть массив чисел var numbers:Array = [2, 7, 4, 9, 12, 6, 13, 19]; и стоит задача найти максимальное или минимальное число из тех, которые находятся в этом массиве. Первое что приходит на ум, это перебрать массив и найти элемент с максимальным (минимальным) значением. Но есть и другой путь.
Все знают функции Math.min()и Math.max(), которые используются для оценки переданных аргументов и определения минимального и максимального из них. Эти функции могут принимать несколько аргументов. Вспомнив, как работает метод apply()у Functionлегко додуматься до следующего способа нахождения минимального и максимального числа из массива: var min:Number = Math.min.apply(null, numbers); var max:Number = Math.max.apply(null, numbers); Это неплохой способ сократить код, такая запись намного короче перебора в цикле. Но остаётся ещё один вопрос — производительность. Тест производительностиСравним Math.min()с реализацией перебором: var min:Number = NaN; var i:uint; var num:Number; var count:uint = numbers.length; for (i = 0; i < count; ++i) { num = numbers[i]; if (isNaN(min) || min > num) min = num; } Массив чисел сгенерирован случайным образом и содержит 20 элементов, поиск элементов выполняется 1000000 раз. Итак, результаты: Numbers: 128,-332,-280,-250,-89,328,91,-279,163,-141,-186,-187,98,-18,-102,-363,-161,-338,-7,342 [Math.min()] Result: -363 Time: 992 ms [for(;;){ }] Result: -363 Time: 7266 ms Как видно, минимум оба метода выдают одинаковый, но реализация перебором при этом работает медленнее. Отмечу, что с увеличением размера массива разница увеличивается. Это логично, ведь при использовании Math.min()перебор элементов происходит нативно, внутри FlashPlayer’а и можно было предположить что такой перебор быстрее цикла в as3. Таким образом мы имеем более простой и более быстрый метод нахождения минимального или максимального значения в массиве чисел. В конце полезные ссылки: |
2014-01-29 |
Ну все, я понял Ищут эйчары, ищут рекрутеры, ищут не могут найти. А я найду. Пишите мне на rostislav.siryk жимейловый. Вилка зарплат -- острая, с четырьмя зубцами. |
2014-01-27 |
Правая и средняя кнопки мыши во flash Доброго дня! Как оказалось, несмотря на то, что у flash-разработчиков уже довольно давно появилась возможность полноценно и без костылей использовать правую и среднюю кнопки мыши, многие попросту пропустили эту новость. Начиная с версии Flash-плеера 11.2 появилось несколько новых событий мыши:
И небольшой пример использования: package { import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Main extends Sprite { private var _container:Sprite; public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { _container = new Sprite(); _container.graphics.beginFill(0xF2F2F2, 1); _container.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight); _container.graphics.endFill(); _container.x = _container.y = 0; addChild(_container); _container.addEventListener(MouseEvent.CLICK, clickHandler); _container.addEventListener(MouseEvent.RIGHT_CLICK, rightClickHandler); _container.addEventListener(MouseEvent.MIDDLE_MOUSE_DOWN, middleDownHandler); _container.addEventListener(MouseEvent.MIDDLE_MOUSE_UP, middleUpHandler); } private function clickHandler(e:MouseEvent):void { var sprite:Sprite = new Sprite(); sprite.graphics.beginFill(0x000000, Math.random()); sprite.graphics.drawCircle(0, 0, 10 + Math.random() * 10); sprite.graphics.endFill(); sprite.x = mouseX; sprite.y = mouseY; _container.addChild(sprite); } private function rightClickHandler(e:MouseEvent):void { if (e.target != _container) _container.removeChild(e.target as DisplayObject); } private function middleDownHandler(e:MouseEvent):void { if (e.target != _container) e.target.startDrag(); } private function middleUpHandler(e:MouseEvent):void { if (e.target != _container) e.target.stopDrag(); } } } (ЛКМ – добавление объекта, ПКМ – удаление объекта, СКМ – перетаскивание объекта) |
2013-12-06 |
Жизненный цикл Spark компонентов Flex фреймворка и базовые правила наследования компонентов Для правильной работы со Spark компонентами и создания собственных компонентов, необходимо иметь понятие о том, как и по каким правилам они работают. Сегодня мы рассмотрим базовые принципы, без знания которых невозможно эффективно использовать этот мощный фреймворк. Итак, жизненный цикл каждого компонента во Flex фреймворке проходит следующие этапы:
Когда мы добавляем компонент с помощью mxml разметки <local:MyComponent fontSize="12" width="100"/> происходит следующее. Сначала запускается этап создания, и инстанциируется экземпляр класса MyComponent. Затем происходит конфигурация, в течение которой компоненту выставляются свойства и стили, объявленные при добавлении компонента (применяются они позже). Пока внутри компонента не доступны свойства private var _data:Object; private var _dataChanged:Boolean; private function set data(value:Object):void { if (this._data !== value) { this._data = value; this._dataChanged = true; this.invalidateProperties(); } } Теперь движемся дальше (до применений изменений мы дойдем чуть позже). Наступает этап подключения, в котором компонент добавляется на сцену, после чего происходит инициализация. Инициализацию рассмотрим подробнее. Фазы инициализации:
При переопределении метода private var _okButton:Button; override protected function createChildren():void { if (this._okButton === null) { this._okButton = new Button(); this._okButton.label = 'OK'; this._okButton.addEventListener(MouseEvent.CLICK, this.okButton_clickHandler); } this.addChild(this._okButton); super.createChildren(); } После того как компонент инициализирован, наступает этап инвалидации. Компоненты Flex фреймворка используют отложенную валидацию изменений. Аналогично как мы делали выше с полем
Для применения изменения свойств будет вызван метод override function protected commitProperties():void { super.commitProperties(); if (this._dataChanged) { this._dataChanged = false; // Применение изменения поля this._data } } Отметим, что, так как валидация происходит после инициализации, то в методе При валидации размеров будет вызван метод override protected function measure():void { var i:uint; var count:uint; var w:Number; var h:Number; var child:UIComponent; w = 0; h = 0; count = this.numChildren; for (i = 0; i < count; ++i) { child = this.getChildAt(i) as UIComponent; if (child !== null) { w = Math.max(w, child.getExplicitOrMeasuredWidth()); h += child.getExplicitOrMeasuredHeight(); } } measuredWidth = w; measuredHeight = h; measuredMinWidth = w; measuredMinHeight = h; } Валидация размеров вызывает метод По окончании инвалидации рассылается событие « Когда компонент уже не нужен – он удаляется со сцены (методами удаления или выставлением флага Полезные ссылки
|
2013-11-29 |
Неожиданный null в JavaScript Моей задачей было изменить поведение следующего JS-кода и я долго изучал первую строку, пытаясь понять ее логику: Логика там была неслучайная: в истории файла было видно, что ее успешно и бережно изменяли до меня много раз. Изучая это выражение, я понял, что не понимаю настоящего (и задокументированного) поведения null в условных выражениях JavaScript. И про сами эти выражения. В итоге была проведена серия тестов в консоли браузера. Она показана ниже. Предлагаю вам попытаться предсказать, каково значение каждого из приведенных выражений. Т.е. что появится в консоли, если вводить эти выражения построчно и жать Enter: Ответы -- под катом: null && true: Кстати! На мастер-класс по Away3D / TypeScript / WebGL в Киеве осталось уже всего 3 билета по $75. Потом будут по $100. |
Изометрическая проекция с использованием библиотеки as3isolib Что такое изометрия, простым, человеческим языком, – это псевдо трехмерная проекция, при которой все объекты повернуты к нам под углом в 45 градусов, так, что мы видим три стороны фигуры. При этом масштаб фигур не изменяется в зависимости от их удаленности. Доступных к общему пользованию изометрических движков на AS3 на самом деле не так уж и много, можно пересчитать на пальцах и двух рук хватит. Расскажу про один из них – as3Isolib. Библиотека с открытым исходным кодом. Легко допиливается под свои нужды. Глюков особо замечено не было. Скоростью, правда, не хвастается, но и жутко не тормозит. В либе присутствует только базовый функционал по отображению и сортировке, все прочие навороты придется допиливать самому. Из недостатков могу подметить, что последнее обновление на Google Code было в 2010 году. Скачать саму либу можно здесь. Итак как ее использовать. весь “изометрический мир” представляет собой одну (для простых проектов) или несколько изометрических сцен package { import as3isolib.display.IsoView; import as3isolib.display.scene.IsoGrid; import as3isolib.display.scene.IsoScene; import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // Создаем вьюпорт var view:IsoView = new IsoView(); // Задаем ему размеры равные нашей флешке view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(view); // Создаем изометрическую сцену var scene:IsoScene = new IsoScene(); // Добавляем сцену во вьюпорт view.addScene(scene); // Для наглядности добавим на сцену сетку scene.addChild(new IsoGrid()); // Рендерим сцену scene.render(); } } } Собственно сетку В библиотеке присутствуют стандартные примитивы например package { import as3isolib.display.IsoSprite; import as3isolib.display.IsoView; import as3isolib.display.primitive.IsoBox; import as3isolib.display.primitive.IsoHexBox; import as3isolib.display.scene.IsoScene; import as3isolib.graphics.SolidColorFill; import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // Создаем вьюпорт var view:IsoView = new IsoView(); // Задаем ему размеры равные нашей флешке view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(view); // Создаем изометрическую сцену var scene:IsoScene = new IsoScene(); // Добавляем сцену во вьюпорт view.addScene(scene); // Создаем примитив IsoBox var box:IsoBox = new IsoBox(); // Устанавливаем ему размер (ширина, длина, высота) box.setSize(50, 50, 50); // Добавляем его на сцену scene.addChild(box); // Создаем примитив IsoHexBox var hexBox:IsoHexBox = new IsoHexBox(); // Задаем ему размер hexBox.setSize(50, 50, 40); // Перемещаем его (x, y, z) hexBox.moveTo( -50, 0, 0); // Зальем его красным цветом, чтоб не сливался с коробкой hexBox.fill = new SolidColorFill(0xFF0000, 1); // Добавляем на сцену scene.addChild(hexBox); // Создаем контейнер IsoSprite var sprite:IsoSprite = new IsoSprite(); // Добавлем в него спрайты (массив DisplayObject'ов) sprite.sprites = [new Tree()]; // Задаем размеры контейнера sprite.setSize(50, 50, 50); // Перемещаем его sprite.moveTo(60, 25, 0); // И добавляем на сцену scene.addChild(sprite); // Рендерим сцену scene.render(); } } } О чем здесь следует сказать. Устанавливать размеры объекта ( Перемещать объекты по изометрической сцене не сложнее, чем по обычной, у всех изометрических объектов имеются методы package { import as3isolib.display.IsoSprite; import as3isolib.display.IsoView; import as3isolib.display.primitive.IsoBox; import as3isolib.display.primitive.IsoHexBox; import as3isolib.display.scene.IsoGrid; import as3isolib.display.scene.IsoScene; import as3isolib.geom.Pt; import as3isolib.graphics.SolidColorFill; import eDpLib.events.ProxyEvent; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Main extends Sprite { private const GRIDSIDE:int = 25; private const GRIDSIZE:int = 10; private var _view:IsoView; private var _scene:IsoScene; private var _box:IsoBox; private var _hexBox:IsoHexBox; public function Main():void { // Создаем вьюпорт _view = new IsoView(); // Создаем изометрическую сцену _scene = new IsoScene(); // Создаем примитив IsoBox _box = new IsoBox(); // Создаем примитив IsoHexBox _hexBox = new IsoHexBox(); if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // Задаем вью размеры равные нашей флешке _view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(_view); // Добавляем сцену во вьюпорт _view.addScene(_scene); // Устанавливаем примитиву IsoBox размер (ширина, длина, высота) _box.setSize(GRIDSIDE, GRIDSIDE, GRIDSIDE); // Добавляем его на сцену _scene.addChild(_box); // Задаем примитиву IsoHexBox размер _hexBox.setSize(GRIDSIDE, GRIDSIDE, GRIDSIDE); // Перемещаем его (x, y, z) _hexBox.moveTo(GRIDSIDE*2, 0, 0); // Зальем его красным цветом, чтоб не сливался с коробкой _hexBox.fill = new SolidColorFill(0xFF0000, 1); // Добавляем на сцену _scene.addChild(_hexBox); // Создаем сетку var grid:IsoGrid = new IsoGrid(); // устанавливаем ей размер grid.setGridSize(GRIDSIZE, GRIDSIZE, 0); // сдвигаем на 100 пикселей для удобства grid.moveTo( -100, -100, 0 ); // добавляем ее на сцену _scene.addChild(grid); // Рендерим сцену _scene.render(); // вешаем слушатель клика на сцену _scene.addEventListener(MouseEvent.CLICK, handlerClick); } private function handlerClick(e:ProxyEvent):void //ловим клики { // Преобразуем координаты клика из экранных в изометрические var pt:Pt = _view.localToIso(new Pt(stage.mouseX, stage.mouseY)); // Округляем точку x по клетке pt.x = Math.round(pt.x / GRIDSIDE) * GRIDSIDE; // Округляем точку y pt.y = Math.round(pt.y / GRIDSIDE) * GRIDSIDE; // Перемещаем примитив Box в новые координаты _box.moveTo(pt.x, pt.y, pt.z); // рендерим сцену _scene.render(); } } } Как можно увидеть я беру не точные координаты клика, а округленные до ближайшего кратного Ну вот впрочем и все, остальное дело техники, переписывать сюда документацию особого смысла не вижу. Вводный экскурс по использованию библиотеки я вам дал, те кто заинтересуется может продолжить изучение либы в доках и ее исходниках. |
2013-11-28 |
TypeScript + WebGL = веб-версия Away3D без боли JavaScript'а Как известно, бум насыщенных веб-приложений разбудил интерес больших и маленьких компаний к интерактивно-медийному вебу. Все вспомнили о JavaScript, но писать на нем готовы далеко не все. Ведь по-человечески хочется делать, как на AS3, Java или C#. Поэтому хакеры и целые компании стали выпускать свои расширения (а иногда и сужения) для слишком уж динамичного JS. Одно из них -- TypeScript от Microsoft. Это полноценный язык программирования, обладающий двумя важнейшими характеристиками (помимо многих других достоинств):
Поддержка TypeScript уже есть во многих IDE, от Visual Studio и Eclipse до Sublime Text. А пару недель назад вышел COLT с поддеркой TS! Язык простой и эффективный, и этот потенциал заметили в Лондоне. Так появился он: Away3D TypeScript 4.1Еще в начале 2013 года Away Foundation начала делать Away3D.ts, то есть TypeScript-версию своего движка Away3D. А 9 октября -- результат: вышел Away3D Typescript 4.1 Alpha, популярный трехмерный движок, портированный в JavaScript / WebGL / HTML5. Примеры: typescript.away3d.com. Что это дает знающему ActionScript3?Это быстро обезбаливает. Правильно поставленное изучение TypeScript делает очевидной схожесть с AS3. Тут же можно освоить создание трехмерных веб-приложений и овладеть юной фишкой нового веба, трехмерной и от этого очень выпуклой -- WebGL. И можно забыть о том, как резал глаза дикий JavaScript: здесь все будет знакомо! Синхронное погружение в TypeScript и WebGL в реальном времени 6 декабря 2013 года, через неделю, в Киеве пройдет платный мастер-класс по Away3D TypeScript от его автора (Роба Бейтмана из Лондона), на английском языке с возможностью перевода. С собой приносить ноутбук, будет практика! Регистрироваться здесь: Away3D TypeScript Workshop by Rob BatemanТэги: |
2013-11-25 |
Конспект встречи UAFPUG-44 в Харькове О чем мы говорили на UAFPUG-44, какие книги, видео, статьи упоминались. Многое не записал -- прошу прощения, если еще что-то вспомните -- напишите! Итак,
Слайдшоу UAFPUG-44:
Блиц-доклады:
Рост
Варим кофе. Бюджетная домашняя машина на 15 бар: Zelmer Espresso 13z013
Фото с ITSea-2013 - см. в группе ITSea на Facebook.
Антон
Новое во Flash Player: AIR 4 and Flash Player 12 Release Notes | AIR Labs
Атлас - иллюстрация: http://dev.
Space Empire iPad Game (Beta): http://www.youtube.
Игорь (Шаулов)
Мувики про текстурные атласы (там, после первого должно предложить еще пару)
Александр
Транслятор интерфейса: транслирует интерфейс Java-приложения в веб-приложение. С поддержкой IE7.
Женя
JS без браузера: http://PhantomJS.org
Олег
Gamification - http://esynctraining.com/
MapQuest
Коннектимся к Адоби Коннект, запускаем аппликуху, проводим урок / собеседование в игровой форме.
Игорь (Руссо)
Sigma. Рефакторинг непрерывен.
--Конец блицев--
Доклады
1. Рефакторинг
См. также: Книга Маритна Фаулера "Рефакторинг" и шпаргалка на Хабре к ней.
2. Потрошим Arduino Starter Kit - Ссылка
Наш набор новичка:
Заказать Ardino Starter Kit можно здесь:
Пример умного дома (Алекс Хердт, Мюнхен): http://webdom.
Подключение Arduino к Adobe AIR, ссылки:
Наш Hello World на Arduino:
Успех! Розыгрыши призов
Розыгрыш билета на DevGamm, победитель: Александр. Поздравляем!
Книги
Темы (обсудили частично)
Аудитория: 198 (16 + 182)
- 16 человек на встрече.
- По данным логов, онлайн-трансляцию нашей встречи смотрело 182 уникальных айпи-адреса.
Антон, спасибо еще раз огромное за трансляцию!
Фотки
Спасибо!
Всем, кто пришел -- моя благодарность, вы классные!
Рост
Мои контакты:
Skype: Rostyslav.Siryk_globallogic.com
Email: Rostislav.Siryk@gmail.com
Важно!
Мастер-класс по Away3D Typescript в Киеве состоится за день до DevGamm. Еще есть билеты по $75, потом будут уже по $100. Анонсы: Твит Роба Бейтмана, анонс в блоге Away3D.com.
|
2013-11-18 |
Вышли Flash Player 12 Beta и Adobe AIR 4 Главные добавления в этом релизе:
Как компилировать под FlashPlayer 12?Вам нужно передать дополнительный аргумент компилятору ASC 2.0, указав, что нужно получить SWF версии 23:
-swf-version=23 Ищите подробности в Adobe AIR and Flash Player 12 Release Notes -- он еще обновляется. Новая система нумерации версий Flash Player и Adobe AIRБета-версии нового Flash Player и AIR под кодовым названием "Jones" получили большое прибавление к номеру версии. В этом релизе введена новая схема нумерации версий по образцу заданному Google Chrome и Mozilla Firefox. Теперь основной номер версии обновляется в каждом релизе, таким образом покончено с минорной нумерацией. Другими словами, начиная с версии "Jones", Flash Player стал Flash Player 12. И с каждым новым релизом (примерно каждые 3 месяца) это число будет увеличиваться на единицу. Это изменение, хоть и не так быстро, распространится и на Adobe AIR SDK. Версия "Jones" пронумерована как Adobe AIR 4 и AIR SDK 4, однако, начиная со следующего релиза с кодовым именем "King" номер версии AIR будет синхронизирован сверсией Flash Player. То есть мы будем иметь Flash Player 13, Adobe AIR 13 и AIR SDK 13 как единый релиз.
Объединение нумерации имеет смысл, так как Flash и AIR всегда основаны на одном и том же ядре и во многом являются одним и тем же продуктом. Больше не придется ссылаться на них как на "AIR 3.x" и "Flash Player 11.x", теперь мы все сможем ссылаться на Flash и AIR, используя единый номер. Урррррррррааааааа!
Надеемся также, что такая синхронизация версий с браузерами приведет к более понятной и четкой синхронизации версий Flash со стороны браузеров, имеющих свою собственную архитектуру плагинов - NPAPI в Firefox и PepperFlash в Chrome.
Adobe AIR и Flash становятся ближе. С каждым днем!Вдумчивый наблюдатель уже заметил, как незаметно Adobe AIR замещает собой Flash, особенно на мобильных устройствах. Фактически, мы уже имеем Flash Mobile, причем лучший за всю историю Flash. При этом он также -- лучший кросс-платформенный инструмент создания кросс-платформенных приложений!
Тэги: |
2013-11-15 |
Харьков, последнее напоминание: завтра -- UAFPUG#44 Встреча состоялась, было очень круто! Давно не узнавал столько нового. Следующая конференция в Харькове будет в 2014 году. Место: Харьков, офис GlobalLogic, ул Новгородская, 3б (карта). Время: 16 ноября 2013 года, 11:00-17:00 Программа:
Хотите рассказать о важном?Пишите в комменты или на rostislav.siryk@gmail.com Как добраться?Карта: |
2013-11-12 |
Видео-записи докладов со встречи UAFPUG-43 в Киеве На встрече флэшеров в Киеве было интересно и тепло! Нам удалось сделать намного больше, чем планировалось. Было много дискуссий и новых планов. Все это можно увидеть ниже. Но сначала -- коротко обо всем, что было:
Видео блиц-докладов с UAFPUG-43Блиц-доклад -- это когда каждый участник встречи выходит и коротко представляет себя и рассказывает о том, что его занимает сейчас. К сожалению, записать удалось далеко не всех, простите! Вот то, что есть: Блиц: Иван ФилимоновБлиц: Михаил ТкачукБлиц: Игорь РуссоБлиц: Виталий СниткоБлиц: Валерий БаштовойБлиц: Александр БурдунБлиц: Лена КузнецоваБлиц: Виктор ПримакПерейдем к докладам. Их было два, но они были объемными, а обсуждения заняли времени чуть ли не больше, чем сами доклады. Итак: Доклад Ивана Филимонова на встрече UAFPUG-43: Асинхронное программированиеПрезентация к докладу Ивана Филимонова Доклад Лены Кузнецовой на встрече UAFPUG-43: Эффективная работа команды и наоборотПрезентация к докладу Лены Кузнецовой Дискуссия после доклада Лены Кузнецовой:Фото дискуссии: Спасибо всем, кто пришел и сделал этот день таким интересным и вдохновляющим! Ссылки:
|
2013-11-07 |
Поиск пути Доброго времени суток! Поговорим о такой вещи как поиск пути, чаще всего, конечно используемой в играх. В одних играх боты просто ходят взад-вперед по заранее предопределенному пути. В других юниты двигаются в определенном направлении, пока не встретят препятствие. Бывает что препятствия вообще не учитываются. Ну и наконец игры в которых юниты находят кратчайший путь до нужного им места в обход препятствий. Вот об этом и будет беседа. Итак, как это работает. Алгоритмов поиска пути и их модификаций на самом деле достаточно много. Один из хорошо зарекомендовавших себя – AStar (А*), младший и более шустрый брат алгоритма Дейкстры. Его особенность в том, что он работает эвристически (грубо говоря интуитивно). Он обходит узел за узлом, переходя в теоретически наиболее ближний к цели узел, попутно корректируя путь, если это не так. На сколько тот или иной узел близок к целевому определяется суммой расстояний от начального узла до текущего и от текущего до конечного. Например так: А теперь в коде: package { public class Grid { private var _nodes:Vector.<Vector.<Node>>; private var _width:int; private var _height:int; public function Grid(width:int = 25, height:int = 25, walkableMap:Array = null) { _width = width; _height = height; _nodes = new Vector.<Vector.<Node>>(); for (var x:int = 0; x < _width; x++) { _nodes[x] = new Vector.<Node>(); for (var y:int = 0; y < _height; y++) { _nodes[x][y] = new Node(x, y, true); if (walkableMap && !walkableMap[x][y]) Node(_nodes[x][y]).walkable = false; } } } public function getNode(x:int = 0, y:int = 0):Node { return (x < 0 || x >= _width)?null:(y < 0 || y >= _height)?null:_nodes[x][y]; } public function get nodes():Vector.<Vector.<Node>> { return _nodes; } } } Класс узла: package { public class Node { private var _g:Number; private var _h:Number; private var _f:Number; private var _x:int; private var _y:int; private var _walkable:Boolean; private var _parentNode:Node; public function Node(x:int, y:int, walkable:Boolean) { _x = x; _y = y; _walkable = walkable; } public function get g():Number { return _g; } public function set g(value:Number):void { _g = value; } public function get h():Number { return _h; } public function set h(value:Number):void { _h = value; } public function get f():Number { return _f; } public function set f(value:Number):void { _f = value; } public function get parentNode():Node { return _parentNode; } public function set parentNode(value:Node):void { _parentNode = value; } public function get walkable():Boolean { return _walkable; } public function set walkable(value:Boolean):void { _walkable = value; } public function get x():int { return _x; } public function get y():int { return _y; } } } И непосредственно класс поиска пути: package { /** * Поиск пути */ public class PathFinder { private static const ALIGNED:int = 1; private static const DIAGONAL:Number = 1.4; private static var _closed:Vector.<Node>; private static var _opened:Vector.<Node>; private static var _path:Vector.<Node>; public static function getPath(start:Node, end:Node, grid:Grid):Vector.<Node> { _closed = new Vector.<Node>(); _opened = new Vector.<Node>(); _path = new Vector.<Node>(); start.g = 0; start.h = getDistance(start, end); start.f = start.g + start.h; start.parentNode = null; _opened.push(start); var currentNode:Node; while (_opened.length) { currentNode = _opened[0]; _closed.push(_opened.shift()); for (var x:int = currentNode.x-1; x <= currentNode.x+1; x++) { for (var y:int = currentNode.y-1; y <= currentNode.y+1; y++) { var testedNode:Node = grid.getNode(x, y); if (!testedNode || !testedNode.walkable || _closed.indexOf(testedNode) != -1) continue; if (_opened.indexOf(testedNode) == -1) { testedNode.g = currentNode.g + getLocalDistance(currentNode, testedNode); testedNode.h = getDistance(currentNode, testedNode); testedNode.f = testedNode.g + testedNode.h; testedNode.parentNode = currentNode; _opened.push(testedNode); } else { var tempG:Number = currentNode.g + getLocalDistance(currentNode, testedNode); if (tempG < testedNode.g) { testedNode.g = tempG; testedNode.f = testedNode.g + testedNode.h; testedNode.parentNode = currentNode; } } } } _opened.sort(sortOpen); if (_opened.length && _opened[0] == end) return pathReconstruct(_opened[0]); } return null; } private static function pathReconstruct(lastNode:Node):Vector.<Node> { while (lastNode.parentNode) { _path.push(lastNode); lastNode = lastNode.parentNode; } _path.reverse(); return _path; } private static function sortOpen(one:Node, two:Node):Number { return one.f - two.f; } private static function getDistance(one:Node, two:Node):Number { var catX:int = Math.abs(two.x - one.x); var catY:int = Math.abs(two.y - one.y); return Math.sqrt(catX * catX + catY * catY); } private static function getLocalDistance(one:Node, two:Node):Number { return (one.x == two.x || one.y == two.y)?ALIGNED:DIAGONAL; } } } Использовать довольно просто: var grid:Grid = new Grid(25, 25); //Создает сетку 25 x 25 третьим параметром можно передать вектор проходимостей var path:Vector.<Node> = PathFinder.getPath(grid.nodes[0][0], grid.nodes[24][24], grid); trace(path); Я привел вполне работоспособную, но в тоже время достаточно простую реализацию этого алгоритма. В реальных проектах вы вероятно захотите ввести еще стоимость клеток, ведь поверхность земли бывает неоднородной (лед, болота, зыбучие пески). Так же вы можете попробовать его ускорить, например, возможно положительно скажется на скорости работы замена пересортировки вектора открытого списка на сохранение индекса следующего узла. Или замена формулы вычисления стоимости h на более легкую. Вобщем желаю вам удачи в экспериментах! |
2013-11-03 |
Генератор шаблона регулярного выражения, определяющего значение числа в промежутке При использовании регулярных выражений может встать задача написания шаблона, определяющего число из промежутка от X до Y, а не просто числа определенной длины. Удобного механизма для этого не предусмотрено и приходится составлять громоздкие шаблоны для каждого случая. Например для промежутка от 125 до 2819 шаблон буден выглядеть следующим образом (online генератор): (12[5-9]|1[3-9][0-9]|[2-9][0-9]{2}|1[0-9]{3}|2[0-7][0-9]{2}|28[01][0-9]) Очевидно, что если границы не известны заранее, а меняются во время выполнения, то для создания таких шаблонов нужна функция, которая будет составлять такие шаблоны по указанным границам промежутка. Ниже приводится миграция Python генератора https://github.com/dimka665/range-regex на Java. package ru.flaps.framework.util; import java.util.*; /** * Вспомогательный генератор шаблонов регулярных выражений и их частей * <span class="hide">Created 31.10.13</span> * @author greymag * @link https://github.com/dimka665/range-regex * Copyright 2013 FlaPS, Inc.<br/> */ public class RegExpGenerator { /** * Функция для генерации регулярного выражения, под которое подпадает * любое число в промежутке между минимальным и максимальным включительно * @param min минимальное значение * @param max максимальное значение * @return шаблон */ public static String intRange(final Integer min, final Integer max) { /* > intRange(12, 345) '1[2-9]|[2-9]\d|[1-2]\d{2}|3[0-3]\d|34[0-5]' */ final List<String> subpatterns = new ArrayList<String>(); Integer start = min; for (final Integer stop : split2Ranges(min, max)) { subpatterns.add(range2Pattern(start, stop)); start = stop + 1; } String listString = ""; for (int i = 0; i < subpatterns.size(); ++i) { if (i > 0) listString += "|"; listString += subpatterns.get(i); } return listString; } private static List<Integer> split2Ranges(final Integer min, final Integer max) { final Set<Integer> stops = new HashSet<Integer>(); stops.add(max); Integer ninesCount = 1; Integer stop = fillByNines(min, ninesCount); while (min <= stop && stop < max) { stops.add(stop); ninesCount += 1; stop = fillByNines(min, ninesCount); } Integer zerosCount = 1; stop = fillByZeros(max, zerosCount) - 1; while (min < stop && stop < max) { stops.add(stop); zerosCount += 1; stop = fillByZeros(max, zerosCount) - 1; } final List<Integer> list = new ArrayList<Integer>(stops); Collections.sort(list); return list; } private static Integer fillByNines(final Integer integer, final Integer ninesCount) { final String integerStr = integer.toString(); final String prefix = ninesCount > integerStr.length() ? "" : integerStr.substring(0, integerStr.length() - ninesCount); return Integer.parseInt(prefix + stringOfSize('9', ninesCount)); } private static Integer fillByZeros(final Integer integer, final Integer zerosCount) { return integer - integer % (int)Math.pow(10, zerosCount); } private static String range2Pattern(final Integer start, final Integer stop) { String pattern = ""; Integer anyDigitCount = 0; final String startStr = start.toString(); final String stopStr = stop.toString(); for (int i = 0; i < startStr.length(); ++i) { final String startDigit = startStr.substring(i, i + 1); final String stopDigit = stopStr.substring(i, i + 1); if (startDigit.equals(stopDigit)) { pattern += startDigit; } else if (!startDigit.equals("0") || !stopDigit.equals("9")) { pattern += String.format("[%s-%s]", startDigit, stopDigit); } else { anyDigitCount++; } } if (anyDigitCount > 0) pattern += "\\d"; if (anyDigitCount > 1) pattern += String.format("{%d}", anyDigitCount); return pattern; } private static String stringOfSize(char ch, int size) { final char[] array = new char[size]; Arrays.fill(array, ch); return new String(array); } } Пример использования: final String numPattern = RegExpGenerator.regex_for_range(10, 133); // numPattern = 1\d|[2-9]\d|1[0-2]\d|13[0-3] Boolean match; match = "Hello, my value is 134!".matches("Hello, my value is (" + numPattern + ")!"); // match = false match = "Hello, my value is 119!".matches("Hello, my value is (" + numPattern + ")!"); // match = true
|
2013-11-01 |
Кастомный курсор мыши Сама по себе тема создания своего курсора мыши довольно избита. Но сводится, как правило, к сокрытию “настоящего” курсора ОС и перемещению клипа в координаты мыши. Преимущества перед “эмулированным курсором” на лицо:
Ну и немного дегтя в бочку с медом, куда ж без него:
Как вы уже верно заметили, для отображения и анимации курсора нужен вектор битмапдат. Для удобства мы не будем эмбеддить набор картинок, а проведем растеризацию анимированного клипа. (Клик для анимации) Ну а теперь все вышесказанное в коде с комментариями: package { import flash.display.BitmapData; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.ui.Mouse; import flash.ui.MouseCursorData; public class Main extends Sprite { private const MY_CURSOR:String = "MySuperCursor"; //Определяем строковую константу - имя курсора public function Main():void { if (Mouse.supportsNativeCursor) //Проверяем что ОС поддерживает встроенные курсоры { var cursorData:MouseCursorData = new MouseCursorData(); //Создаем новый экземпляр класса "параметров курсора" cursorData.data = getBitmapsVector(new MyCursorClip()); //Определяем вектор битмап. (Подразумеваю, что MyCursorClip это и есть нарисованный ранее курсор) cursorData.frameRate = stage.frameRate; //Определяем частоту кадров. Mouse.registerCursor(MY_CURSOR, cursorData); //Регистрируем курсор Mouse.cursor = MY_CURSOR; //Делаем курсор активным } else //Иначе, если в ОС нет поддержки курсоров, используем старый способ с сокрытием курсора { Mouse.hide(); var mc:MovieClip = new MyCursorClip(); mc.mouseEnabled = false; mc.x = mouseX; mc.y = mouseY; mc.addEventListener(Event.ENTER_FRAME, cursorFrameHandler); addChild(mc); } } /** * Возвращает вектор битмапдат - кадров переданного клипа * @param mc преобразуемый в вектор клип * @return Vector.<BitmapData> вектор битмапдат */ private function getBitmapsVector(mc:MovieClip):Vector.<BitmapData> { var vector:Vector.<BitmapData> = new Vector.<BitmapData>(); for (var i:int = 0; i < mc.totalFrames; i++) { mc.gotoAndStop(i + 1); vector[i] = new BitmapData(32, 32, true, 0x000000); vector[i].draw(mc); } return vector; } /** * Обработчик входа имитирующего курсор клипа в кадр. перемещает его в координаты "реального" курсора * @param e событие */ private function cursorFrameHandler(e:Event):void { e.currentTarget.x = mouseX; e.currentTarget.y = mouseY; } } } И пример: |
2013-10-29 |
Flash vs WebRTC в борьбе за браузерные VoIP звонки Если в каком-нибудь коммюнити спрашивают про аудио- или видеозвонки из браузера, как правило, получают ответ: "Попробуйте WebRTC". WebRTC, действительно, подходящая для этого технология и имеет ряд преимуществ над другими способами передачи аудио и видео в браузере.
Адепты WebRTC уже давно похоронили Flash, несмотря на то, что WebRTC местами имеет сырые реализации и доступна далеко не повсеместно. В настоящей статье представлены TOP 3 технологий звонков из браузера с описанием их преимуществ и недостатков.
Как известно, сам браузер "звонить" до последнего времени не умел. Не умел обрабатывать звук с микрофона, посылать, принимать и воспроизводить. Относительно недавно в некоторых браузерах появилась возможность захвата с микрофона и вебкамеры и дальнейшей отправки этих данных по защищенному SRTP протоколу, а так же воспроизведение потока с использованием адаптивного jitter buffer. Все эти новые возможности и есть не что иное, как WebRTC. Здесь стоит заметить, что браузерные звонки существовали за много лет до появления WebRTC, поэтому начнём с наиболее древних.
TOP 3 – JavaВременем появления браузерных звонков можно считать момент, когда Java апплеты стали поддерживать захват аудио с микрофона. Java Runtime Environment (JRE), как правило, уже установлена в системе, будь-то Linux или Windows. JRE так же присутствует в виде плагина в большинстве известных браузеров. Например, если заглянуть во вкладку chrome://plugins браузера Google Chrome, можно найти там NPAPI Java плагин. Этот плагин и будет средой для выполнения Java апплета. Второй, более продвинутый способ запуска, это JNLP (Java Network Launch Protocol), который позволяет, к примеру, кустомизировать окно "Загрузка апплета...".
В итоге Java код выполняется десктопом или браузерным плагином, захватывает аудио с микрофона и отправляет его на сервер по стандартному RTP протоколу (для Java можно с легкостью отыскать несколько готовых RTP реализаций). С безопасностью здесь так же все в порядке. Понятно, что апплет должен быть подписан, и при запуске пользователя спросят, желает ли он запустить подписанный апплет от данного производителя, который может получить доступ к тем или иным функциям.
Плюсы решения на Java:
Кажется, что все идеально? К сожалению, в Java есть проблемы с DSP для VoIP. А это весь "must have" набор:
Теперь представим звонок с Java апплета без гарнитуры (наушников с микрофоном). Если провести этот эксперимент ночью, поставив колонки на полную громкость, можно напугать соседей до заикания. Всё из-за эхоподавления. Его нет. Отсутствие AGC заставит ваших пользователей крутить уровень громкости (нормальный AGC должен делать это за пользователя, чтобы не было слишком тихо или слишком громко). А отсутствие Adaptive Jitter Buffer выльется либо в большую задержку либо в "choppy audio" – прерывистый неразборчивый звук. В результате качество коммуникации будет далеким от оптимального.
Все недостающие алгоритмы можно теоретически реализовать на Java, но есть пара проблем. Во-первых, реализовать универсальные и производительные алгоритмы (например AEC) достаточно сложно: такая реализация потребует высоких трудозатрат и расходов на R&D. Во-вторых, реализация таких алгоритмов на Java может работать в несколько раз медленнее, чем на C/C++, что может повлечь серьезные проблемы с производительностью и перерасход ресурсов клиентского CPU.
Производители Java апплетов с функцией звонков реализуют собственные DSP процессоры или используют уже существующие решения на C/C++. Как правило, они подкладывают к апплету DLL библиотеки, которые берут на себя обработку вышеописанных DSP алгоритмов. В результате Java апплет имеет стандартные VoIP функции для обеспечения качественного звонка со всеми "must have" VoIP алгоритмами.
В конечном итоге остается два минуса Java:
Довести DSP до отличного качества или купить соответствующие разработки может позволить себе не каждый вендор. То же касается поддержки различных аудио- и видеокодеков.
В итоге, Java можно назвать незаслуженно покинутой разработчиками платформой для браузерных звонков.
Незаслуженно покинута она по двум причинам:
О них далее.
TOP 2 – FlashДо некоторого времени Flash был технологией для красивых интерактивных баннеров.
В 2002 году появилась в релизе версия Flash Communication Server MX 1.0 - прародитель сегодняшнего Adobe Media Server. Flash Player 6, являясь тогда продуктом компании Macromedia, умел взаимодействовать с FCS MX 1.0 и обмениваться с сервером аудиопотоками. Это еще раз указывает на то, что WebRTC припозднился на 10 лет, а также то, что рынок начинает закрывать свои потребности за 10 лет до появления вменяемой технологии браузерного интерактива.
В это время Flash Player 6 уже умел захватывать аудио и жать его в NellyMoser и видео - в Sorenson Spark. Java в это время была слабо представлена в веб и Flash Player 6 в связке с сервером претендовали на мировое господство в области web-стриминга. Позже появились Red5, Wowza, но это немного другая история.
В качестве транспорта для аудио и видео в Flash Player 6 использовался протокол RTMP, который сегодня имеет открытую спецификацию, опубликованную Adobe.
Flash Player 6 в связке с сервером стал платформой для браузерных звонков, обладающей следующими функциями:
До полноценного браузерного VoIP тогда было еще очень далеко. AEC (Acoustic Echo Cancellation) в тот период, наверное, даже не было в планах. Но платформа делала свое дело и передавала звук и видео от одного плеера к другому через сервер.
Все, кто работают с VoIP, рано или поздно сталкиваются с задержкой. Когда разработчик впервые тестирует написанное им VoIP приложение, он не обращает внимания на задержку: звук есть, картинка есть - и хорошо. Первыми задержку замечают пользователи и пишут репорты типа: «I say "one" then Bob says "two" and it seems it takes about 5 seconds. Why?» Потом уже два разработчика начинают тестировать звук и не понимают, куда пропали эти 5 секунд, ведь у них сервер Xeon на 100500 ядер и он не может тормозить.
Задержка была в связке Flash Player 6 + Flash Communication Server MX 1.0, а также осталась в следующих версиях сервера, включая последнюю Adobe Media Server, с ней безуспешно боролись на Wowza и Red5. Причина, конечно, проста и известна каждому VoIP разработчику: RTMP протокол работает поверх TCP, а потому не приспособлен для полноценного VoIP. Сохранить пакеты любой ценой – это не тот случай, когда дело касается передачи звука либо видео. Но это главная задача TCP протокола: сохраняем пакеты и получаем задержку. Все просто.
Отсутствие полноценного UDP транспорта сделало невозможным развитие интерактивных сервисов. Например, если участник вебинара хочет пообщаться face-to-face с ведущим, у него не всегда получится это сделать нормально. Все в значительной степени зависит от качества сети и потерь. В результате на базе RTMP развивались, в основном, video on demand сервисы, или live video, или вебинары с одним ведущим, где задержка не так важна.
Кстати, здесь вопрос к Macromedia: почему они не сделали audio и video стриминг по UDP. Это бы значительно упростило жизнь всем разработчикам и конечным пользователям. Очевидно, что VoIP функция браузера была на переферии и над ней никто особо не задумывался, а для интерактива с данными (sharedobjects, callbacks итд) TCP подходит оптимально.
Ситуацию с UDP в Flash Player сдвинула компания Adobe, когда в версии плеера 10 ввели поддержку нового протокола RTMFP и эхоподавление. В 11 версии Flash Player добавили поддержку кодеков G.711 и H.264. В AS3 API так же имеются упоминания про Adaptive Jitter Buffer для G.711 и Speex.
VoIP возможности Flash Player 11:
Благодаря этим нововведениям, Flash Player имеет практически все необходимое, чтобы стать VoIP платформой №1 для браузера: шифрование AES защищает трафик между браузером и сервером от посторонних; AEC и Jitter Buffer обеспечивают качество воспроизведения звука; новые кодеки совместимы с традиционным VoIP, а RTMFP протокол работает по UDP. Не хватает AGC (Automatic Gain Control). Его отсутствие не смертельно, но неприятно для тех, кто понимает пользу этой функции для VoIP и не понимает, почему её до сих пор нет. Помогает перенос AGC-фильтра на сторону сервера.
Еще одна маленькая неприятность от Adobe - невозможность во Flash Player нормально проиграть H.264 поток, закодированный для передачи по RTP. В багтрекере Adobe cуществует "by design" баг, который накладывает ограничение 1 NALU per video frame. Это ограничение отрубает все H.264 кодеры, которые дают поток, совместимый с RTP. В результате приходится применять транскодинг, что в свою очередь вызывает избыточное потребление ресурсов CPU, которого в принципе хотелось бы избежать.
Flash RTMFP основан на UDP и довольно прилично передает звук. Но и здесь не обошлось без сюрпризов. В доках Adobe AS3 сказано, что RTMFP для аудио и видео поддерживает три режима: надежная доставка (reliable), частично-надежная доставка (partially reliable), ненадежная доставка (unreliable). В этих же доках есть только два флага для audioReliable и videoReliable: true, false. False описывается как режим частичной доставки (partially reliable). В итоге, получается, что ненадежная доставка (unreliable) пропала, а для передачи звука она наиболее важна.
Частичная доставка – это TCP подобные ретрансмиты, которые происходят очень ограниченное время, но и этого хватает, чтобы испортить звук на нестабильной сети. Такие ретрансмиты вызывают джиттер, который портит поток. Jitter buffer на принимающей стороне в данном случае не помогает, т.к. идет очень большой разброс. Решением является переход к ненадежной доставке (unreliable) звука. В Flash Player API нет возможностей её включить, и приходится добавлять её на уровне протокола на серверной стороне.
Например, в WebRTC - Flash RTMFP SIP Gateway Flashphoner Web Call Server реализован хак на уровне RTMFP протокола, который позволяет полностью исключить ретрансмиты в RTMFP и обеспечить unreliable доставку. Это в разы повышает устойчивость потока к потерям и лагам сети. Можно получить разборчивый Speex поток до 12% потерь в сети. Тот же поток заметно рвется в случае частичной доставки(partially reliable) причем рвется на тестах с Adobe Flash Media Gateway, несмотря на то что эта часть Adobe Media Server должна по задумке являться эталонной реализацией RTMFP протокола.
Плюсы Flash:
Минусы Flash:
Кстати, что мешает разработчикам Flash Player внедрить WebRTC стек?
TOP 1 – WebRTCИ наконец, любимец публики, зомбирующая разработчиков, кошмарящая телекомов и активно обсуждаемая технология WebRTC. Рынок живет ожиданиями, а в ожиданиях сегодня доминирует WebRTC.
На текущий момент WebRTC присутствует в трех распространенных браузерах в состоянии production:
А также в двух браузерах в состоянии beta:
Яндекс Браузер не проверяли, но по информации в сети, он не всегда корректно работает с WebRTC, поэтому мы поставили его в beta в нашем списке.
Даже в Chrome браузере WebRTC продолжает оставаться недоработанной, хотя уже прошло немало времени после релиза. Простые вещи работают, но когда дело доходит до смены состояния сессии по SDP (аналог re-INVITE в SIP) или при других нетривиальных действиях, появляются разные сюрпризы, которые сильно огорчают.
Однако это не мешает WebRTC завоевывать все новые умы и определять вектор развития VoIP и вообще интерактивных технологий в Web. И это не удивительно по двум причинам:
На технологической начинке WebRTC хотелось бы остановиться отдельно, это:
SRTP, DTLS, ICE, STUN, AEC, AGC, Adaptive Jitter Buffer, Opus, VP8
Выглядит так, как будто в браузер встроили софтфон. Не хватает только поддержки SIP.
Действительно, набор используемых в WebRTC технологий больше похож на VoIP SDK. SRTP и DTLS обеспечивает защиту трафика между WebRTC узлами. ICE и STUN помогают преодолеть NAT, выставив с обеих сторон кандидатов для созвона в виде простых пар host:port. AEC, AGC и Jitter Buffer работают для того чтобы сделать аудио и видео качественным – без лагов и задержек. Кодеки Opus и VP8 хорошо подходят для глобального Интернета, где битрейт до конечного пользователя может легко падать до очень низких значений вопреки обещаниям провайдеров про каналы в 100Mbps.
Несколько омрачает картину отсутствие поддержки WebRTC в других браузерах, таких как IE, Safari, Opera и т.д. К недостаткам еще можно отнести несовместимость с традиционным VoIP оборудованием. Например, производители SIP/VoIP продуктов, коих великое множество, были бы очень признательны поддержке обычных SIP/RTP протоколов и кодеков для совместимости с миллионами устройств.
Здесь стоит упомянуть, что WebRTC изначально задумана как peer-to-peer между браузерами и ориентирована на шифрованный SRTP трафик. Скорее всего, именно поэтому VoIP вендорам, которые обмениваются стандартными RTP потоками, придётся внедрять у себя WebRTC совместимый транспорт и кодеки.
Хотя и здесь не все так плохо. Существуют шлюзы для обеспечения такого рода совместимости. Например WebRTC SIP Gateway Flashphoner Web Call Server 3 является шлюзом, который может соединить WebRTC клиента и стандартное SIP/RTP устройство будь то VoIP свитч или GSM шлюз, работающий по SIP. Таким образом, данная проблема вполне решаема путем ввода промежуточного ПО.
Преимущества и недостатки WebRTC достаточно прозрачны:
Плюсы WebRTC:
Минусы WebRTC:
Ожидания и ресурсы, стоящие за WebRTC, с лихвой перекрывают текущие минусы, поэтому смело отдаем ей законное первое место TOP1 в списке браузерных технологий для VoIP.
Если же вспомнить, что остальные описанные здесь браузерные технологии Java и Flash – это плагины (хоть и предустановленные в большинстве браузеров), то выходит, что WebRTC – это единственная чисто-браузерная технология, которой в этом отношении нет аналогов.
Итак, мы закончили разбор трех технологий для web звонков, обобщим все описанное выше в виде следующих таблиц:
VoIP фильтрыСетевые протоколы и спецификацииАудио кодекиВидео кодекиПоддерживаемые браузерыНекоторые пояснения:
Ну вот и пришло время заняться подсчетом.
Некоторые функции, конечно, могут быть даже близко не равны по весу, но если считать в попугаях получается следующая картина:
Первое место в этой гонке VoIP технологий и коммуникационных протоколов занимает VoIP софтфон - 54% (21 попугай из 39). На втором месте WebRTC - 44% (17 попугаев из 39) и Flash, который идет за WebRTC с 41% (16 попугаев из 39).
В окончании, хотелось бы поставить вопрос: если мы строим облако для web-звонков с выходом на SIP/VoIP/PSTN, на чем мы будем это облако строить, какие материалы использовать?
Отвечая на этот вопрос, придется затронуть еще пару моментов. Первый из них связан с мобильными устройствами, второй - с проходимостью через брандмауэры.
Не секрет, что сейчас важна поддержка Android, iOS SDK и кроссплатформенность. С мобильными устройствами все более или менее понятно. Есть несколько вариантов:
Теперь про брандмауэры(firewalls). Как звук пройдет через брандмауэр, если UDP на нем отключен? Ответ: для этого потребуется переключение на TCP транспорт. Подойдет например Flash RTMP.
А если весь трафик организации идет через proxy, и админ закрыл весь не HTTP трафик? Тогда придется использовать HTTP туннелированные, например RTMPT, что, кстати, не лучшим образом скажется на задержке.
В итоге получаем супероблако для VoIP звонков такого вида: для передачи аудио и видео используем WebRTC, RTMFP, RTMP, RTMPT, Java Applet. Для интеграции со стандартным VoIP используем SIP, RTP. Для мобильных устройств: Adobe Air, WebRTC, SIP/RTP клиентов.
Перечисленные технологии покроют большинство браузеров и мобильных устройств, хотя схема определенно избыточна.
Что из нее убрать, чтобы облегчить – решать вам.
--
Материал подготовлен при участии специалистов компании Flashphoner
Тэги: |