Оцените мой сайт
1. Отлично
2. Хорошо
3. Неплохо
4. Плохо
5. Ужасно
Всего ответов: 37
Главная » Статьи » Статьи о флеш

“Нарядная инициализация AS1 классов.”

Для начала хочется прибить читателя кодом:

#initclip this.set$$$Class = function() { delete this.set$$$Class; var $$$Class = _global.$$$=function () { this.init(); }; Object.registerClass(‘$$$_mc’, $$$Class); ASSetPropFlags(_global, "$$$”, 7, 1); var tmp = $$$Class.prototype=new MovieClip(); tmp.init = function() { }; }; this.set$$$Class(); #endinitclip

- не правда ли, странный код? Как думаете, сколько времени у меня ушло на его написание? Доли секунды. Во флэше, когда курсор на редакторе кода, я последовательно нажал три клавиши: Esc+s+c и получил этот код.

Не стоит пока пытаться повторить этот подвиг.

Чтобы фокус удался, нам нужно задать эскейп-последовательность.

Задаем эскейп-последовательность

Для начала нужно провести небольшие манипуляции с файлом ActionsPanel.xml. 
Он лежит в папочке C:\Documents and Settings\ИмяЮзера\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\ActionsPanel\

- разумеется ИмяЮзера это ваше имя пользователя на этом компе.

Итак, открываем (не ленимся!) ActionsPanel.xml и практически вначале, после строки

<folder name="Global Functions" id="Actions"........................

втыкаем следующий XML узел:

<folder name="Personal" id="Personal" tiptext="Presonal" helpid="">
<action name="setClass" tiptext="setClass" helpid="" text="#initclip\nthis.set$$$Class = function() {\n delete this.set$$$Class;\n var $$$Class = _global.$$$ = function () {\n this.init();\n };\n Object.registerClass(‘$$$_mc’, $$$Class);\n ASSetPropFlags(_global, ‘$$$’, 7, 1);\n var tmp = $$$Class.prototype=new MovieClip();\n tmp.init = function() {\n };\n};\nthis.set$$$Class();\n #endinitclip" quickey="sc"/> </folder>

Сохраняем XML, перезапускаем редактор Flash. Всё. Ескейп-последовательность добавлена. 
Теперь, при последовательном наботе Esc+s+c в окне редактора вставится заготовка класса. 

Дальше-проще. Например мы хотим создать знаменитый по всем детским учебникам класс Ball.

Жмем Ctrl+h (поиск и замена). Водим $$$ вверху и Ball внизу. Получаем результат:

#initclip this.setBallClass = function() { delete this.setBallClass; var BallClass = _global.Ball = function () { this.init(); }; Object.registerClass(‘Ball_mc’, BallClass); ASSetPropFlags(_global, ‘Ball’, 7, 1); var tmp = BallClass.prototype=new MovieClip(); tmp.init = function() { }; }; this.setBallClass(); #endinitclip

Теперь, собственно, можно приступить к изучению того, что мы натворили.



Приватные объекты

Первое и главное: Класс задается внутри метода-инициализатора класса, в данном случае это setBallClass. Этот метод удаляет ссылку на себя во время вызова, чтобы небыло лишнего мусора. 
Однако, сам метод не удаляется, он остается жить в памяти, вечная ему память за это!
Зачем такие замороки? Это позволит нам иметь приватные, т.е недоступные снаружи переменные, объекты и методы. 
Для дальнейших экспериментов модифицируем класс, снесем #initclip и #endinitclip
сделаем класс наследником Object, соответственно удалим registerClass.

Затем добавим локальную переменную my_array и присвоим ей ссылку на массив. 

Сделаем внутри метода init вызов trace с использованием ссылки на массив.

И в конце создадим экземпляр класса. Получим результат:

this.setBallClass = function() { delete this.setBallClass; var BallClass = _global.Ball=function () { this.init(); }; ASSetPropFlags(_global, ‘Ball’, 7, 1); var tmp = BallClass.prototype={}; var my_array = ["Hello, ", "world!"]; tmp.init = function() { trace(my_array[0]+my_array[1]); }; }; this.setBallClass(); // TEST foo = new Ball()// Hello, world!

Самое время заглянуть в листинг переменных. Ничего кроме созданного экземпляра класса мы не увидим. 
_global.Ball закрыт с помощью ASSetPropFlags
а массив my_array хоть и существует в памяти, но добраться до него невозможно, 
иначе, как из методов класса Ball

Вот вам и приватность. Это ооочень удобно. Правильная организация приватных/публичных объектов, 
когда у класса не торчат лишние уши, это здорово! 

Эти уши никакой другой класс или объект случайно никогда не чикнет. 

И к приватным объектам очень удобно обращаться: не нужно соображать по какому пути они находятся, 
они локальны и доступны в любом месте кода класса. 

Ссылки типа this.constructor легко заменяются на BallClass
который объявлен как локальная переменная. Сылки this.__proto__ заменяются 
на tmp.

Статические методы класса.

Сносим весь код, создаем мувик, обзываем его ball_mc
задаем такой же Linkage, рисуем в нем квадратик (всем назло) и слоем выше жмем волшебную комбинацию клавиш: 
Esc+s+c. Результат модифицируем ручками так, чтобы получилось следующее:

#initclip this.setBallClass = function() { delete this.setBallClass; var BallClass = _global.Ball=function () { this.init(); }; Object.registerClass(‘ball_mc’, BallClass); ASSetPropFlags(_global, ‘Ball’, 7, 1); var tmp = BallClass.prototype=new MovieClip(); tmp.max_width = 100; tmp.max_height = 100; var step = 2; BallClass.create = function(thisObj, name, depth, initObj) { var mc = thisObj.createEmptyMovieClip(name, depth); mc.beginFill(0, 100), mc.lineTo(10, 0), mc.lineTo(10, 10), mc.lineTo(0, 10), mc.endFill(); for (var i in initObj) { mc[i] = initObj[i]; } mc.__proto__ = tmp; BallClass.call(mc); return mc; }; var setDimentions = function () { if ((this._width += step)>=this.max_width) { this._width = this.max_width; } if ((this._height += step)>=this.max_height) { this._height = this.max_height; } if (this._height == this.max_height && this._width == this.max_width) { delete this.onEnterFrame; } }; tmp.init = function() { this._width = this._height=1; this.onEnterFrame = setDimentions; }; }; this.setBallClass(); #endinitclip


- я понимаю, дураков нет корячиться - набивать самому, если можно просто скопировать. 
Но совесть-то надо иметь. Если просят модифицировать ручками, надо модифицировать ручками, а не копировать.

Ок. бросаем на сцену мувик ball_mc и слоем выше втыкаем код:

Ball.create(this, "ball1_mc", 1, {_x:30, _y:50})

Тестируем, не верим своим глазам, восхищаемся результатом. 

Мы создали статический метод, create, который нам может быть очень полезным, в случае, 
когда предполагается, что данный класс может быть загружен извне динамически, 
а объект класса будет использоваться в другом ролике. 
В этом случае приаттачить мувик не удастся и нас спасет статический метод 
create.
Параллельно предлагаю маленький тренинг:
Выяснилось, что нам не нужны max_width и max_height 
в прототипе класса и Билл Гейтс дал указание сделать эти переменные приватными. Время пошло.
Ну как? Успели в отведенное время? За это вам повышена зарплата на $6000. 
Не стоит благодарности.

Что еще? или подводные камни

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

#initclip this.setBallClass = function() { delete this.setBallClass; if (_global.Ball) { return } // код дальше.... };<.code>

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

function myPrivateFunction (){ // code here }

и настоятельно рекомендуется использование такого синтаксиса:

myPrivateFunction = function (){ // code here }

Хотя эффект практически тот же, однако, в первом случае, 
компилятор во время компиляции перемещает функцию со своего места на самый верх. 
В итоге функция будет объявлена до кода:

if (_global.Ball) { return }

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

Автор: Ivan Dembicki aka Iv.

Категория: Статьи о флеш | Добавил: Falanga (13.12.2009)
Просмотров: 393 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Понедельник
13.05.2024
11:35


Логин:
Пароль:
Текст/Код

Онлайн всего: 1
Гостей: 1
Пользователей: 0
200


Хостинг от uCoz