Тежката артилерия - Flasm

Flashm - какво е това ли? Това е безплатен “command line assembler/disassembler” чрез чиято помощ ще можете да ровите във флаш филмчетата си на ниско ниво :) . На сайта на това “чудо” е описано доста подробно как и кога може да се ползва … можете да си оптимизирате кода от към бързина и т.н. … ама си е наистина “тежка” артилерия и не е за всеки :) Enjoy …

Архитектура на Флаш компонентите

От клас до компонент

Въведение:
Целта на тази статия е да покаже как можем да си направим простичък (елементарен) Флаш компонент, като започнем от писането на клас които ще управлява поведението на нашия компонент и завършим с .mxp файл които ще бъдем способни да споделим с останалите флаш потребители. В същото време ще разгледаме някои основни идеи при ООП (Обектно Ориентирано Програмиране). Първо нека да хвърлим бърз поглед върху това което ще получим като резултат. Не изглежда особенно сложно, както е и всъщност - просто обикновен slider които може да бъде конфигуриран от 0 до които номер бихте желали да го ползвате ( Пр. 100 ако искате да го ползвате за настройка на височината на звука или може би 360 за да го ползвате за въртене на някакъв movieClip). Идеята която ще разгледаме тук може да бъде приложена за създаването на доста по сложни компоненти. Нека започваме …
.FLA Файлът:
Нека започнем с направата на графичните елементи за нашия slider. Ние не искаме нищо претрупано, нищо твърде сложно като вид, като компонент трябва да го направим така че да може да пасне на всеки вид приложение с вида си. Не ни трябват някакви светещи мигащи или от сорта визуални ефекти, като начало предлагам семпъл “inner shadow” ефект които ще придаде дълбочина на нашия компонент.

-Големината има значение-
Един флаш разработчик трябва да мисли винаги поне 2 хода напред (като при играта на шах) в процес на разработване на своите проекти за да не се окаже в ситуация в която е можело да си спести доста работа а не го е направил. Този начин на мислене е много важен, първо да “видим” в съзнанието си пътя по които можем да направим едно нещо и после да го направим. Искаме да направим този компонент колкото се може по семпъл, първо ни трябва “dragger” ( така се нарича малкото нещо което влачим с мишката ) които ще се премества по _x (хоризонталата) от 0 до 100. Това е добър старт но ако се замислим за момента в които решаваме да позиционираме “dragger” мууви клипът, неговите граници ще излязат извън тези стоности (между 0 и 100). Примерно ако направим dragger мууви клипът 10 пиксела висок и 15 пиксела широк, и позиционираме неговата “registration point” в горния ляв ъгъл (както и ще направим) и след това позиционираме този мууви клип по хоризонталата на _x = 100 вътре в друг мууви клип, то този мууви клип ще се разпъне до 115 пиксела ширина (100 плюс неговите 15 пиксела). Поради тази причина ще направим нашият slidеr, 115 пиксела широк. Ето защо размерът има значение. По този начин като преценяваме нещата които трябва да направим можем да си спестим доста работа. Като цяло тези графични елементи които ще са скин-а/кожата на нашия компонент може да изглеждат както си поискате, може да направите просто елементарни правоъгълници или нещо по стилно във фотошоп. Акцента на тази статия не е графичните елементи на компонента а самия код които го изгражда.

Отворете Flash и създайте нов документ, след това създайте нов movie clip на сцената и го наименувайте “slider track” след това вътре в този movie clip създайте графичния елемент които ще е 115 пиксела широк и 10 пикселa висок, позиционирайки го на _x = 0, _y = 0 вътре в мууви клипа. След това създайте още един movie clip на сцената които ще наречем “dragger” - с графика в него 15 пиксела широка и 10 пиксела висока, позиционирате и нея на координати _x = 0, _y = 0 вътре в мууви клипа. И накрая създаваме последния 3-ти movie clip в които създаваме 2 отделни слоя, на първия слои завличаме от библиотеката на флаш по една инстанция на 2-та movie clip-а които създадоихме преди малко и ги подравняваме на координати _x = 0, _y = 0 и двата. “Slider track” movie clip-ът не е нужно да бъде наименуван. На “dragger” movie clip-ът задайте име на инстанцията “dragger_mc”( клик с ляв бутон на мишката върху инстанцията на movie clip-а и във properties панел-а, в полето “instance name” напишете “dragger_mc” без кавичките. Също така в Библиотеката на Flash извикайте linkage диалоговия прозорец на movie clip-а “slider track” и задайте “export for actionscript in the first frame” с името “Slider” също така напишете в полето AS 2.0 Class: “Slider” (без кавички). Това ще каже на флаш името на клас-а от които този movie clip ще вземе кода с които ще работи. Този клас ще напишем сега. Запазете този документ като Slider.fla.
Класът:
Създайте нов .as документ във флаш и го запазете с името “Slider.as” във същата директория където е и “Slider.fla” файлът. По принцип в самото началото може да поставите в коментар информация за вас (автор, дата, версия, употреба). Това не е задължително но се счита за добра практика.


/**
Slider класът връща стойностмежду 0 и дефинирана от потребителя стойност когато драгвате slider bar-а
@version: 1.0
@author: Димитър Грудев.
@date: 25FEV07
*/

Долу-горе по този начин може да изглежда тази информация в началото на клас-а.

Класовете винаги започват с ключовата дума class. В този случай знаем също, че нашият клип разширява възможностите на MovieClip класът. Като за начало пишем нещо такова:

class Slider extends MovieClip{ }

За тези които ООП са запознати с (Обектно Ориентирано Програмиране) нашият Slider клас ще наследи всички свойства и методи на MovieClip класът. За тези които не са запознати с ООП, това ще бъде кратко въведение в ООП. Следващата част може да бъде пропусната от разбиращите :)
Класовете:
Класовете са блокове от код на ООП програмни езици (какъвто е Actionscript 2.0). “Обектите” всъщност са инстанциите на movie clip-овe които се управляват от тези класове. Всички класове съдържат свойства и методи които позволяват ан инстанциите на тези класове взаимодействат с инстанциите на други класове в процеса на изграждане на функционираща програма. Кода вътре в един клас е така нар. “encapsulation” което ще рече (Encapsulation описва способноста на обекта да скрива свойте данни и методи от програмиста (като не го натоварва мисловно, и той може да не бъде въобще запознат с начина на работа на този клас/обект и се съсредоточи върху останалата част от кода която пише в момента) - това е един от фундаменталните принципи на ООП (Обектно Ориентираното Програмиране)). Нека хвърлим един поглед към класът. Предполагам сте запознати най-малко със класът MovieClip. Той има свойства (които могат да бъдат считани за променливи вътре в класът) като например “_width” и “_rotation” и има свои методи (които могат да бъдат считани за функции вътре в класът) като например “createEmptyMovieClip()”и “getNextHighestDepth()”. Благодарение на това свойство “encapsulation” което описахме какво значи по горе :) може да не знаете въобще как изглежда кода на класа но все пак трябва да знаете достатъчно за да накарате този обект да работи. Класовете съдържат също “event handlers” които са нещо като “onRelease” и “onLoad” които ви позволяват да комуникирате с други обекти във вашия Флаш проект. Ето как ще изглежда комуникацията с нашия обект (в псевдо код):

someObject.onSomeTriggeredEvent = function() {
thisObject.communicateSomeInformationTo(someOtherObject or itself);
}

Това е като цяло същноста на ООП. Ще се върнем към “event handler”-ите след малко. Първо нека да напишем още малко код.

Кодът:

Нека отново помислим какво целим да направим и да си изясним пътя по които да го направим. Сега след като знаем малко за класовете и ООП е време да помислим какви методи и свойства ще има нашият Slider клас. Както знаете нашият slider съдържа movie clip с име “dragger_mc”, следователно ще зададем такова свойство на нашият Slider клас. Също ни е нужна променлива/свойство което да определи максималната стойност до която нашият slider ще достигне. Ще наречем това просто “maxVal”. Ще ни е нужна и начална стойност от която да бъде стартиран нашия slider (например ако го използваме за контролер за звука може да искаме да го настроим да бъде стартиран по подразбиране от стойност 50, потребителя да си избира след това дали да увеличава още или намаля стойноста на slider-а) За тази цел създаваме променлива с име “initVal”. Може би най-важното своиство е “текуща стойност” на dragger елемента от нашия slider, затова създаваме и “curVal”. Сега да помислим какви методи искаме да има нашият slider, Имайте в предвид основните действия които може да извършва инстанцията на нашия slider. Бихме искали да има максимална и зададена по подразбиране величина с които да работи нашия slider, затова трябва д анаправим 2 метда с имена примерно “setMaxValue()” иi “setInitValue()”.

Логично бихме искали да можем да проверяваме тези зададени стойности на slider-а по всяко едно време затова създаваме и метод с името “getValue()”. Всеки клас също има и метод конструктор които е със същото име като клас-а(задължително!). Този метод се изпълнява в момента в които бива създадена нова инстанция на нашия компонент. ова ще рече че трябва да имаме и “Slider();” метод. Сега нека се върнем на идеята за “event handler”-ите както споменахме малко по нагоре, искаме нашия компонент да съобщава за промени със стойностите му на останалите обекти чрез т.нар. “broadcasting” или грубо казано “предаване/съобщаване за промяна”. В същност ще създадем метод с името “onChanged” които ще се извиква когато параметрите на нашия slider биват променени. Това се подразбира от концепцията на “listener”(слушател за събитие) обект които трябва да създадем. Тук няма да се спираме много подробно върху listener-ите и broadcastersобектите. Само ще споменем, че най-лесният начин да създадем тази функционалност на клас-а е чрез използването на Flash клас-а AsBroadcaster.

Няма да се впускам и в обяснения за работата на този клас, ще спомена само как да извикаме неговия метод “initalize()” които позволява други класове да прибавят и премахват “listener” и да съобщават за различни състояния. Използваики този клас трябва да добавим три допълнителни свойства на нашия Slider клас. “addListener()”, “removeListener()”, и “broadcastMethod()”. И накрая можем да започнем да сглобяваме това което изредихме до тук а то ще изглежда така:

// ***** PROPERTIES *****
// лични свойства - единствено достъпни вътре от клас-а.
// По принцип е добра практика да пазим свойствата private (лични).
private var dragger_mc:MovieClip;
private var curVal:Number;
private var maxVal:Number;
private var initVal:Number;
//
// свойствата нужни за използването на AsBroadcaster
public var addListener:Function;
public var removeListener:Function;
private var broadcastMessage:Function;

Нека започнем с написването на най-лесните методи, а това са именно “setMaxValue” и “setInitValue”. Това са методи които задават стойности на нашия компонент без които той неможе да работи правилно. Такива методи се наричат “setter” инък казано приемат някаква стоиност за да работи нашия компонент.

public function setMaxValue(val:Number):Void {
maxVal = val;
}
public function setInitValue(val:Number):Void {
initVal=val;
}

Нашите “getter” методи пък ще връщат някаква стойност (в случая стойноста на curVal свойството на компонент)

public function getValue(val:Number):Number {
return curVal;
}

Сега следва по сложната част - конструктор метода на нашия клас. Нашият конструктор трябва да дефинира всички не дефинирани до тук свойства, да извиква “initialize()” метода на AsBroadcaster класа, да си регистрира собствен listener (слушател) за събитие, и след това да “извика” семплия но много важен метод които ще инициализира действията на dragger_mc.

function Slider() {
// слагаме нашото maxVal свойство на100
if (maxVal == undefined) {
maxVal = 100;
}
// слагаме нашето initVal свойство по подразбиране да е от 100 до 0
if (initVal == undefined) {
initVal = 0;
}
// подаваме този обект към AsBroadcaster initialize() метода и го регистрираме като слушател за самия себе си
AsBroadcaster.initialize(this);
this.addListener(this);
// извикваме функциято която да инициализира нашия “dragger_mc”
initDragger();
}

и последния метод които ще напишем е реално метода които ще накара нашият слайдър да работи. Нашият “initDragger()” метод ще коригира всяка малка грешка ан потребителя, след това ще вкара в действие нашият dragger (които ще може да се влачи чрез мишката и ще съобщава за състоянието “onChanged” когато се движи).

private function initDragger():Void {
// правим референция към този обект
var thisObj:Slider = this;
// ако потребителя е задал maxVal свойството и получим НЕцяло число, загръгляме стойноста
if (maxVal % 1) {
maxVal = Math.round(maxVal);
}
// ако потребителя е задал maxVal да е 0 или отрицателна стойност, правим maxVal да е равно на 1
if (maxVal < 1) {
maxVal = 1;
}
// ако потребителя е задал initVal извън обсега на нашия slider,правим initVal да е равно на 0
if (initVal < 0 || initVal > maxVal) {
initVal = 0;
}
var ratio:Number = maxVal / 100;
dragger_mc._x = initVal / ratio;
dragger_mc.onPress = function() {
this.onMouseMove = function() {
thisObj.curVal = Math.round(this._x * ratio);
thisObj.broadcastMessage(”onChanged”);
updateAfterEvent();
};
this.startDrag(false, 0, 0, 100, 0);
};
dragger_mc.onRelease = dragger_mc.onReleaseOutside = function () {
delete this.onMouseMove;
this.stopDrag();
};
}

Ако прочетете внимателно кода в този метод ще забележите, че dragger_mc е зависим от стойностите на maxVal и initVal свойствата. Поради тази причина, всеки път когато тези стоиности се променят ще извикваме initDragger() метода. Нека сега се върнем към нашите “setMaxVal()” и “setInitVal()” методи и да добавим следния ред:

initDragger();

Ако не мислите за това, какво ще ни е нижно като функционалност на нашия клас, може да пропуснете по този начин важни редове без които нашия slider няма да работи или ще работи проблемно.

Като съберем всичко написано до тук се получава нашия Slider клас :) :

/**Slider класът връща стоиност между 0 и специфично зададената стойностслед като потребителя е завлачил компонента на сцената
@version: 1.0
@author: Someone
@date: 25JAN06
*/
//
class Slider extends MovieClip {
// ***** СВОЙСТВА *****
// “лични” свойства - достъпни само от класа, не и за “общо” ползваме така да го кажем :)
// По принцип е добра практика да пазим всички свойства “лични”(private).
private var dragger_mc:MovieClip;
private var curVal:Number;
private var maxVal:Number;
private var initVal:Number;
//
// свойства нужни за ползването на AsBroadcaster
public var addListener:Function;
public var removeListener:Function;
private var broadcastMessage:Function;
//
// конструктора ан нашия клас
//
function Slider() {
// задаваме maxVal да е равно на 100
if (maxVal == undefined) {
maxVal = 100;
}
// задаваме нашата initVal стойност по подразбиране на 0
if (initVal == undefined) {
initVal = 0;
}
// подаваме този обект към AsBroadcaster initialize() метода и го регистрираме като слушател за самия себе си
AsBroadcaster.initialize(this);
this.addListener(this);
// извикваме функцията за инициализиране на нашия “dragger_mc”
initDragger();
}
//
// “лични” методи
//
private function initDragger():Void {
// правим референция към този обект
var thisObj:Slider = this;
// ако потребителя е задал maxVal свойството да бъде определяно от някаква функция,тя може да ни върне дробно число.
//В такъв случай заклъгляме това число
if (maxVal % 1) {
maxVal = Math.round(maxVal);
}
// Ако потребителя е задал maxVal на 0 или отрицателно число, правим maxVal равно на 1
if (maxVal < 1) {
maxVal = 1;
}
// Ако потребителя е задал initVal извън обсега на slider-а , правим initVal равно на 0
if (initVal < 0 || initVal > maxVal) {
initVal = 0;
}
var ratio:Number = maxVal / 100;
dragger_mc._x = initVal / ratio;
curVal = Math.round(dragger_mc._x * ratio);
dragger_mc.onPress = function() {
this.onMouseMove = function() {
thisObj.curVal = Math.round(this._x * ratio);
thisObj.broadcastMessage(”onChanged”);
updateAfterEvent();
};
this.startDrag(false, 0, 0, 100, 0);
};
dragger_mc.onRelease = dragger_mc.onReleaseOutside = function () {
delete this.onMouseMove;
this.stopDrag();
};
}
//
// public methods
//
public function getValue():Number {
return curVal;
}
public function setMaxValue(val:Number):Void {
maxVal = val;
initDragger();
}
public function setInitValue(val:Number):Void {
initVal = val;
initDragger();
}
}

Запазете това, след това се върнете към .fla файла.

Тестване на класа:

Завлачете с мишката инстанция на Slider movie clip-ът от библиотеката на флаш на сцената. Задайте “instance name” mySlider и в нов слои сложете следния скрипт:

mySlider.setInitValue(50);mySlider.onChanged = function() {
trace(this.getValue());
};

тествайте проекта си (ctrl + Enter) и вижте какво ще се получи. Забележете как dragger-а застава веднага в центъра ан графиката която направихме. Завлачете го с мишката напред, назад и вижте как Flash трейсва от 0 до 100 докато го мърдате от единия край до другия. Запомнете, че вместо трейсването на стойностите можете лесно да изпълнявате някаква функция. Пример:

someSound.setVolume(this.getValue());

по този начин да контролирате височината на звука на flash mp3 плеър. Сложете този скрипт и тествайте отново.

mySlider.setMaxValue(500.25);
mySlider.setInitValue(-50);
mySlider.onChanged = function() {
trace(this.getValue());
};

Експериментирайте и вижте какво можете да нарпавите още с този пример. Можете да приспособите този клас за какъвто се сетите друг вид компонент, просто добавяте друга функционалност - планирате какво искате да направите и го правите :) експериментирайте и ще видите, че всичко е супер лесно. Можете да използвате компонентите и в случи когато някои колега или приоятел има нужда да ползва такъв компонент но не искате да споделяте работнте си файлове, предоставяйки му компонент той няма как да види кода ви, можете да сте спокойни :)

Компонентът
За да си починем малко от писане на код, нека направим още малко графики във фотошоп (или програмата която ползвате за да създавате .png файлове) Нека графиката която създадем сега бъде 18 пиксела широка и 18 пиксела висока и я запазете (save) като “icon.png”. Не ви трябва да е нищо прекалено кичозно, това ще е картинката която ще се показва в компонент панела когато нашия компонент бъде компилиран и инсталиран във Flash. Може би най-полезното нещо на компонентите е това, колко лесно могат да се разпространяват и преизползват във различни приложения (тяхната портативност). за да направим така, че като зададем няколко параметъра в parameters panel-a във Flash и нашият компонент да заработи без дори да сме написали и един ред код, трябва да добавим “metadata” на нашия клас. Metadata в даден клас е просто начина да кажете на Flash, че искате вашия компонент да наследи някакви свойства. За нашият простичък компонент единствените metadata които ще са ни нуни са “очакващ”(”Inspectable”) и “за икона” (”IconFile”) тагове. “IconFile” таг-а е себезадаващ се - т.е задава се от създателя на компонента а не от потребителя. Той казва на Flash кой файл да използва като икона за компонента. Отново в нашият Slider.as файл, след информативния хедър и преди декларацията на класа добавете този ред:

[IconFile(”icon.png”)]

“Inspectable” metadata таг-а ще казва на флаш, че следващото след него свойство на клас-а трябва да бъде “видимо” във parameter panel-а и да позволява на потребителя да въвежда стойности които ще определят как ще работи/изглежда компонента. Обратно към Slider.as файла добавете над реда деклариращ “maxVal” свойството следния ред:

[Inspectable(defaultValue=100, name=”Maximum Value”)]

Това казва на флаш че нашето maxVal свойство ще може да бъде задавано от parameter panel-а (в същото време ние все още ще можем да си ползваме нашия setMaxValue() метод) и неговата стойност би трябвало по подразбиране да е 100. “name” атрибута е името което Flash ще покаже във parameter panel-а. Без него Flash ще изведе като име, името ан свойството. В случая то би било “maxVal” което не е много ясно и потребителя може да се чуди каво е затова по добре да зададем този метод със стойност “Максимална стойност” или “Maximum Value”. По същия начин добавете над метода “initVal” следния metadata ред:

[Inspectable(defaultValue=0, name=”Initial Value”)]

Схемата на нашия клас би трябва да изглежда така:

[IconFile(”icon.png”)]class Slider extends MovieClip {

// ***** СВОЙСТВА *****

// лични свойства - достъпни само от вътрешноста на класа, не са за общо ползване.
// обикновенно е добра практика да се пазят свойствата “лични”(private).
private var dragger_mc:MovieClip;
private var curVal:Number;

// свойствата които се появяват във properties панела
[Inspectable(defaultValue=100, name=”Maximum Value”)]
private var maxVal:Number;
[Inspectable(defaultValue=0, name=”Initial Value”)]
private var initVal:Number;

// свойства нужни за AsBroadcaster
public var addListener:Function;
public var removeListener:Function;
private var broadcastMessage:Function;

// конструктор на класа

Обратно във .fla файла, изтрийте actionscript слоя и slider movie clip-а от сцената. Във библиотеката на флаш с десен клик върху Slider movie clip-а отворете “Component Definition” диалоговия прозорец. Във AS 2.0 Class полето “Slider” без кавичките и натиснете ОК. И вече можем да кажем, че нашия компонент е готов напълно, със иконка зададена му иконка.(Забележка: Ако иконката не се показва, трябва да отворите отново linkage диалоговия прозорец и без да правите никакви промени натиснете ОК) Завлачете инстанция на компонента на сцената и проврете parameter панела. Невероятно нали :) поекспериментирайте със стойностите за д апроверите как работи. Вече почти сме готови.

.MXP файлът

Единствения начин да споделите вашия компонент с други е да го пакетирате във .mxp файл. Този .mxp файл може да бъде разглеждан като архив файл които инсталира компонента автоматично следвайки зададени му инструкции. Тези инструкции се съдържат вътре във .mxp файла. Не позволявайте името му да ви плаши. Всички .mxp файлове са строго форматирани .xml файлове с по различно разширение. те могат да бъдат променяни със всеки текстов редактор. Ето и празния темплейт на такъв файл които можете да ползвате.

[UNKNOWN NODETYPE 4]

[UNKNOWN NODETYPE 4]

Забележете че .mxi файла търси за .swc файл. .SWC е всъщност вашия компонент. Едно от последните неща които все още не сме направили е да се върнем към .fla файла и с десен клик на вашия нов компонент и изберете “Export SWC File”. Запазете .swc файла във вашата работна директория (където са вашите icon.png, Slider.as) като “Slider.swc”. Сега настройте .mxi файла за да паснат нещата. Би трябвало да изглежда така:

[UNKNOWN NODETYPE 4]

[UNKNOWN NODETYPE 4]

За финал, отворете Macromedia Extension Manager и от File менюто, изберете “Package Extension”. Посочете вашия .mxi файл, селектирайте го и изберете ОК. И ето имате си компонент :) които можете да ъплоуднете в Macromedia Exchange, да го продавате в Ebay или да го споделите с приятели (казвайки им, колко трудно е било да го нарпавите).

Наслаждавайте се :)

Evolution of Beauty

Без коментар, тук думите са излишни.

“Джуркащ” се текст

ScrambleText” е елементарен AS2 клас, които изписва подадения му String в текстово поле разбъркано и след това го нарежда. Интересен е може да се доразвие :) оставям експериментите за вас ;)

Ето и пример как се ползва:

import ScrambleText;
var newScramble:ScrambleText = new ScrambleText();
this.createTextField(”my_txt”, 1, 100, 100, 300, 100);
stringToScramble = “Джуркащ се текст”;

newScramble.scramble(my_txt, stringToScramble);

www.yopark.com.hk

Днес попаднах на тази страница и тъй като имам слабост към красивите неща, особенно правени на флаш … реших да я споделя с вас :) www.yopark.com.hk