/potapenko.com/articles/conveyor (part 2)/

Вернемся к настоящему

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

Конвейер, по сути, есть паттерн проектирования – Flash-паттерн. Он помогает бороться со сложностью, упрощая понимание поведения приложения.

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

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

Конкретный пример

Представим себе, что мы делаем реальное Flash приложение – рулетку.

Как статическая система приложение уже готово. Каждое конкретное действие реализовано в отдельных компонентах. Игрок должен нажать на кнопку «начать игру» и мы должны вывести игровой результат.

Как выводить игровой результат? Игровой результат не может возникнуть в один момент. Нам нужно показывать игровой процесс шаг за шагом.

Опишем эти шаги:

  1. Заблокировать интерфейс игрового приложения.
  2. Создать случайный результат. Произвести расчет результатов для ставок. Создать таблицу выигравших и проигравших ставок. Вычислить величину выигрыша–проигрыша для каждой ставки.
  3. Запустить анимацию колеса.
  4. После остановки колеса: вывести выпавшее число на дисплей и в виде гирьки на столе рулетки.
  5. Озвучить игровой результат: объявить голосом дилера номера, цвет и четность выпавшей цифры.
  6. Убрать все проигравшие ставки: создать анимацию движения стопок проигравших фишек в сторону дилера.
  7. С каждой выигравшей ставкой произвести анимационные действия:
    1. увеличение ставки,
    2. движения в сторону игрока,
    3. увеличения баланса игрока (на значение ставки плюс выигрыш)
  8. Разблокировать интерфейс игры.

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

Вот тут и начинается самое сложное. Как показывает практика, большая часть ошибок, сбоев, «глюков» приложения возникает при реализации последовательного вывода во времени.

Вот здесь и приходит на помощь конвейер.

Пишем код метода начала игры:


private function spin() 
{ 
  // заблокировать 
  // пользовательский интерфейс 
  this.lock(); 
  
  // вычислить игровой результат 
  this.createGameResult(); 
  
  // начать движение колеса 
  // (время 100 кадров) 
  Conv.put(this, "startWeel", "100"); 
  
  // остановить колесо 
  Conv.put(this, "stopWeel", 0); 
  
  // озвучить игровой результат 
  // (время - две секунды) 
  Conv.put(this, "gameSounds", 2000); 
  
  // анимационно убрать проигравшие 
  // ставки (на каждую ставку по 50 кадров) 
  Conv.put(this, "looses", 
    String(this.looses_array.length*50)); 
  
  // анимационно показать 
  // выигрыш всех выигравших 
  //(если такие имеются) 
  // на каждую ставку по 100 кадров 
  Conv.put(this, "wins", 
    String(this.wins_array.length*100)); 
  
  // разблокировать интерфейс 
  //игрового приложения 
  Conv.put(this, "unlock", 0) 
}

Метод lock блокирует пользовательский интерфейс. Метод createGameResult вычисляет игровой результат. Происходит вычисление суммы выигрыша, и создаются массивы проигравших и выигравших ставок. Анимируется выигрыш пошагово и в финале разблокируется интерфейс.

Здесь мы впервые встречаем имя Conv и метод put . Conv – имя класса реализующего механизм конвейера (сокращенно от Conveyor). Метод put помещает команду в конвейер.

Conv.put

Как же описать действия?

Чтобы выполнить действие нам нужно вызывать функцию. Если функция является методом объектом, то нужно указать объект и имя метода.

Нам нужно указать задержку. Или в миллисекундах или во фреймах.

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

Примерно так:


Conv.put(trace, 1000, "Hello!"); 

Conv.put(trace, 0, "World!");

В output последовательно выведется сначала слово “Hello !”, а через одну секунду будет выведено слово “World !”.

В данном примере мы задаем задержку в миллисекундах, а что если мы захотим задать задержку во фреймах timeline ?

Тогда будем вводить задержку в виде строки. Если нужна задержка 10 кадров – то пишем «10», если в один фрейм - то «1».

Например, мы хотим перемещать некий мувиклип по одному пикселю вверх-влево в каждый кадр и так десять раз?


for (var i=1;i<=10;i++) 
{ 
  Conv.put(any_mc, "moveBy", "1", -1, -1); 
}

Как видно из примера, все компактно и просто. Но нам не нужно каждый раз писать метод для таких простых действий, как перемещения.

А что если нам реализовать и работу с полями (properties)?


for (var i=1;i<=10;i++) 
{ 
  Conv.put(any_mc, "_x", 0, any_mc._x+i);
  Conv.put(any_mc, "_y", any_mc._y+i);
}

Опишем метод put конвейера в виде краткой спецификации:

Conv.put

Conv.put( function, timeout[, argument1, … argumentN] )
Conv.put( function, scope, timeout[, argument1, … argumentN] )
Conv.put( object, methodName, timeout[, argument1, … argumentN] )
Conv.put( object, paramName, timeout, value )

Parameters

function – ссылка на функцию, которую необходимо выполнить.

object – путь к объекту. Он может задаваться в виде ссылки и (если объект еще не существует в момент добавления действия) – в виде строки, например, “_root.any_object”.

methodName – строка, имя вызываемого метода объекта

timeout – строка или номер, задержка после выполнения. Строка – задержка во фреймах. Номер – в миллисекундах.

scope – ссылка на объект, то что при выполнении функции будет текущим пространством имен (this).

arguments – аргументы метода или функции

paramName – имя параметра объекта

value – значение параметра

Returns

Ничего

Description

Метод добавляет в конвейер действие. Действие состоит из объекта, действия над ним, параметров и задержки. Есть три варианта добавления действия:

В виде функции:

Conv.put(function, timeout[, argument1, … argumentN ])
Conv.put(function, scope, timeout[, argument1, … argumentN])

В виде метода объекта:

Conv.put(object, methodName, timeout[, argument1, … argumentN])

В виде изменения параметра объекта:

Conv.put (object, paramName, timeout, value)

Если действие это – выполнение функции, то указывается ссылка на функцию. В данном варианте можно указать дополнительный параметр – пространство имен ( scope ), чтобы функция выполнялась как «временный метод» объекта. И this в коде этой функции – будет относиться к этому объекту.

Если действие – это выполнение метода объекта, то указывается ссылка на объект и имя его метода в виде строки. Если объект еще не создан, и ссылку на него указать нельзя, то ссылку можно указать в виде строки.

Если действие – это изменение параметра объекта – то указывается ссылка на объект, имя его параметра в виде строки и значение которое нужно присвоить параметру. Если объект еще не создан, то ссылку на объект можно указать в виде строки.

Usage

Функция и параметры:


Conv.put(function(str) 
{
trace(str);
}, 1000, "Hello, World!");

Функция с указанием пространства имен (scope):


Conv.put(function(str) 
{
trace(this._name);
}, any_mc, 1000);
Объект, метод и параметры: 

_root.any_object = {}; 

_root.any_object.method = function(str) 
{ 
  trace(str); 
} 

Conv.put(_root.any_object, "method", 
  "12", "Hello, World!"); 

Путь к объекту в виде строки и его метод:


Conv.put("_root.any_object", "method", 
  "12", "Hello, World!"); 

_root.any_object = {}; 

_root.any_object.method = function(str) 
{ 
  trace(str);
}

Изменение параметра объекта

Conv.put("_root.textField_txt", "text", 
  "12", "Hello, World!");

Предыдущая часть | Следующая часть
[1] [2] [3] [4] [5] [6] [7]