Flex и RIA блоги



2014-04-21

11:10:25, Flash-ripper.com
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


05:38:38, Action Script 3
Как отделить мух от колет?

Рано или поздно любой flex-разработчик понимает, что нужно что-то сделать с собственным “винегретом” в коде, состоящим из mxml-разметки вперемешку с inline-кодом. А, собственно, что с ним не так? Если кратко, то:

  • код трудночитаем, из-за постоянного перехода внутри одного файла от as3 кода к mxml разметке и обратно;
  • сильная связанность (нет возможности легко заменить разметку или реализацию);
  • низкая переиспользуемость кода (трудно перенести код/разметку в другой проект);
  • отсутствует возможность разделить обязанности между разработчиком и дизайнером (кто-нибудь помнит/пользовался Flash Catalyst?, ах да: Development and sales ended on April 23, 2012);
  • сильно разросшийся размер файла;
  • и так далее.


Почему же так происходит? Отчасти в этом виновата сама Adobe, которая не удосужилась привить нужные навыки будущим разработчикам. Официальный хелп пестрит примерами наподобие этого (это всего лишь примеры, но все же):

<?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>

 

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

Не будем о грустном. Так как же можно отделить просо от гречки? Если хорошо поискать, то Adobe предлагает следующие варианты:

  • использовать <fx:Script> блок. Собственно, от его использования мы и пытаемся избавиться;
  • инлайн обработчики событий:

<s:Button label="Convert" 
click="celsius.text=String(Math.round((Number(fahrenheit.text)-32)/1.8 * 10)/10);"/>

 

  • в отдельном as файле: <fx:Script source=”includes/Sample3Script.as”/>.

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

Описывание кода в отдельном 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 кода не получится. А так как именно эту проблему мы и решаем, то вариант с подпиской на событие в разметке в данном случае подходит лучше. Используем тот вариант, который решает нашу задачу лучше.

Таким образом, мы частично решили поставленные в начале статьи задачи, и даже получили некоторые другие преимущества:

  • создание конструктора класса;
  • возможность тестировать логику приложения отдельно от её представления;
  • возможность наследоваться от базовой логики, без необходимости нести с собой mxml-мусор.

Но, как и у любого другого шаблона, у CodeBehind есть не только плюсы, но и минусы:

  • увеличилось количество набираемого кода;
  • увеличилось количество файлов/классов для редактирования (что приводит к частому переключению между вкладками в IDE);
  • использование наследования вместо композиции, что ведет к увеличению иерархии наследования;
  • необходимость в предоставлении ссылок-заглушек при тестировании базовых классов;
  • возможно частичное нарушение инкапсуляции и наследования.

Другим вариантом реализации отделения логики от разметки является приём, называемый 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
Code behind in Flex and WPF
Flex and WPF: A comparison – Part 2b
Code-Behind and Flex 2.0 (Partial Classes)
Building components by using code behind
Creating components and enforcing separation of concerns with Flex
Best Practice: Code Behind versus MXML Script Blocks versus View Helper


2014-04-18

14:32:37, Flash-ripper.com
Александр Письменчук - 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

13:17:21, Flash-ripper.com
Кефирам нужен человек в Киеве

Kefir Games (тюряга) ищет бандеровца девлида в Киеве для работы в центровом офисе. Нужно делать игры, отвечая за качество кода и архитектуры, пасти котов руководить программистами и работать с ТЗ от и до.

Требования:

  • Опыт в социальном AS3-геймдеве от 2 лет, Starling и Adobe AIR.
  • Знать оптимизацию графики и алгоритмов.
  • Практиковать ООП как стиль.
  • Уметь спрашивать и отвечать.
  • Работать с чужим кодом.
  • Собственные движки и библиотеки.

Компания дает хорошую зарплату и там есть куда расти

 
 

2014-04-15

14:39:56, Flash-ripper.com
Generic Animation Format и оптимизация Adobe AIR: записи докладов

12 апреля в Харькове прошел UAFPUG №46. Доклады были записаны на видео:

  1. Запись части блиц-докладов и описание Generic Animation Format от Вадима Митина из GAFMedia.
  2. Запись доклада "Оптимизация Adobe AIR Mobile" от Антона Азарова из Харькова.

Важно: по горячим следам Антон сделал разбор полетов к собственному докладу про AIR. Также во время доклада мы долго обсуждали оптимизацию списков в Adobe AIR, и один из наших онлайн-слушателей, Виталий Кононец прислал ссылку на свой блог по темеОптимизация списков в мобильном приложении. Спасибо, Виталий!

Фото с UAFPUG-46:

Вадим Митин вкратце рассказывает о разработке Generic Animation Format:

Мини-доклад Вадима Митина

Нас было немного: 

Но интересно:

Александр Мостовой

Баги Flash IDE достали!

На встрече мы собрали список самых назойливых багов Adobe Flash IDE. Причешем его и устроим витруальный майдан Адобу. Присылайте свои жалобы на Flash в комменты или на мою почту rostislav.siryk.

Спасибо всем, кто пришел и был с нами онлайн!

Гду будет следующий фпуг?

Следующая встреча пройдет в городе, жители которого первыми предложат два доклада. Прошу писать в комменты или на почту выше: кто о чем хочет рассказать. Указывайте город. 

Люблю вас!
Рост

 


2014-04-12

20:54:34, Flash-ripper.com
Агентство помощи социальным стартапам, Киев

AIN сообщает о новом проекте помощи социальным стартапам от организаторов IT-палатки. Этот проект называется "Украинское агентство стратегических инициатив" и будет помогать стартапам, делающим социальные или коммерческие проекты для развития Украины. Об этом рассказал один из инициаторов создания организации Юрий Чайка (MoneXy).

Под такие проекты практически невозможно найти инвестора, так как они, в основном, неприбыльные. В поле зрения организаторов уже около 200 подобных проектов. Агентство планирует помогать стартапам в привлечении инвестиций, юридическом оформлении, работе с государственными органами, консультациях и т.д. Это — неприбыльная организация, которая финансируется через краудфандинг (презентация агентства). «После Майдана многие компании и граждане хотят участвовать и поддерживать социальные проекты», — поясняет Юрий Чайка.


12:45:46, Flash-ripper.com
Трансляция доклада "Оптимизация Adobe Air для мобильных устройств"

UPDATE: записи докладов из онлайн-трансляции:

  1. Запись части блиц-докладов и описание GAF SWF Converter (01:10:11)
    Докладчики: Александр Мостовой, Ростислав Сирык (блицы) и Вадим Митин, GAFMedia.com, Харьков, 04/12/2014 16:02 AM
  2. Запись доклада "Оптимизация Adobe AIR Mobile" (03:21:37)
    Докладчик - Антон Азаров, Харьков, 04/12/2014 17:37 AM

=======================

Идет онлайн-трансляция доклада:
"Оптимизация Adobe Air для мобильных устройств"

09:24:25, Flash-ripper.com
UAFPUG #46 - онлайн-трансляция

Присоединиться к конференции UAFPUG-46 в Харькове онлайн можно здесь:

http://adobechats.adobeconnect.com/uafpug-46/

UPDATE: записи докладов из онлайн-трансляции:

  1. Запись части блиц-докладов и описание GAF SWF Converter (01:10:11)
    Докладчики: Александр Мостовой, Ростислав Сирык (блицы) и Вадим Митин, GAFMedia.com, Харьков, 04/12/2014 16:02 AM
  2. Запись доклада "Оптимизация Adobe AIR Mobile" (03:21:37)
    Докладчик - Антон Азаров, Харьков, 04/12/2014 17:37 AM
Тэги: 

2014-04-08

18:18:03, Flash-ripper.com
Вышел Adobe AIR SDK 13

Adobe AIR SDK

Новое в Adobe AIR  13:

  • GamePreview на Adobe AIR (только для Android)
  • Improved Packaging Engine - iOS - BETA
  • Предупреждение о включении фуллскрина переместили наверх
  • Enhanced Supplementary Character Support for TextField
  • New Stage3D Texture Wrapping Modes
  • Stage3D Anti-Aliasing for Texture Rendering

Ссылки:

Обсуждать возможности новой версии Adobe AIR, а также оптимизацию созданных на Adobe AIR мобильных приложений будем на конференции UAFPUG#46 в Харькове. Готовьте вопросы, а лучше задавайте их прямо здесь в комментариях. 

Важно: Регистрирация на UAFPUG#46

Тэги: 

2014-03-25

17:14:00, Flash-ripper.com
Unity Night Odessa — пост гордости за Одессу и Юнити

22 февраля в Одессе прошла "Ночь Юнити" — Unity NightБыли докладчики из Дании и Финляндии. Участие приняли более 100 человек. Краткий обзор того, о чем говорили:

Building Quality (Unity3D)

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

Unity Test Tools

Этот доклад был посвящен созданию игры с гидом по тестам. Это не тривиальная задача, особенно при работе с кодовыми базами, которые не были разработаны с тестируемости в виду. Ведущие обратил на собственном опыте и лучших практиках автоматизации тестирования, и дал демонстрацию недавно выпущенных Unity Test Tools.

Automated performance regression testing

Секреты производительности регрессионного тестирования. Показано, какие данные собирают тесты производительности, как они используются для идентификации регрессий.

Дискуссии продолжились на афтепати. Это была первая ночь Юнити в Одессе и она удалась!

rsz_unitynight2

Теперь про политику:

Флэш Потрошитель будет писать о важном. Важное во флэше — пишем. Важное про Юнити — пишем. Важное про HYML5/JS — пишем. 

UAFPUG №46

Следующая встреча состоится 12 апреля в Харькове. Готовимся.

И — регистрируемся!


2014-03-24

05:32:54, Action Script 3
Отличия 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

22:08:06, Flash-ripper.com
Разрешить безвизовое посещение США на срок до 90 дней

На официальном сайте Белого Дома размещена петиция о том, чтобы позволить гражданам Украины безвизовое посещение США длительностью до 90 дней.

Прогресс неплохой: вчера до 100 000 подписей нам не хватало 22 000, а сегодня -- уже всего 12 000. Но и дедлайн недалек: 28 марта 2014. Возможно, вы захотите подписать петицию и распространить ссылку на нее: 

https://petitions.whitehouse.gov/petition/allow-ukrainian-citizens-90-da...


2014-03-06

19:56:38, Flash-ripper.com
Политическая информация

 10 фактов


2014-03-03

18:26:14, Flash-ripper.com
Русские в Украине. Нужна ли им помощь Путина?

Внимание: текст написал моим другом. Публикую без изменений. Рост.

Меня зовут Андрей Ткачук. Я живу на Украине. Многие из вас знают меня как разработчика популярного менеджера управления делами: http://mylifeorganized.net

 

Но сегодня речь пойдет не об этом. Речь пойдет о том,что происходит в Украине и почему Россия, пытаясь “помочь”, на самом деле мешает и разрушает мою обновленную страну. И почему я не могу промолчать.

 

О себе: Я русский, родился в Свердловске (Екатеринбурге), прожил 15 лет на севере России в Норильске, где окончил школу с серебряной медалью. В Харьков приехал учиться на программиста. Закончил с красным дипломом, потом была аспирантура, написал диссертацию. Женился, остался жить в Украине и считаю ее своей страной. В Екатеринбурге живет мой родной брат и родственники.

 

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

 

Теперь, когда вы поняли, что я не “бандеровец”, позвольте мне рассказать о том, что происходит здесь в Украине, как говорится, из первых уст.

 

Российское телевидение - информационная война с Украиной

По моим личным наблюдениям, федеральные каналы Российского ТВ, перекручивая и даже подтасовывая факты ведут жесткую информационную войну вместо предоставления объективной информации. Цель: создать общественное мнение в России и в русскоговорящих областях Украины, о необходимости “срочной помощи” со стороны России, чтобы спасти нас от “бесчинств бандеровцев” и ввести войска.

 

Жертвами этой отлично организованной компании стали не только россияне но и некоторые жители Украины которые теперь боятся “бандеровцев”. Но даже они очень настороженно отнеслись к вводу российских войск в Крым.

 

Я понимаю, что многим Россиянам трудно поверить, что им врут. Ведь вы думаете, что  вам показывают голые “факты”. Но вам действительно врут. Я раскрою вам страшную тайну - нет полчищ “бандеровцев”, которые нас терроризируют.

 

Что происходит в Украине на самом деле

Я с полной ответственностью заявляю, что нам, русскоговорящим украинцам, не нужна помощь России. Мы сами разберемся. За все время моей жизни здесь я НИ РАЗУ не почувствовал себя ущемленным. Я объездил всю Украину от Львова до Днепропетровска.  Ни один мой знакомый (а их у меня очень много) не чувствовал себя ущемленным. За все время революции я лично не испытывал никаких притеснений. Мало того, мои знакомые, которые говорят только на русском, участвовали в Майдане в Киеве. Я очень внимательно следил за ситуацией из разнообразных источников и могу уверенно сказать - нет проверенных фактов ущемления русскоговорящих жителей Украины.

 

Что произошло в феврале 2014, если коротко: Народ сбросил власть бандитов. Другого способа не было. Выборы фальсифицировались. Судьи боялись выносить честные приговоры. В милиции пытали. Бизнес моих друзей отбирали. Страна превращалась в феодальное государство с крупными монополистами и их рабами. Все работали на Семью Януковича. Этим летом (за 3 месяца до Майдана!) во двор нашего многоквартирного дома заехали джипы без номеров, и молодчики на глазах у играющих детей битами и кувалдами разбили все клумбы с цветами во дворе, которые жильцы решили поставить, чтобы ограничить количество машин и чтобы было где играть детям. Милиция отказалась искать виновников. Так мы и жили в нашей стране с ощущением несправедливости и беспомощности. До февраля 2014.

 

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

 

После первоначального хаоса очень быстро все начало налаживаться. Например, здравомыслящие люди в сети начали самоорганизовываться, объединяться в виртуальные комитеты и строить новую страну. Выдвигались идеи. Изучался Грузинский опыт реформы силовых структур. Люди воспряли духом! Люди почувствовали весну (помните Пражскую весну? не прослеживаете аналогий?)

 

И тут — ввод российских войск. Шок. Я считаю, что Путин после потери влияния в Украине решил разыграть Крымскую карту. Конечно, ущемление русских это ложь, чтобы оправдать агрессию. Почему Россией не было предпринято действенных ПОЛИТИЧЕСКИХ шагов по урегулированию ситуации, начиная с декабря? Почему перед вводом войск не было консультаций с действующим правительством Украины? Цель Путина не в защите русских, и все здесь это понимают. Но цена этих политических игр может быть очень высока. Ценой может быть ВОЙНА! Я считаю, что Россия сейчас цинично убивает мою страну - доведенную до дефолта Януковичем и растерзанную, неокрепшую, но возрождающуюся после революции. Более того, Кремль превращает русских в агрессоров, вторгшихся на территорию суверенного государства. Вдумайтесь: русский народ — захватчик? В глазах всего мира? Это станет черным пятном в истории России!

 

Крестный отец моего сына стоял на баррикадах и видел смерть. Он адвокат и владелец компании, которая консультирует частных предпринимателей. Он просто больше не мог терпеть того, что происходило в стране. Другие мои знакомые сейчас стоят в Харькове около памятника Ленину, защищая его от “бандеровцев”. Да общество разделилось. Но я считаю, что мы сможем договориться сами. Нам не нужен для этого Путин. Мы его не звали. Я говорю это как русскоязычный гражданин Украины.

 

Как лично Вы можете нам помочь?

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

 

Почему это важно? Да потому что игры закончились. Потому что возможно это самый важный проект моей жизни - хоть как то помочь предотвратить эту войну. Да просто потому, что я не хочу стрелять в своего брата из Екатеринбурга из-за игр политиков!!!


Андрей Ткачук
Русскоязычный гражданин свободной Украины
http://mylifeorganized.net

Вы можете задать мне вопросы на этом форуме:

http://www.mylifeorganized.net/forum-ru/


P.S. Любые попытки посеять межнациональную рознь в комментариях (с любой стороны) будут жестко пресекаться. Хватит. Доигрались...

P.P.S. Ссылки для тех , кто хочет узнать правду:

 

Андрей Макаревич о войне с Украиной:

  1. Весь мир застыл в ожидании.
  2. Войну с Украиной захотели?
  3. Про мерзость.

Борис Гребенщиков: Будьте дальновидны: перестаньте натравливать одних людей на других. и Дорогая редакция телеканала Россия 24.

Помогите донести правду и остановить войну!

 

 


2014-02-11

04:46:27, Action Script 3
Unity3D обзор

Unity3D – один из самых популярных, кроссплатформенных движков для разработки игр. Что же в нем такого особенного и чем вызвана такая популярность этого движка.

  • В первую очередь, конечно, его стоимость. Не обязательно покупать PRO-лицензию для того чтобы начать делать игру. Функционал Free-версии, конечно, несколько ограничен, но работать с ней можно. Из прямых конкурентов похвастать подобным может разве что Torque 3D.
  • Во-вторых – кроссплатформенность. Unity3D позволяет создавать и портировать игры под Windows (в т.ч. и phone), Mac, Linux, iOS, Android, BlackBerry, Xbox 360, PS3, Wii, WEB-плеер. Такого набора поддерживаемых платформ нет, пожалуй, ни в одном из прочих движков.
  • В-третьих поддерживаемые языки программирования. Это C#, JavaScript и Boo, не буду говорить за всех, но для меня это несомненный плюс при выборе, скажем, между Unity3D и Unreal Engine, где в качестве ЯП используется UnrealScript.
  • И в-четвертых хорошая документация, активное сообщество и множество уроков, что тоже играет свою роль при выборе.

Из всего вышеперечисленного можно сделать вывод, что движок, как нельзя лучше подходит для небольших команд и инди-разработчиков. Впрочем, крупные компании тоже не обделяют Unity вниманием. Что подтверждает долгосрочный контракт  Unity Technologies с Electronic Arts  (есть уже и плоды – Need for Speed: World, а так же проект EA SPORTS).

О производительности и “красивости графики” говорить не буду. Это довольно спорный вопрос, здесь все больше зависит от прямоты рук, профессионализма моделлеров и дизайнеров. В сети много холиваров по поводу того, кто круче CryEngine, UDK или Unity3D, не будем начинать еще один. В любом случае уровень графики приличный.
Dead Trigger NFS World

Что, на мой взгляд, несколько нелогично в Unity – это работа с GUI, собственно это то, что я не могу визуально построить окно с кнопками, чекбоксами и прочим. Создавать их возможно только программно. С одной стороны это нормально и даже более привычно. Но кажется мне не совсем логичным, то, что строить трехмерные миры я могу тыкая мышкой, а чтобы собрать какую-нибудь пресловутую панельку с кнопочками надо написать пару десятков строк кода. Пока этот момент решается установкой дополнительных плагинов, будем надеяться, что в будущем прикрутят к редактору по умолчанию.

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

Из минусов не могу не подметить, что с движком идет очень скудный набор префабов, текстур и скриптов. Я понимаю, что каждая игра уникальна со своими моделями и прочим, но хотя-бы травы, деревьев и текстур земли можно было добавить и побольше, чем по две. Да и, скажем, скрипт симулирующий физику движения транспорта не помешал бы. Зато у нас есть обширный магазин ассетов, доступный прямо из редактора (меню Window -> Asset Store), в котором можно как купить себе готовые вещи, так и выставить свое на продажу.

Ну, и что мне режет глаз, это лапша из разношерстного кода. Вот пример, открываю Unity, кидаю на сцену стандартный компонент First Person Controller. И что я вижу, на нем висит три скрипта:

  • FPSInputController.js
  • CharacterMotor.js
  • MouseLook.cs

Что это за солянка, половина на JS, вторая на C#, хорошо хоть на Boo нет. Писали бы уж все на одном языке или дублировали, раз движок позиционируется как мультиязычный.

Кстати о JavaScript, он тут немного “не тот”, что мы привыкли видеть в браузере. В Unity3D js более “продвинутый” и похож больше на ActionScript. Хотя они все одного поля ягоды, так что проблем с этим возникнуть не должно. И не стоит полагать, что раз JavaScript, то будет все тормозить, как в IE. Скорость исполнения на достойном уровне, хотя и немного проигрывает скриптам на шарпе.

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


2014-02-03

04:00:21, Action Script 3
Получение минимального или максимального числа из массива

Пусть у нас есть массив чисел

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

12:37:04, Flash-ripper.com
Ну все, я понял

 rostislav.siryk@globallogic.com

Ищут эйчары, ищут рекрутеры, ищут не могут найти. А я найду. Пишите мне на rostislav.siryk жимейловый. 

Вилка зарплат -- острая, с четырьмя зубцами.


2014-01-27

06:51:54, Action Script 3
Правая и средняя кнопки мыши во flash

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

Начиная с версии Flash-плеера 11.2 появилось несколько новых событий мыши:

  • RIGHT_CLICK – клик правой кнопкой мыши;
  • RIGHT_MOUSE_DOWN – нажатие правой кнопки мыши;
  • RIGHT_MOUSE_UP – отпускание правой кнопки мыши;
  • MIDDLE_CLICK – клик средней кнопкой мыши;
  • MIDDLE_MOUSE_DOWN – нажатие средней кнопки мыши;
  • MIDDLE_MOUSE_UP – отпускание средней кнопки мыши.

И небольшой пример использования:

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

03:54:04, Action Script 3
Жизненный цикл Spark компонентов Flex фреймворка и базовые правила наследования компонентов

Для правильной работы со Spark компонентами и создания собственных компонентов, необходимо иметь понятие о том, как и по каким правилам они работают. Сегодня мы  рассмотрим базовые принципы, без знания которых невозможно эффективно использовать этот мощный фреймворк.

Итак, жизненный цикл каждого компонента во Flex фреймворке проходит следующие этапы:

  • создание (construction);
  • конфигурация (configuration);
  • подключение/присоединение (attachment);
  • инициализация (initialization);
  • инвалидация (invalidation);
  • взаимодействие (interaction);
  • удаление (detachment);
  • сборка мусора (garbage collection).


При наследовании компонентов разработчик может (должен) переопределять следующие методы:

  • createChildren();
  • commitProperties();
  • measure();
  • updateDisplayList().

Когда мы добавляем компонент с помощью mxml разметки

<local:MyComponent fontSize="12" width="100"/>

происходит следующее.

Сначала запускается этап создания, и инстанциируется экземпляр класса MyComponent. Затем происходит конфигурация, в течение которой компоненту выставляются свойства и стили, объявленные при добавлении компонента (применяются они позже). Пока внутри компонента не доступны свойства systemManager, stage, root и т.д. Но при этом могут вызываться get/set методы (конфигурация), поэтому при реализации необходимо правильно определять такие методы. Нельзя сразу применять изменения внутри метода, необходимо использовать валидацию.

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();
    }
}

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

Фазы инициализации:

  • устанавливается значение свойства parent;
  • событие «preinitialize»;
  • создание дочерних компонентов createChildren() (для скинируемых компонентов это порождает вызов attachSkin(), про скины мы поговорим в следующий раз);
  • событие «initialize», вызов метода инициализации initialize().

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

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 фреймворка используют отложенную валидацию изменений. Аналогично как мы делали выше с полем data: изменения сохраняются и помечаются как измененные, а валидация происходи позже. Это позволяется сохранить высокую производительность, в том числе за счет того, что изменения применяются не по одному, а сразу все. Чтобы сообщить флексу о том, что требуется валидация, необходимо вызывать один из методов инвалидации:

  • изменение свойств – invalidateProperties();
  • изменение размеров – invalidateSize();
  • изменение отображения – invalidateDisplayList().

Для применения изменения свойств будет вызван метод commitProperties(), именно его и надо переопределять в наследниках для применения изменения данных. Для определения необходимости обновления используются флаги (_dataChanged в примере с set data).

override function protected commitProperties():void
{
    super.commitProperties();

    if (this._dataChanged)
    {
        this._dataChanged = false;

        // Применение изменения поля this._data
    }
}

Отметим, что, так как валидация происходит после инициализации, то в методе commitProperties() уже доступны дочерние элементы, созданные в createChildren().

При валидации размеров будет вызван метод measure(), который устанавливает предпочтительные размеры (поля measuredWidth, measuredHeight, measuredMinWidth, measuredMinHeight). Замечу, что метод не будет вызван при установленных explicitWidth/explicitHeight (значения, присвоенные пользователем: <s:Label width="100"/>). Пример:

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;
}

Валидация размеров вызывает метод updateDisplayList(). При переоределении этого метода в наследниках здесь следует позиционировать и устанавливать размеры дочерних элементов. Также можно перерисовывать например фон. Актуальный размер компонента выставляется именно здесь. Вызов super.updateDisplayList() снова советую делать в конце переопределения.

По окончании инвалидации рассылается событие «creationComplete», после чего компонент находится в рабочем состоянии и доступен для взаимодействия с ним.

Когда компонент уже не нужен – он удаляется со сцены (методами удаления или выставлением флага visible=false). Если при этом больше не существует ссылки на объект или она слабая, то компонент будет удален из памяти сборщиком мусора. Обратите внимание, что ссылки на объект могут сохраняться при использовании обработчиков событий, биндига, сохранении в качестве ключей в словаре и т.д., поэтому не забывайте отписываться от событий, если больше не требуется его слушать.

Полезные ссылки


2013-11-29

17:48:11, Flash-ripper.com
Неожиданный null в JavaScript

Моей задачей было изменить поведение следующего JS-кода и я долго изучал первую строку, пытаясь понять ее логику:

Логика там была неслучайная: в истории файла было видно, что ее успешно и бережно изменяли до меня много раз. Изучая это выражение, я понял, что не понимаю настоящего (и задокументированного) поведения null в условных выражениях JavaScript. И про сами эти выражения.

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

Ответы -- под катом: null && true:

Кстати! На мастер-класс по Away3D / TypeScript / WebGL в Киеве осталось уже всего 3 билета по $75. Потом будут по $100.


14:03:01, Action Script 3
Изометрическая проекция с использованием библиотеки as3isolib

Что такое изометрия, простым, человеческим языком, – это псевдо трехмерная проекция, при которой все объекты повернуты к нам под углом в 45 градусов, так, что мы видим три стороны фигуры. При этом масштаб фигур не изменяется в зависимости от их удаленности. Доступных к общему пользованию изометрических движков на AS3 на самом деле не так уж и много, можно пересчитать на пальцах и двух рук хватит. Расскажу про один из них – as3Isolib.

Библиотека с открытым исходным кодом. Легко допиливается под свои нужды. Глюков особо замечено не было. Скоростью, правда, не хвастается, но и жутко не тормозит. В либе присутствует только базовый функционал по отображению и сортировке, все прочие навороты придется допиливать самому. Из недостатков могу подметить, что последнее обновление на Google Code было в 2010 году. Скачать саму либу можно здесь.

Итак как ее использовать. весь “изометрический мир” представляет собой одну (для простых проектов) или несколько изометрических сцен IsoScene, которые отображаются через вьюпорт IsoView. Создадим простейшую изометрическую сцену.

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(); 
		} 
	} 
}

Собственно сетку IsoGrid можно было и не добавлять, но тогда бы мы увидели просто пустой экран, что было бы не очень наглядно.

В библиотеке присутствуют стандартные примитивы например IsoBox, которые больше подходят для тестирования и отладки, чем для практического использования, но для примера вполне подойдут. Кроме того имеется IsoSprite, это уже более полезный объект, сам он не имеет внешнего представления и является контейнером для DisplayObject-ов. Проще говоря помещаем DisplayObject или набор нескольких в IsoSprite и они становятся частью “изометрического мира”. Добавим на сцену примитив IsoBox, IsoHexBox и IsoSprite.

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(); 
		}
	}
}

О чем здесь следует сказать. Устанавливать размеры объекта (setSize(width, length, height) нужно обязательно. Иначе он не будет принимать участия в сортировке. Это не размер DisplayObject‘a, а размер объекта в изометрическом мире.

Перемещать объекты по изометрической сцене не сложнее, чем по обычной, у всех изометрических объектов имеются методы moveTo(x, y, z) и moveBy(x, y, z). Первый перемещает объект в указанные координаты. Второй смещает объект на указанное количество пикселей относительно текущей позиции. Координаты конечно нужно указывать в изометрической проекции, а не в экранной. Самим ничего естественно пересчитывать не придется, для этого в библиотеке есть класс IsoMath с соответствующими статическими методами isoToScreen() и screenToIso(). Кроме того у объекта IsoView есть удобные методы для перевода координат isoToLocal(), localToIso().
Напишем код, который будет перемещать объект IsoBox в координаты клика.

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(); 
		}
	}
}

Как можно увидеть я беру не точные координаты клика, а округленные до ближайшего кратного GRIDSIDE (25), т.е. до ширины / длины ячейки. Хитрости никакой здесь нет, это делается чтобы объекты не пересекались, просто некрасиво.

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


2013-11-28

13:05:46, Flash-ripper.com
TypeScript + WebGL = веб-версия Away3D без боли JavaScript'а

TypeScript Logo Как известно, бум насыщенных веб-приложений разбудил интерес больших и маленьких компаний к интерактивно-медийному вебу. Все вспомнили о JavaScript, но писать на нем готовы далеко не все. Ведь по-человечески хочется делать, как на AS3, Java или C#. Поэтому хакеры и целые компании стали выпускать свои расширения (а иногда и сужения) для слишком уж динамичного JS. Одно из них -- TypeScript от Microsoft. Это полноценный язык программирования, обладающий двумя важнейшими характеристиками (помимо многих других достоинств):

  1. TypeScript обратно-совместим с JavaScript (кстати, за отсутствие этого ругают CoffeeScript) и компилируется в JS.
  2. TypeScript -- зрелый язык. На нем можно писать строго типизированный код со всеми преимуществами: традиционной ООП-структурой классов (интерфейсы, методы, геттеры-сеттеры etc.), компиляцией и проверкой на этом. А на выходе -- JavaScript!

Поддержка TypeScript уже есть во многих IDE, от Visual Studio и Eclipse до Sublime Text. А пару недель назад вышел COLT с поддеркой TSЯзык простой и эффективный, и этот потенциал заметили в Лондоне. Так появился он:Away3D Logo

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

15:59:24, Flash-ripper.com
Конспект встречи UAFPUG-44 в Харькове
О чем мы говорили на UAFPUG-44, какие книги, видео, статьи упоминались. Многое не записал -- прошу прощения, если еще что-то вспомните -- напишите! Итак,

Слайдшоу UAFPUG-44:
 
 
Блиц-доклады:
 
 
 
Рост
Варим кофе. Бюджетная домашняя машина на 15 бар: Zelmer Espresso 13z013
 
Антон
Новое во Flash Player: AIR 4 and Flash Player 12 Release Notes | AIR Labs
Атлас - иллюстрация: http://dev.boltcreative.com/PocketGod/TextureAtlas0.png
 
 
 
Игорь (Шаулов)
Мувики про текстурные атласы (там, после первого должно предложить еще пару)
 
Александр
Транслятор интерфейса: транслирует интерфейс Java-приложения в веб-приложение. С поддержкой IE7.
 
 
Женя
JS без браузера: http://PhantomJS.org
 
Олег
MapQuest
Коннектимся к Адоби Коннект, запускаем аппликуху, проводим урок / собеседование в игровой форме.
 
 
Игорь (Руссо)
Sigma. Рефакторинг непрерывен. 
 
 
--Конец блицев--
 
 
Доклады
 
1. Рефакторинг
 
 
 
2. Потрошим Arduino Starter Kit - Ссылка
 
Наш набор новичка:
 
 
Заказать Ardino Starter Kit можно здесь:
 
Пример умного дома (Алекс Хердт, Мюнхен): http://webdom.synology.me/
 

Подключение Arduino к Adobe AIR, ссылки:

 

Наш Hello World на Arduino:

 

Успех!

 
 
Розыгрыши призов
Розыгрыш билета на DevGamm, победитель: Александр. Поздравляем!
 
Книги
 
Темы (обсудили частично)
  • Психология программирования
  • Почему Программист может быть против математика (тест FizzBuzz -- как иллюстрация)
  • Freelance VS BodyShop (не успели обсудить )
 
Пицца
Заказывали здесь, вроде понравилось.
 
 
Аудитория: 198 (16 + 182)
- 16 человек на встрече. 
- По данным логов, онлайн-трансляцию нашей встречи смотрело 182 уникальных айпи-адреса.
Антон, спасибо еще раз огромное за трансляцию!
 
 
Фотки
 
 
Спасибо!
Всем, кто пришел -- моя благодарность, вы классные!
 
 
Рост
 
Мои контакты:

http://flash-ripper.com

Skype: Rostyslav.Siryk_globallogic.com
 
Важно!
Мастер-класс по Away3D Typescript в Киеве состоится за день до DevGamm. Еще есть билеты по $75, потом будут уже по $100. Анонсы: Твит Роба Бейтмана, анонс в блоге Away3D.com.
 

 


2013-11-18

15:18:36, Flash-ripper.com
Вышли Flash Player 12 Beta и Adobe AIR 4

Главные добавления в этом релизе:

  • Поддержка инсталляции .pkg на Mac
  • Встроенность в Windows 8 (Active X там больше не нужен)
  • Поддержка Internet Explorer 11 на Windows 7
  • Поддержка нового режима Safe Mode в Safari 6.1 и выше
  • Реализация 64-Bit PPAPI Flash Player для Chrome
  • Графика: новый флаг испольования буффера для Stage3D, Context3DBufferUsage
  • Android Workers -- улучшенные воркеры из AIR 3.9 (с учетом пожеланий сообщества).

Как компилировать под 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 3
Вдумчивый наблюдатель уже заметил, как незаметно Adobe AIR замещает собой Flash, особенно на мобильных устройствах. Фактически, мы уже имеем Flash Mobile, причем лучший за всю историю Flash. При этом он также -- лучший кросс-платформенный инструмент создания кросс-платформенных приложений!

2013-11-15

17:03:29, Flash-ripper.com
Харьков, последнее напоминание: завтра -- UAFPUG#44

Встреча состоялась, было очень круто! Давно  не узнавал столько нового. Следующая конференция в Харькове будет в 2014 году. 

Место: Харьков, офис GlobalLogic, ул Новгородская, 3б (карта). Время: 16 ноября 2013 года, 11:00-17:00

Программа:

  1. Flash Player 12 и Adobe AIR 4: что нового? Родион Субботин, Харьков.
  2. Безопасный рефакторинг: правда или вымысел? Роберт Самойлов, Харьков.
  3. Чем дышит железо. Технический рассказ об основах работы с видеокартами (ввиду последних тенденций). Основные понятия и факторы, влияющие на производительность. Андрей Андреев, Киев.
  4. TypeScript: в чем профит? Ростислав Сирык, Харьков.
  5. Актуальные вопросы флэш-производства. Круглый стол.
  6. Розыгрыш призов. Сюрприз!
  7. After Party! Как обычно - при любой погоде.

Хотите рассказать о важном?

Пишите в комменты или на rostislav.siryk@gmail.com

Как добраться?

Карта:

Тэги: 

2013-11-12

17:14:01, Flash-ripper.com
Видео-записи докладов со встречи UAFPUG-43 в Киеве

На встрече флэшеров в Киеве было интересно и тепло! Нам удалось сделать намного больше, чем планировалось. Было много дискуссий и новых планов. Все это можно увидеть ниже. Но сначала -- коротко обо всем, что было:

  1. Блиц-доклады: каждый рассказал немного о себе и о том, что его волнует. См. видео ниже.
  2. Лена Кузнецова рассказала о том, как не развалить проект. О популярных ошибках в работе команды, усвоенных на личном опыте. Смотрите видеозапись доклада.
  3. Перерыва не было -- мы были слишком увлечены!
  4. Иван Филимонов поведал девять тысяч важных сведений об асинхронном программировании. Изложил опыт лучших фреймворков, как клиентских, так и серверных. И презеновал фреймворк, этот опыт впитавший. Смотрите видео ниже.
  5. Разыграли главный приз. Победил Sergey 'sencher' Senkov, Киев, Avenue Games. Поздравляем!
  6. Обсудили близкий мастер-класса Роба Бейтмана по Away 3D TypeScript в Киеве 6 декабря 2013 г (за день до DevGamm 2013). Следите за объявлениями!
  7. Обсудили новую инициативу (тсс! все подробности потом).

Видео блиц-докладов с UAFPUG-43

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

Блиц: Иван Филимонов

Блиц: Михаил Ткачук

Блиц: Игорь Руссо

Блиц: Виталий Снитко

Блиц: Валерий Баштовой

Блиц: Александр Бурдун

Блиц: Лена Кузнецова

Блиц: Виктор Примак

 

Перейдем к докладам. Их было два, но они были объемными, а обсуждения заняли времени чуть ли не больше, чем сами доклады. Итак:

Доклад Ивана Филимонова на встрече UAFPUG-43: Асинхронное программирование

Презентация к докладу Ивана Филимонова

 

Доклад Лены Кузнецовой на встрече UAFPUG-43: Эффективная работа команды и наоборот

Презентация к докладу Лены Кузнецовой

Дискуссия после доклада Лены Кузнецовой:

Фото дискуссии:

Спасибо всем, кто пришел и сделал этот день таким интересным и вдохновляющим!

Ссылки:

  1. Презентация к докладу Лены Кузнецовой о командной работе: http://vk.com/doc13147855_231442402
  2. Презентация к докладу Ивана Филимонова о паттернах асинхронного программирования: http://www.slideshare.net/sunrize531/fpug-dzyga-presentation
  3. Фреймворк Dzyga, реализующий удачные паттерны асинхронного программирования из доклада Ивана Филимонова: https://github.com/wysegames/dzyga
  4. Регистрация на встречу UAFPUG-44 в Харькове -- харьковчане, не пропустите!


2013-11-07

18:30:38, Action Script 3
Поиск пути

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

Итак, как это работает. Алгоритмов поиска пути и их модификаций на самом деле достаточно много. Один из хорошо зарекомендовавших себя – AStar (А*), младший и более шустрый брат алгоритма Дейкстры. Его особенность в том, что он работает эвристически (грубо говоря интуитивно). Он обходит узел за узлом, переходя в теоретически наиболее ближний к цели узел, попутно корректируя путь, если это не так.

AStar

На сколько тот или иной узел близок к целевому определяется суммой расстояний от начального узла до текущего и от текущего до конечного. Например так:
2 3
g – стоимость пути от начального узла до текущего. Как видно на изображениях выше g складывается из стоимости всех пройденных узлов.
h – эвристическая стоимость пути от текущего узла до конечного. Мы не знаем ее наверняка, а рассчитываем, какова эта стоимость была бы если бы мы двигались по прямой.
На самом деле разные реализации алгоритма могут немного отличаться друг от друга. Здесь я рассчитываю h по теореме Пифагора, в других реализациях вы можете увидеть пересчет количества узлов до конечой точки или умножение вектора x на вектор y. Здесь всем заведует отношение скорости выполнения к возможной погрешности. Я же сейчас не ставлю перед собой задачи сделать наиболее быструю реализацию алгоритма, поэтому могу себе позволить более точные вычисления.

А теперь в коде:
Класс сетки/карты:

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 на более легкую. Вобщем желаю вам удачи в экспериментах!
И конечно же пример:
(клик – поиск пути и перемещение, Ctrl+клик – изменение проходимости узла)


2013-11-03

06:00:17, Action Script 3
Генератор шаблона регулярного выражения, определяющего значение числа в промежутке

При использовании регулярных выражений может встать задача написания шаблона, определяющего число из промежутка от 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

07:04:40, Action Script 3
Кастомный курсор мыши

Сама по себе тема создания своего курсора мыши довольно избита. Но сводится, как правило, к сокрытию “настоящего” курсора ОС и перемещению клипа в координаты мыши.
Мы побеседуем о другом. Как заменить “реальный” курсор ОС.
Начиная с версии Flash 10.2 у класса Mouse появились новые методы registerCursor для регистрации нового курсора и unregisterCursor, как не сложно догадаться, для обратной операции.
А так же свойство supportsNativeCursor, позволяющее проверить поддерживает ли ОС на которой выполняется ролик встроенные курсоры.
Внешний вид собственного курсора определяется классом MouseCursorData имеющий три полезных свойства:
data : Vector.<BitmapData> – вектор битмапдат – “кадров” курсора,
frameRate : Number – частота кадров анимации, да, да она может отличаться от frameRate самого ролика,
hotSpot : Point – активная точка курсора (по умолчанию 0, 0).

Преимущества перед “эмулированным курсором” на лицо:

  • Не нужно следить “а не перекрыл ли его новый добавленный DisplayObject”
  • При изменении масштаба ролика курсор остается не изменным
  • Нет артефактов при выводе мыши за пределы ролика
  • После клика пользователем правой кнопкой мыши не будет эффекта “двойного курсора”
  • ???
  • PROFIT

Ну и немного дегтя в бочку с медом, куда ж без него:

  • Максимальный размер курсора 32×32 пикселя.

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


(Клик для анимации)

Ну а теперь все вышесказанное в коде с комментариями:

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

12:43:37, Flash-ripper.com
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:
  • простое;
  • нет лишних звеньев, возможность прямого взаимодействия с сервером по RTP;
  • широкая распространенность и доступность JRE для конечного пользователя.
 
Кажется, что все идеально? К сожалению, в Java есть проблемы с DSP для VoIP. А это весь "must have" набор:
  • AEC (Acoustic Echo Cancellation);
  • AGC (Automatic Gain Control);
  • Adaptive Jitter Buffer;
  • Noise suppression.
Теперь представим звонок с Java апплета без гарнитуры (наушников с микрофоном). Если провести этот эксперимент ночью, поставив колонки на полную громкость, можно напугать соседей до заикания. Всё из-за эхоподавления. Его нет. Отсутствие AGC заставит ваших пользователей крутить уровень громкости (нормальный AGC должен делать это за пользователя, чтобы не было слишком тихо или слишком громко). А отсутствие Adaptive Jitter Buffer выльется либо в большую задержку либо в "choppy audio" – прерывистый неразборчивый звук. В результате качество коммуникации будет далеким от оптимального.
 
Все недостающие алгоритмы можно теоретически реализовать на Java, но есть пара проблем. Во-первых, реализовать универсальные и производительные алгоритмы (например AEC) достаточно сложно: такая реализация потребует высоких трудозатрат и расходов на R&amp;D. Во-вторых, реализация таких алгоритмов на Java может работать в несколько раз медленнее, чем на C/C++, что может повлечь серьезные проблемы с производительностью и перерасход ресурсов клиентского CPU.
 
Производители Java апплетов с функцией звонков реализуют собственные DSP процессоры или используют уже существующие решения на C/C++. Как правило, они подкладывают к апплету DLL библиотеки, которые берут на себя обработку вышеописанных DSP алгоритмов. В результате Java апплет имеет стандартные VoIP функции для обеспечения качественного звонка со всеми "must have" VoIP алгоритмами.
 
В конечном итоге остается два минуса Java:
  • кроссплатформенность - придется снабжать апплеты DLL библиотеками под Win и SO библиотеками под Linux;
  • сложность реализации этих DSP библиотек.
 
Довести DSP до отличного качества или купить соответствующие разработки может позволить себе не каждый вендор. То же касается поддержки различных аудио- и видеокодеков.
 
В итоге, Java можно назвать незаслуженно покинутой разработчиками платформой для браузерных звонков.
 
Незаслуженно покинута она по двум причинам:
  • недостаток встроенных возможностей по работе с DSP;
  • более распространенные для Web конкурирующие платформы, которые лишены такого недостатка.
О них далее.
 
 

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 в связке с сервером стал платформой для браузерных звонков, обладающей следующими функциями:
  • NellyMoser, Sorenson spark;
  • RTMP.
До полноценного браузерного 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:
  • Nelly Moser, Speex, G.711, Sorenson Spark, H.264;
  • RTMP, RTMFP;
  • AEC;
  • Adaptive Jitter Buffer;
  • AES шифрование.
Благодаря этим нововведениям, 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:
  • самый широкий охват браузеров;
  • привычная технология для разработчиков - Flex/AS3;
  • качественная VoIP передача аудио и видео.
Минусы Flash:
  • требует промежуточного сервера (не поддерживает открытые UDP протоколы, такие как RTP/SRTP);
  • относительно медленное улучшение VoIP части разработчиком (Adobe): отсутствие AGC, H.264 1 NALU per frame problem.
Кстати, что мешает разработчикам Flash Player внедрить WebRTC стек?
 
 

TOP 1 – WebRTC

И наконец, любимец публики, зомбирующая разработчиков, кошмарящая телекомов и  активно обсуждаемая технология WebRTC. Рынок живет ожиданиями, а в ожиданиях сегодня доминирует WebRTC.
 
На текущий момент WebRTC присутствует в трех распространенных браузерах в состоянии production:
  • Google Chrome;
  • Mozilla Firefox;
  • Mozilla Firefox mobile.
А также  в двух браузерах в состоянии beta:
  • Google Chrome Beta Mobile;
  • Яндекс Браузер.
Яндекс Браузер не проверяли, но по информации в сети, он не всегда корректно работает с WebRTC, поэтому мы поставили его в beta в нашем списке.
 
Даже в Chrome браузере WebRTC продолжает оставаться недоработанной, хотя уже прошло немало времени после релиза. Простые вещи работают, но когда дело доходит до смены состояния сессии по SDP (аналог re-INVITE в SIP) или при других нетривиальных действиях, появляются разные сюрпризы, которые сильно огорчают.
 
Однако это не мешает WebRTC завоевывать все новые умы и определять вектор развития VoIP и вообще интерактивных технологий в Web. И это не удивительно по двум причинам:
  • WebRTC поддерживается гигантами индустрии;
  • WebRTC имеет действительно удачную и продуманную архитектуру, избавленную от ошибок и недостатков, выявленных в браузерных плагинах, которые существовали до неё.
 
На технологической начинке 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:
  • полноценное VoIP в браузере
Минусы WebRTC:
  • недостаточно поддерживающих браузеров
  • отсутствие RFC (Cпецификации находятся в draft-ах и меняются, хотя нужно признать, что по сравнению с тем, что было год назад,  сейчас все более-менее стабильно).
  • отсутствие совместимости с традиционным VoIP (by design).
 
Ожидания и ресурсы, стоящие за WebRTC, с лихвой перекрывают текущие минусы, поэтому смело отдаем ей законное первое место TOP1 в списке браузерных технологий для VoIP.
 
Если же вспомнить, что остальные описанные здесь браузерные технологии Java и Flash – это  плагины (хоть и предустановленные в большинстве браузеров), то выходит, что WebRTC – это  единственная чисто-браузерная технология, которой в этом отношении нет аналогов.
 
Итак, мы закончили разбор трех технологий для web звонков, обобщим все описанное выше в виде следующих таблиц:
 

VoIP фильтры

 

Сетевые протоколы и спецификации

 

Аудио кодеки

 

Видео кодеки

 

Поддерживаемые браузеры

 
Некоторые пояснения:
  1. Все возможности Java клиента отмечены символом \\*. Это означает, что все вышеописанное может быть теоретически реализовано на Java. Вопрос в том сколько времени это займет, как хорошо это будет работать и сколько будет весить исполняемый файл со всеми библиотеками.
  2. С символами "плюс", "минус" и "вопрос" все должно быть понятно.
  3. В последний столбец таблицы было решено добавить для сравнения один из продвинутых VoIP софтфонов "традиционной" VoIP телефонии - Bria.
 
Ну вот и пришло время заняться подсчетом.
 
Некоторые функции, конечно, могут быть даже близко не равны по весу, но если считать в попугаях получается следующая картина:
 
Первое место в этой гонке VoIP технологий и коммуникационных протоколов занимает VoIP софтфон - 54% (21 попугай из 39). На втором месте WebRTC - 44% (17 попугаев из 39) и Flash, который идет за WebRTC с 41% (16 попугаев из 39).
 
В окончании, хотелось бы поставить вопрос: если мы строим облако для web-звонков с выходом на SIP/VoIP/PSTN, на чем мы будем это облако строить, какие материалы использовать?
 
Отвечая на этот вопрос, придется затронуть еще пару моментов. Первый из них связан с мобильными устройствами, второй - с проходимостью через брандмауэры.
 
Не секрет, что сейчас важна поддержка Android, iOS SDK и кроссплатформенность. С мобильными устройствами все более или менее понятно. Есть несколько вариантов:
  1. Adobe Air – тот же Flash с поддержкой тех же RTMP/RTMFP протоколов. Серьезный недостаток – нет эхоподавления. Преимущество – кроссплатформенность. Разворачиваем один и тот же код на Android и IOS.
  2. Браузер с поддержкой WebRTC. Недостаток – не очень удобно. Нативное мобильное приложение будет лучше в look and feel терминах.
  3. Портировать WebRTC код под IOS и Android. Недостаток – не кроссплатформенно и нетривиально.
  4. Использовать стандартный VoIP SDK с поддержкой SIP/RTP и портировать на IOS и Android. Недостаток – не  кроссплатформенно, несовместимо с WebRTC. Преимущества – совместимо  с традиционным VoIP оборудованием.
 
Теперь про брандмауэры(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
 

Предыдущие 30 | Следующие 30