[as2] Zestrzelił i uciekł - asteroids-textoids :-)
 Oceń wpis
   

Czyli zasada levelowania w asteroids. Które pisze Darek 3DH.

var speed:Number = 1;
var speed_const:Number = 1;
var speed_multiplier:Number = 2;
var speed_acc:Number = 0.2;
var speed_prevAccSpeed:Number = 0;
//
var shootOut_counter:Number = 0;
var shootOut_speedStep:Number = 3;
var shootOut_bonusStep:Number = 5;
var bonus_prevShootCount:Number = 0;
//
this.onEnterFrame = function () {
//
var output:String = "";// "\n" jeżeli chcesz dodatkowy odstęp (przy trace z flasha jest niepotrzebny - dodaje sam)
//
output += "Zestrzeliłeś asteroidę... ";
output += "zestrzelonych: " + shootOut_counter + " asteroid. ";
output += "Prędkość: wynosi " + speed + ". ";
shootOut_counter++;
//
if (!(shootOut_counter % shootOut_speedStep) && (speed_prevAccSpeed != speed))
{
 speed_prevAccSpeed = speed;
 speed = speed_const + int (shootOut_counter * speed_multiplier) * speed_acc;
 output += "No i przyspieszam do " + speed + ".";
}
if (!(shootOut_counter % shootOut_bonusStep) && (bonus_prevShootCount != shootOut_counter))
{
 bonus_prevShootCount = shootOut_counter;
 output += " I bonus nr " + int (shootOut_counter / shootOut_bonusStep) + " też się trafił.";
}
if (shootOut_counter == 200)
{
 delete this.onEnterFrame;
}
trace(output);
};
Skrypt symuluje grę w asteroids przy zadanych parametrach - level'owanie na podstawie prędkości, co 3 zestrzelone sztuki, wrzucanie bonusa co pięć zestrzelonych asteroid. Oczywiście jest to model - bardzo łatwy do połączenia z View.

Wynik działania:

Zestrzeliłeś asteroidę... zestrzelonych: 0 asteroid. Prędkość: wynosi 1. 
Zestrzeliłeś asteroidę... zestrzelonych: 1 asteroid. Prędkość: wynosi 1. 
Zestrzeliłeś asteroidę... zestrzelonych: 2 asteroid. Prędkość: wynosi 1. No i przyspieszam do 2.2.
Zestrzeliłeś asteroidę... zestrzelonych: 3 asteroid. Prędkość: wynosi 2.2. 
Zestrzeliłeś asteroidę... zestrzelonych: 4 asteroid. Prędkość: wynosi 2.2.  I bonus nr 1 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 5 asteroid. Prędkość: wynosi 2.2. No i przyspieszam do 3.4.
Zestrzeliłeś asteroidę... zestrzelonych: 6 asteroid. Prędkość: wynosi 3.4. 
Zestrzeliłeś asteroidę... zestrzelonych: 7 asteroid. Prędkość: wynosi 3.4. 
Zestrzeliłeś asteroidę... zestrzelonych: 8 asteroid. Prędkość: wynosi 3.4. No i przyspieszam do 4.6.
Zestrzeliłeś asteroidę... zestrzelonych: 9 asteroid. Prędkość: wynosi 4.6.  I bonus nr 2 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 10 asteroid. Prędkość: wynosi 4.6. 
Zestrzeliłeś asteroidę... zestrzelonych: 11 asteroid. Prędkość: wynosi 4.6. No i przyspieszam do 5.8.
...
...
Zestrzeliłeś asteroidę... zestrzelonych: 39 asteroid. Prędkość: wynosi 16.6.  I bonus nr 8 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 40 asteroid. Prędkość: wynosi 16.6. 
Zestrzeliłeś asteroidę... zestrzelonych: 41 asteroid. Prędkość: wynosi 16.6. No i przyspieszam do 17.8.
Zestrzeliłeś asteroidę... zestrzelonych: 42 asteroid. Prędkość: wynosi 17.8. 
Zestrzeliłeś asteroidę... zestrzelonych: 43 asteroid. Prędkość: wynosi 17.8. 
Zestrzeliłeś asteroidę... zestrzelonych: 44 asteroid. Prędkość: wynosi 17.8. No i przyspieszam do 19. I bonus nr 9 też się trafił.
...
...
Zestrzeliłeś asteroidę... zestrzelonych: 60 asteroid. Prędkość: wynosi 25. 
Zestrzeliłeś asteroidę... zestrzelonych: 61 asteroid. Prędkość: wynosi 25. 
Zestrzeliłeś asteroidę... zestrzelonych: 62 asteroid. Prędkość: wynosi 25. No i przyspieszam do 26.2.
Zestrzeliłeś asteroidę... zestrzelonych: 63 asteroid. Prędkość: wynosi 26.2. 
Zestrzeliłeś asteroidę... zestrzelonych: 64 asteroid. Prędkość: wynosi 26.2.  I bonus nr 13 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 65 asteroid. Prędkość: wynosi 26.2. No i przyspieszam do 27.4.
...
...
Zestrzeliłeś asteroidę... zestrzelonych: 90 asteroid. Prędkość: wynosi 37. 
Zestrzeliłeś asteroidę... zestrzelonych: 91 asteroid. Prędkość: wynosi 37. 
Zestrzeliłeś asteroidę... zestrzelonych: 92 asteroid. Prędkość: wynosi 37. No i przyspieszam do 38.2.
Zestrzeliłeś asteroidę... zestrzelonych: 93 asteroid. Prędkość: wynosi 38.2. 
Zestrzeliłeś asteroidę... zestrzelonych: 94 asteroid. Prędkość: wynosi 38.2.  I bonus nr 19 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 95 asteroid. Prędkość: wynosi 38.2. No i przyspieszam do 39.4.
Zestrzeliłeś asteroidę... zestrzelonych: 96 asteroid. Prędkość: wynosi 39.4. 
Zestrzeliłeś asteroidę... zestrzelonych: 97 asteroid. Prędkość: wynosi 39.4. 
Zestrzeliłeś asteroidę... zestrzelonych: 98 asteroid. Prędkość: wynosi 39.4. No i przyspieszam do 40.6.
Zestrzeliłeś asteroidę... zestrzelonych: 99 asteroid. Prędkość: wynosi 40.6.  I bonus nr 20 też się trafił.
Zestrzeliłeś asteroidę... zestrzelonych: 100 asteroid. Prędkość: wynosi 40.6. 
...
... 
Zestrzeliłeś asteroidę... zestrzelonych: 199 asteroid. Prędkość: wynosi 80.2.  I bonus nr 40 też się trafił.

Przy połączeniu z kontrolerem (GameManager/Controller) i z View bardzo prosto przejść do normalnej gry. Wystarczy linijkę shootOut_counter++; zamienić na wywołanie metody sprawdzającej skutek strzału/położenie pocisku względem obiektów do zestrzelenia.

Po linijce  speed = speed_const + int (shootOut_counter * speed_multiplier) * speed_acc; można dodać linijkę zmieniającą  wartość shootOut_bonusStep, która decyduje o ilości asteroid na jeden level. Np. na proste shootOut_bonusStep++; (czyli na każdym kolejnym levelu będzie trzeba zbić o jedną asteroidę więcej). Podobnie można też regulować wartość shootOut_bonusStep - np. dodanie shootOut_bonusStep++; spowoduje, że bonusy będą coraz rzadsze.

Wyobrażacie sobie grę w Asteroids w postaci tekstowej ? :D

PS. Z powodu niewłaściwego dobrania parametrów shootOut_counter (= 2) i speed_multiplier (= 0.2) zbyt szybko rośnie prędkość - od 1 do 80 w 66 leveli. To trochę za szybko. Choć w sumie: czy ja wiem ? :D

Komentarze (0)
Repeater: Interfejs - uniform, czyli garniturek
 Oceń wpis
   

Ten wpis może zawierać treści niewłaściwe dla osób niepełnoletnich... :D

Czasami ludzie pytają się mnie (podobnie jak ja kiedyś) po co ten interfejs ? No bo czytając definicję interfejsu niewiele moż na zrozumieć - jakaś klasa abstrakcyjna ? Implementacja ?

Przybliżając "na chłopski rozum" rolę interfejsu porównałbym go do kabelka z dwoma zestandaryzowanymi wtyczkami (czyli wszyscy wiedzą, co jest na jakim bolcu) - męską i żeńską, które łączą "jakieśtam" urządzenia - ale: za pomocą zestandaryzowanego protokołu. Po drugiej stronie kabelka może być cokolwiek - na kabelku może być cokolwiek, ważne jest, żeby wejscie (wtyczka żeńska :D ), była w stanie poprawnie odbierać to, co jest na wyjściu (gniazdo męskie :D ).

Mi akurat skojarzył się on z "garniturkiem" - jak uniformem: nieważne, co jest wewnątrz, kto to produkuje, ważne by na końcu wyglądało jak marynarka, spodnie, koszula i krawacik :).

A oto garniturek dla Repeatera:

interface flashfactory.pl.maw.interfaces.IRepeater {
          //
          function enable ():Boolean;
          //return false is Repeater was earlier enabled
          function disable ():Boolean;
          //return false if Repeater was earlier disabled
          function removeListener (obj:Object):Void;
          //deprecated: only for use with older projects (with Timer2.0)
          function addListener (obj:Object):Void;
          //deprecated: only for use with older projects (with Timer2.0)
          //
          function repeat (fn:Function, interval:Number, times:Number, group_id:String, as_first:Boolean):String;
          //main method: fn - funtion to repeat, interval - pause time, times - number of executions
          //repeat (fn:Function [, interval:Number [,times:Number [, group_id:String]]]):String
          //returns id of position of method
          function hold (id:String):Boolean;
          //hold ([id:String]):Boolean
          //returns true, if Repeater|member was earlier enabled
          function restore (id:String):Boolean;
          //restore ([id:String]):Boolean
          //returns true, if class Repeater|member was earlier disabled
          function reset (id:String):Void;
          //reset ([id:String]):Void
          function remove (id:String):Boolean;
          //remove ([id:String]):Boolean
          //returns false if no id found in methods table and cannot be removed
          function removeFromGroup (id:String, group_id:String):Boolean;
          //removeFromGroup (id:String[, group_id:String]):Boolean
          //returns false if group not exist or id not exist in group
          //remove id from current group or all groups
          function removeGroup (group_id:String):Boolean;
          //returns true if group was existing and removed
          function addToGroup (id:String, group_id:String, as_first:Boolean):Boolean;
          //returns false if id is incorrect, if group not exist, will be created
          //EventDispatcher methods
          function addEventListener ():Void;
          function removeEventListener ():Void;
          function dispatchEvent ():Void;
}
PS. Horrorek będzie kontynuowany... :]

Komentarze (0)
Repeater: lysta lysta i... I-lysta
 Oceń wpis
   

Po ostatnich zmianach lista metod publicznych wygląda  tak (żeby się nie powtarzać po każdej metodzie krótkie objaśnienie):

  •  enable ():Boolean
    enable zwróca wartość zmiany - a więc, jeżeli Repeater był załączony zwróci false, jeżeli był wyłączony, a został załączony to zwróci true, identycznie jak disable() zwróci informację, czy czasem repeater nie był wyłączony wcześniej:
  •  disable ():Boolean
    dodatkowo klasę Repeater wyposażę (podobnie jak Timer) w gettera i settera stanu enabled
  •  removeListener (obj:Object):Void
    (nic nie zwraca)
  •  addListener (obj:Object)
    (dwie powyższe metody zostawiam w takim stanie, jak są w Timerze)
  •  repeat (fn:Function [, interval:Number [,times:Number [, group_id:String]]]):String
    ta metoda jest sercem klasy - zwracana wartość typu string to unikatowy id przypisany naszej metodzie - uwaga! jest on różny od wpisanej nazwy grupy
  • hold ([id:String]):Boolean
    pan i władca klasy :) - zwraca info, czy Repeater był wyłączony przed zatrzymaniem
  • restore ([id:String]):Boolean
    druga metoda władcza :) - zwraca info, czy Repeater był zatrzymany przed przywróceniem
  •  reset ([id:String]):Void
    zeruje wszystkie liczniki ustawiając czas następnego wykonania metod na równy interwałowi
  • remove ([id:String]):Void 
    usuwa wszystkie powtarzane metody lub wybraną 
  • removeGroup(group_id:String):Boolean
    usuwa grupę, zwraca true jeżeli grupa istniała
  • removeFromGroup (id:String[, group_id:String]):Boolean
    usuwa metodę z grupy lub ze wszystkich grup
  • addToGroup (id:String, group_id:String):Void
    dodaje metodę do grupy - zwraca false, jeżeli metoda już w grupie wcześniej istniała, jeżeli grupa nie istnieje, założy ją

i na koniec niespodzianka - klasę wyposażę w możliwość rozgłaszania:

  • addEventListener():Void
    dodaje obiekt nasłuchujący
  • removeEventListener():Void
    usuwa obiekt nasłuchujący z listy słuchaczy
  •  dispatchEvent():Void
    "rozsiewa" event(y)

W przypadku metody repeate podanie interval, times i group nie jest obowiązkowe - jeżeli ich nie podamy metoda zadziała tak, jak byśmy używali oEFa, podanie interval (ms) spowolni wykonywanie tego "oEFa" (pod warunkiem, że interval będzie większy od czasu trwania jednej klatki - w przypadku 31 FPS będzie to więcej niż 33 ms), podanie times powoduje ograniczenie ilości wywołań metody do oznaczonej, a nazwa grupy group_id pozwoli na przyporządkowanie metody do określonej sekcji - dzięki temu rozwiąże się problem "dziedziczenia po Timerze" (pozwoli to na użycie "starej" składni) - i usuwa wcześniejsze ograniczenie Timera: jeden obiekt - jedna metoda.

A kto jeszcze nie załapał tytułu i komu jeszcze się nie nasunęło, z czym ta lista się kojarzy, temu mówię: właśnie przygotowałem podwaliny pod interfejs :)

Komentarze (0)
Repeater: powrót do źródeł
 Oceń wpis
   

Stwierdziłem, że najlepiej będzie, gdy Repeater będzie w 100% zgodny z (moim) Timerem. Od stwierdzenia do działania droga prosta - wypisałem wszystkie metody publiczne dostępne w Timerze:

  •   enable ()
  •  disable ()
  • get enabled ()
  • set enabled (_value:Boolean)
  • addListener (obj:Object, time:Number, todo:Function, times:Number)
  • removeListener (obj:Object)
  • public function Timer (_MC:MovieClip) ta deklaracja będzie zastąpiona konstruktorem klasy, tym razem na 100% prywatnym ze względu na jej singletonowy charakter (choć jak wiedzą as3-kowcy, na upartego z publicznym też da się go zrobić)

Dodałem do tego metody, które chciałem zaimplementować w Repeaterze jako natywne:

  • repeat (fn:Function, interval:Number, times: Number, group_id):String (-> id:String)
  • pause ([group|id])
  • play([group|id])
  • reset([group|id])
  • remove([group|id])

I podobieństwa od razu widać - addListener to szczególny przypadek wywołania metody repeat - z parametrem grop_id - wystarczy teraz wykonać rzutowanie w String, by mieć "zamapowaną" metodę addListener, podobnie removeListener to nic innego jak użycie metody remove z rzutowaniem argumentu obj w String:

public function addListener (obj:Object, time:Number, todo:Function, times:Number) {
//
repeat(todo,time,times,String(obj));
}

public function removeListener (obj:Object) {
//
remove (String(obj));
}

Uciekam od używania nazw "rozgłoszeniowych" z tego względu, że klasa ta z rozgłaszaniem nie ma ic wspólnego.

Rodzi się Wam pytanie, dlaczego tak gromadzę wywoływane metody w jednym miejscu, a nie rozgłaszam poszczególnym zainteresowanym przez dispatch-a ? Bo go nie lubię ;-) (żart :P )

Rozgłaszając zdarzenie, jakim jest oEF musielibyśmy w każdej metodzie obsługiwanej z określonego interwału sprawdzać odrębnie, czy czas tego interwału już minął - co oznacza, że musielibyśmy trzymać dla każdej metody odrębny licznik czasu ostatniego wykonania. W przypadku, gdy korzystamy z for .. in wewnątrz Repeatera, wszystko dzieje się w obrębie listy obiektów, gdzie sprawdzany jest tylko czas ostatniego wykonania zapisany przy danej pozycji.

Dzięki temu, że Repeater będzie "kompatybilny wstecz" - a więc poza zmianą w deklaracji zmiennej (var timer:Repeater = Repeater.getInstance(myMovieClip)) wewnątrz kodu klas wszystko pozostaje tak samo. Oczywiście addListener i removeListener będą już "deprecated" (w nowych projektach już ich nie będę używał), ale wolę zmieniać po jedej linijce w deklaracjach zmiennych(/wywołaniach klasy) niż szukać igły w stogu siana :).

Komentarze (0)
[as2] Żegnaj Timer, witaj Repeater
 Oceń wpis
   

Timer to fajna klasa - ale w as3 też jest - i to systemowo ;-). I troszeczkę inaczej się ją obsługuje niż mojego "tajmerka". No więc żegnaj as2-Timer, witaj Repeater.

Powstaje mały problem: dalej chcę się trzymać oEF-a (nie zależy mi na tym, co się dzieje "pomiędzy" klatkami - zależy mi na tym, co dzieje się "na początku" klatki) - dalej uważam, że jest on jak najbardziej regularnie działającą funkcją inerwałową, ale powoli moje szkice sprowadzają go do... multiInterwału. Tzn. w moim Timerze oznaczałeś listenera ścieżką bezwzględną klipa (_level0.costam.costam.tutaj.mojeMC) co oznaczało, że... mogłeś dla każdego klipa użyć danego interwału tylko raz. No a co, jeśli potrzebowałem dwa równoległe interwały ?

Nie tylko nazwa się zmieni, lecz także nazwy i wywołania metod. Nie - nie będę tworzył kopii 1:1 Timer-a z AS3 - w końcu to ma być repeater :P.

Więcej - wkrótce.

PS. Halooo!!! Jest tu ktoś jeszcze z as2/OOP ?

Komentarze (0)
Odliczamy w dół. Plus liczba ze stałą ilością miejsc (upd)
 Oceń wpis
   

Naprawdę, chyba prościej się zrobić nie da.

1. Minutnik

Jeżeli interesuje nas czas, który będzie za 5 minut to znaczy, że do obecnego czasu musimy pięć minut dodać. Proste.

Obecny czas w Actionscript zwróci nam new Date() bez parametrów.

Czas za 5 minut ? new Date () + new Date(0,0,0,0,5,0,0) Jak to przechowywać ? Najprościej w postaci milisekundowej, a więc Date.valueOf() się kłania.

Teraz wystarczy od otrzymanej na początku końcowej daty (ironia, co ? koniec na początku - żeby programy tak się pisały :D ) odjąć bieżącą, żeby otrzymać różnicę wskazującą, czy jeszcze jesteśmy w naszej pięciominutówce, czy też już jest "po ptokach".

No i omawiany skrypcik:

 //5 minut
var endtime = new Date ().valueOf () + new Date (0, 0, 0, 0, 5, 0, 0).valueOf ();
//
trace (new Date ().valueOf ());
//
function multiPosNumber (nr:Number, pos:Number):String {
 //
 var n:String = nr.toString ();
 var o:String = "";
 //
 for (var i = 0; i < (pos - n.length); i++)
 {
  o += "0";
 }
 return o + n;
}
function showCountDown () {
 //
 var d:Date = new Date (endtime - new Date ().valueOf ());
 var ss:Number = d.getSeconds ();
 var mm:Number = d.getMinutes ();
 var hh:Number = d.getHours ();
 //
 trace (([multiPosNumber (hh, 2), multiPosNumber (mm, 2), multiPosNumber (ss, 2)]).join (":"));

if (!hh && !mm && !ss) {

trace ("czas się skończył!!!");
delete this.onEnterframe;

}
}
//
this.onEnterframe = showCountDown;

2. Liczba stałopozycyjna

Dodatkowo jeszcze przemycił się nam drugi skrypcik: multiPosNumber - metoda dodająca do naszej wartości zadaną liczbę zer - można oczywiście ją jeszcze usprawnić, by była to dowolna liczba (nie tylko zero), a nawet "ogonek" - np. " zł". No ale to już możecie zrobić we własnym zakresie.

function multiPosNumber (nr:Number, pos:Number):String {
 //
 var n:String = nr.toString ();
 var o:String = "";
 //
 for (var i = 0; i < (pos - n.length); i++)
 {
  o += "0";
 }
 return o + n;
}

Wszystko w "formie tajmlajnowej". Z przerzuceniem do klas nie powinno być żadnego problemu.

Miłego używania.

//EDIT: Liczba stałopozycyjna to pojęcie z binarki (czyli stringi "001010" itp.), ale nie widzę problemu w tym, by metoda działająca na zerojedynkowym zakresie działała też w innym.

Ponieważ i parseInt, i Number.toString(radix) zwraca typ String, a u mnie potrzebny jest typ Number, musimy przed przekazaniem do metody zrobić proste rzutowanie na Number - czyli Number(liczba.toString(2)); zwróci nam np. 1011001, a nie "1011001" - z powrotem znowu otrzymamy String. Co chyba widać ?

Komentarze (0)
StageResizer: Nowa Funkcjonalność! (update pakietu)
 Oceń wpis
   

Nowa Funkcjonalność czyli ObjectResizer! Lub prościej: skalowalne okienka.

Zastanawiałem się ostatnio, co by było, gdyby StageResizer podpiąć pod "różne Stage'e" - np. jeden miał by 320x200, drugi 520x520 itd. itp... wtedy każdy obiekt miałby własną przestrzeń!

A co szkodzi na przeszkodzie ? Założenie. Założeniem tym jest, że StageResizer musi być unikatem.

No ale w prosty sposób za pomocą dziedziczenia idzie to zmienić - wystarczy napisać nowy konstruktor - z założenia "stary" (ten ze StageResizera) powinien się nie wykonać. No niestety nie ma tak dobrze - flash przy dziedziczeniu ignoruje parametr "private" konstruktora. Trzeba było w konstruktorze Stageresizera dodać "małego ifa", który powodował odrzucenie treści (zawartości) konstruktora, jeżeli zmienna myInstance była już zdefiniowana.

Druga przeszkoda: klasa opiekująca się obiektami  - StageResizerListener - odwoływała się zawsze do klasy StageResizer - stamtąd brała wartości. Znów trzeba było dokonać małej modyfikacji. Dzięki tej modyfikacji budowa ObjectResizera to dosłownie parę linijek. Nawiasem mówiąc w większości skopiowanych ze StageResizera.

Idąc za ciosem, korzystając z dobrodziejstwa dziedziczenia (co poniektórzy: nie śmiać się z literówek :D) wykonałem te parę drobnych zmian, które w działaniu możecie zobaczyć tutaj:

SWF: Przykład działania ObjectResizera (chwyć za szary kwadracik w lewym dolnym rogu zdjęcia, zdjęcia możesz przestawiać)

za pomocą takiego kodu (plus oczywiście wszystkie te rzeczy z pakietu stageresizerPackage) można dokonać tych cudów:

import stageresizerPackage.*;
import system.Delegate;
//
var stageresizer:StageResizer = StageResizer.getInstance ();
//
objectresizer.addListener (kolo, "TL").setScaleMode ("ShowAll");
//
function windowPress (MC:MovieClip) {
 MC.swapDepths (this.getNextHighestDepth ());
 MC.startDrag (false, 0, 0, Stage.width - MC.movingMC._width, Stage.height - MC.movingMC._height);
}
function windowRelease (MC:MovieClip) {
 stopDrag ();
}
function resizePress (MC:MovieClip) {
 MC.swapDepths (this.getNextHighestDepth ());
 MC.resizingMC.startDrag (true);
 MC.onmousemove = Delegate.create (this, setResizeValues, MC.resizingMC, MC.resizer);
}
function resizeRelease (MC:MovieClip) {
 stopDrag ();
 delete MC.onmousemove;
}
function setResizeValues (MC:MovieClip, resizer:ObjectResizer) {
 //
 resizer.setAreaSize (MC._x + 0.5 * MC._width, MC._y + 0.5 * MC._height);
 resizer.onresize ();
}
function makeMovable_n_Resizable (MC:MovieClip) {
 //
 MC.resizer = new ObjectResizer (MC.resizingMC._x + 0.5 * MC.resizingMC._width, MC.resizingMC._y + 0.5 * MC.resizingMC._height);
 MC.resizer.addListener (MC.movingMC, "TL").setScaleMode ("exactfit");
 MC.movingMC.onPress = Delegate.create (this, windowPress, MC);
 MC.movingMC.onRelease = MC.movingMC.onReleaseOutside = Delegate.create (this, windowRelease, MC);
 MC.resizingMC.onPress = Delegate.create (this, resizePress, MC);
 MC.resizingMC.onRelease = window1.movingMC.onReleaseOutside = Delegate.create (this, resizeRelease, MC);
}
//
makeMovable_n_Resizable (window1);
makeMovable_n_Resizable (window2);
makeMovable_n_Resizable (window3);
makeMovable_n_Resizable (window4);
makeMovable_n_Resizable (window5);
//
window1.gfxMC.gotoAndStop (1);
window2.gfxMC.gotoAndStop (2);
window3.gfxMC.gotoAndStop (3);
window4.gfxMC.gotoAndStop (4);
window4.setMask (window4.movingMC);
window5.gfxMC.gotoAndStop (5);
//
window1.resizer.addListener (window1.gfxMC, "TL").setScaleMode ("exactFit");
window2.resizer.addListener (window2.gfxMC, "CC").setScaleMode ("ShowAll");
window3.resizer.addListener (window3.gfxMC, "CL").setScaleMode ("width");
window4.resizer.addListener (window4.gfxMC, "CC").setScaleMode ("NoBorder");
window5.resizer.addListener (window5.gfxMC, "BR");
//
window1.resizer.onresize ();
window2.resizer.onresize ();
window3.resizer.onresize ();
window4.resizer.onresize ();
window5.resizer.onresize ();

Najważniejsze rzeczy - czyli ile linijek kodu trzeba, by "ruszyć" jeden obiekt - zaznaczyłem na zielono.

Jak to działa ? Praktycznie w identyczny sposób, jak StageResizer - pokażę na prostszym przykładzie:

var max_x:Number = MC1._width;
var max_y:Number = MC1._height;
var MC1_objectresizer:ObjectResizer = new ObjectResizer(max_x, max_y);
MC1_objectresizer.addListener(MC1.childMC,"TL").setScaleMode("exactFit");
MC1_objectresizer.onresize();

danemu klipowi przyporządkowujemy odpowiedni resizer, dopisujemy (addListener) do resizera potomka (klip podrzędny do klipu, w którym stworzyliśmy instancję objectresizera) i powiadamiamy go o zmianie parametrów onresize() - to jest konieczne, by dodany potomek "wysłuchał co ma zrobić".

A w przykładach moich mini okienek - wystarczy zmieniać (np. co pewien okres czasu lub co ruch myszy - jak w przykładzie) wartości maksymalne poprzez MC1_objectresizer.setAreaSize(max_x, max_y); i następnie wywoływać onresize(), by uzyskać efekt jak w przykładzie.

...no i oczywiście poprawiło się przy okazji parę bugów :)

Pakiet można pobrać stąd: stageresizerPackage.zip (zip, 113kB)

//EDIT: Ops, zapomniałem zaktualizować pakiet na serwerze ^^ - spróbuję zoptymalizować przykłady, żeby tyle nie ważyły...

//EDIT2: Zoptymalizowane ze 794kB do 121kB 113kB

//EDIT3: Dragowanie (pingwiny) poprawione

Komentarze (1)
StageResizer:Finał - StageResizerPackage v2.0
 Oceń wpis
   

O projekcie: projekt powstał na podstawie "szkicu" napisanego w as1 (z użyciem globali i takich tam innych mniej ważnych pierdół); pierwotnym jego celem (wersji 2) było wypróbowanie i konkretne zastosowanie mojej wiedzy nt. programowania obiektowego. Jak wyszło - sami widzicie.

Zawartość Pakietu

Na pakiet składają się dwie klasy główne: stageresizerPackage.StageResizer i stageresizerPackage.StageResizerListener, trzy klasy pomocnicze definiujące postać obiektów alignu, offsetu i skali (*ModesArrayItem.as)
oraz cztery pakiety podrzędne (foldery): interfaces czyli "wzorce klas", align czyli metody właściwe dla wyrównywania obiektów względem stage'u, offset czyli metody przesunięć zależne od wybranych metod wyrównania, scale czyli metody właściwe dla wybranego skalowania obiektu względem stage'u.

Uwaga: klasa StageResizer zmienia samodzielnie align Stage'u na "TL" oraz wyłącza ustawione scaleMode na "noScale".

Metody publiczne klasy StageResizer

W poniższych opisach metod tych klas będę omijał ścieżkę pakietu i odwoływał się do samych nazw. Tak samo w klasach podrzędnych.

1. Metody statyczne - pozwalają rozszerzyć klasy ustawień o dodatkowe funkcjonalności

addAlignMode (mode:String, alignXClass:IStageResizer_AlignX, alignYClass:IStageResizer_AlignY) dopisuje do istniejącej listy wyrównań nowy sposób wyrównania, przypisane klasy muszą być odpowiedniego typu interfejsu

addOffsetMode (mode:String, offsetXClass:IStageResizer_OffsetX, offsetYClass:IStageResizer_OffsetY) jak wyżej, odpowiada za dopisanie nowego offsetu

addScaleMode (mode:String, scaleClass:IStageResizer_Scale) odpowiada za dopisanie nowego sposobu skalowania - uwaga: metoda przyjmuje tylko jedną klasę działającą po X i Y równocześnie (takie rozwiązanie było konieczne ze względu np. na skalowanie proporcjonalne)

mapAlignMode (mode:String, targetmode:String):Boolean pozwala zamapować (dodać nową nazwę wywołania sposobu) mode w istniejący sposób wyrównania, zwraca false gdy mapowanie było nie udane

mapOffsetMode (mode:String, targetmode:String):Boolean jak wyżej, dla offsetu
mapScaleMode (mode:String, targetmode:String):Boolean jak wyżej, dla skalowania

2. SINGLETON

 StageResizer jest klasą typu singleton (unikat), a więc jej konstruktor jest prywatny, do wywołania klasy służy metoda getInstance() zwraca: (i tworzy) referencję do klasy

3. Metody publiczne dostępne po wywołaniu singletona

addListener (MC:MovieClip, onstagepos:String [, scalemode:String]):StageResizerListener - dodaje obiekt do listy słuchaczy klasy SR, zwraca referencję do obiektu nasłuchującego (uwaga!!! StageResizerListener != MovieClip); w przypadku dodania słuchacza tylko z jednym parametrem (onstagepos czyli align) klasa SR próbuje ten parametr przypisać pozostałym ustawieniom - a więc i offsetowi, i skalowaniu.

removeListener (MC:MovieClip) - usuwa obiekt z listy słuchaczy

addEventListener (MC:Object) - dodaje listenera do słuchaczy klasy Stage (uwaga!!! to jest tylko przekazanie, obiekt dodany tą metodą _nie_będzie_ miał stworzonego obiektu nasłuchującego w klasie SR!)

removeEventListener (MC:Object) - usuwa obiekt z listy słuchaczy klasy Stage (uwaga: jeżeli użyłeś wcześniej addListener, to obiekt pozostanie dalej w liście słuchaczy klasy SR)

dwie powyższe metody zostały dodane po to, by SR obsługiwała "kompleksowo" ułożenie obiektów na Stage'u, wraz z rozgłaszaniem.

setStageAreaAtStart (startwidth:Number, startheight:Number) ta motoda jest wywoływana w konstruktorze, na wartościach zdefiniowanych tą metodą opiera się przeliczanie wielkości w podstawowych metodach skalowania; domyślne wartości to Stage.width i Stage.height, lecz jeżeli potrzebujesz, by Twoje obiekty widziały "mniejszą rozdzielczość" użyj np.: setStageAreaAtStart(1024, 768);

setListenerAlignMode (MC:MovieClip, mode:String):Boolean
setListenerOffsetMode (MC:MovieClip, mode:String):Boolean
setListenerScaleMode (MC:MovieClip, mode:String):Boolean

te trzy metody powyżej pozwalają ustawić wyrównanie, offset, skalę dla danego obiektu bez odwoływania się do referencji obiektu słuchacza, zwracają false jeżeli obiekt jest nieprzypisany lub metoda nieznaleziona

setListenerOffset (MC:MovieClip, offsetX:Number, offsetY:Number) pozwala na ustawienie określonego parametrami offsetX i offsetY przesunięcia, o ile obiekt jest zarejestrowany w klasie SR

updateListener (MC:MovieClip):Boolean w przypadku zmian (np. rozwinęło się okienko, skończyła animacja) pozwala na aktualizację parametrów wyświetlania, jeżeli udana zwraca true; po wywołaniu metody wskazane jest wywołać "ręcznie" metodę onresize() klasy StageResizer

setListenerAutoOffset (MC:MovieClip, autooffset:Boolean) ustawia/przywraca automatyczny offset (uwaga: ta metoda może działać niepoprawnie)

onresize () przekazuje wszystkim obiektom nasłuchującym zajście zdarzenia Stage.onresize

notifyListener (listener) działa podobnie jak dla updateListener z tym, że odwołuje się do konkretnego obiektu nasłuchującego

4. Metody publiczne, których nie należy używać, jednak przydające się przy własnoręcznym rozszerzaniu pakietu

getAlignXMode (mode:String):IStageResizer_AlignX zwraca referencję do klasy przypisanej wyrównaniu wzdłuż osi X

getAlignYMode (mode:String):IStageResizer_AlignY jak wyżej, dla osi Y

getOffsetXMode (mode:String):IStageResizer_OffsetX zwraca referencję do klasy przypisanej przesunięciu wzdłuż osi X

getOffsetYMode (mode:String):IStageResizer_OffsetY jak wyżej, dla osi Y

getScaleMode (mode:String):IStageResizer_Scale zwraca referencję do klasy odpowiedzialnej za skalowanie

Metody publiczne klasy StageResizerListener

Metody te pozwalają na "szybsze" zmiany słuchacza. Ponieważ metoda addListener klasy StageResizer zwraca referencję do instancji klasy StageResizerListener, pozwala to na użycie bezpośrednie metod od razu po użyciu metody addListener np. stageresizer.addListener("bg","TL").scaleMode("exactfit");

1. Klasa SRL nie posiada metod statycznych

 i tyle na ten temat

2. Konstruktor publiczny: StageResizerListener(_MC:MovieClip)

 Uwaga: nie zalecam używania samodzielnego klasy StageResizerListener - i tak zostanie zainicjowana klasa SR i wg jej właściwości zostaną dobrane parametry obiektu.

3. Metody przydatne przy zarządzaniu ustawieniami

onresize () metoda wywoływana po przekazaniu zdarzenia Stage.onresize, uaktualnia właściwości obiektu

setAlignMode (mode:String):Boolean
setOffsetMode (mode:String):Boolean
setScaleMode (mode:String):Boolean

powyższe metody powodują ustawienie właściwych danemu stringowi "mode" klas ustawień

setOffset (ox:Number, oy:Number)
setOffsetX (ox:Number)
setOffsetY (oy:Number)

powyższe metody ustawiają offset odpowiednio: dla obu osi, dla oX, dla oY

4. Metody publiczne, których nie należy używać, jednak przydające się przy własnoręcznym rozszerzaniu pakietu

setAutoOffsetMode (mode:Boolean) nie obsługiwana

setAlignXBehavior (alignbehavior:IStageResizer_AlignX)
setAlignYBehavior (alignbehavior:IStageResizer_AlignY)
setOffsetXBehavior (offsetbehavior:IStageResizer_OffsetX)
setOffsetYBehavior (offsetbehavior:IStageResizer_OffsetY)
setScaleBehavior (scalebehavior:IStageResizer_Scale)

Metody "behaviorów" są odpowiedzialne za przypisane odpowiednich klas interfejsu (wzorzec strategia)

Właściwości publiczne klasy StageResizer

_actualWidth:Number
_actualHeight:Number
przechowują informacje nt. aktualnej wielkości Stage'u

_actualWidth05:Number;
_actualHeight05:Number;
jak wyżej, tylko dla środka Stage'u

_stageScaleX:Number;
_stageScaleY:Number;
przechowują wyliczoną "skalę" czyli zmianę obszaru Stage'u względem wartości podanych w metodzie setStageAreaAtStart

Właściwości publiczne klasy StageResizerListener

frozen:Boolean - wartość true powoduje opuszczenie metody onresize
alignMode:String,offsetMode:String,scaleMode:String - przechowuje łańcuch opisujący określone mode
dynamicOffset:Boolean - wartość true powoduje ominięcie przeliczania offsetu przy wywołaniu onresize
x0:Number, y0:Number, w0:Number, h0:Number, bounds:Object, s0y:Number, s0x:Number - przechowują wartości początkowe obsługiwanego klipu
offsetX:Number, offsetY:Number - przechowują "ręczne ustawienia" przesunięcia względem osi

Ze względu na bezpośrednie wywoływanie wartości przez klasę nadrzędną (SR), a także przez problemy przy delegacji (brak widoczności właściwości) poniższe metody także są publiczne, jednakże nie należy ich wykorzystywać poza sytuacjami, gdy wymaga to rozszerzanie pakietu

setXAlign:Function = function (_MC:MovieClip, oX:Number);
setYAlign:Function = function (_MC:MovieClip, oY:Number);
setScale:Function = function (_MC:MovieClip);
getXOffset:Function = function (_MC:MovieClip);
getYOffset:Function = function (_MC:MovieClip);
scaleBehavior:IStageResizer_Scale;
offsetXBehavior:IStageResizer_OffsetX;
alignXBehavior:IStageResizer_AlignX;
offsetYBehavior:IStageResizer_OffsetY;
alignYBehavior:IStageResizer_AlignY;

Tabela predefiniowanych wartości

Uwaga: ze względu na ułatwienia dla "szybkiego programowania" wszystkie stringi opisujące tryby ustawień są konwertowane na duże litery, a więc _wielkość_liter_jest_ignorowana_; litery są dobrane wg pierwszych liter nazw angielskich i w większości zgodne z parametrami Stage.align oraz Stage.scaleMode

Alignmodes

Nazwa
pozycja X
pozycja Y
mapowane
TL
lewo
góra
 
TC
środek
góra
 
TR
prawo
góra
 
LC
lewo
środek
CL, LM
C
środek
środek
CC, C%
HC
środek
brak
 
M
brak
środek
VM
M%
proporcjonalnie
środek
 
RC
prawo
środek
RM, CR
BL
lewo
dół
 
BC
środek
dół
 
BR
prawo
dół
 
T
brak
góra
 
T%
proporcjonalnie
góra
 
B
brak
dół
 
B%
proporcjonalnie
dół
 
L
lewo
brak
 
L%
lewo
proporcjonalnie
 
R
prawo
brak
 
R%
prawo
proporcjonalnie
 
V
brak
proporcjonalnie
H%, %V
H
proporcjonalnie
brak
V%, %H
R%
proporcjonalnie
proporcjonalnie
%%
*
brak
brak
*, none, noAlign

Offsetmodes

Ze względu na zgodność z trybami wyrównania, niektóre pozycje pomimo, że mają przypisane wartości, jednak nie wywołują żadnego przesunięcia; wszystkie przesunięcia są dokonywane względem środka obiektu wyliczonego na podstawie getBounds()

Nazwa
pozycja X
pozycja Y
mapowane
R
na lewo
brak
right, R%
L
na prawo
brak
left, L%
HC
wyśrodkowane
brak
 
VC
brak
wyśrodkowane
 
T
brak
poniżej
T%, top
B
brak
powyżej
B%, bottom
M
brak
środek
middle
noOffset
brak
brak
none, *, %, %H, %V, H%, V%
TL
na prawo
poniżej
 
TC
środek
poniżej
 
TR
na prawo
poniżej
 
LC
na prawo
środek
LM, CL
C
środek
środek
CC
RC
na lewo
środek
RM, CR
BL
na prawo
powyżej
 
BC
środek
powyżej
 
BR
na lewo
powyżej
 

Scalemodes

Podane metody są zbieżne z trybami skalowania klasy Stage

Nazwa
Metoda
Odpowiednik klasy Stage
mapowane
NoScale
brak skalowania
"noScale"
*, none
NoBorder
obcinanie
"noBorder"
 
Proportional
proporcjonalnie
brak
%, T%, B%, L%, R%
ShowAll
maksymalnie widoczne
"showAll"
 
ExactFit
nieproporcjonalne
"exactFit"
 
Width
dopasuj szerokość
brak
 
Height
dopasuk wysokość
brak
 
Vertical
na wysokość proporcjonalnie
brak
V%, %V
Horizontal
na szerokość proporcjonalnie
brak
H%, %H

W folderze $test znajduje się kilka przykładowych użyć projektu.

Uwagi końcowe

Do działania konieczna jest poszerzona delegata, która musi znajdować się w folderze system, jej kod to:
//****************************************************************************
//Extended Delegate - sends all parameters to the called function
//****************************************************************************
//
//
class system.Delegate {
 /**
 Creates a functions wrapper for the original function so that it runs
 in the provided context.
 @parameter obj Context in which to run the function.
 @paramater func Function to run.
 */
 //
 static function create (obj:Object, func:Function):Function {
  //
  var extraArgs:Array = arguments.slice (2);
  var f = function () {
   var target = arguments.callee.target;
   var func = arguments.callee.func;
   var args:Array = arguments.concat (extraArgs);
   return func.apply (target, args);
  };
  f.target = obj;
  f.func = func;
  return f;
 }
 //
 private function Delegate () {
 }
}
za tą delegatę możecie podziękować Semie(www.devlog.szemraj.eu) - bez niego nie udało by mi się do końca zrobić przekazywania parametrów i zwracania wyników.

Najprostsze użycie jako skalowanego tła:
Uwaga: nie odpowiadam za błędne działanie pakietu, za skutki uboczne i wpływ na inne metody jak np. efekty nadpisania flashowej klasy Delegate obecną delegatą, czy też błędne działanie z innymi managerami, nieprzetestowanymi we współpracy ze StageResizerem.

import stageresizerPackage.*;
//
var sr:StageResizer = StageResizer.getInstance();
sr.addListener(this.moje_tlo,"TL").setScaleMode("exactFit");
  No i jeszcze na koniec: dzięki Arthwoodowi zrozumiałem jak przydatne są interfejsy, Edi (Edicapo) spojrzał na mój kod krytycznym wzrokiem (przepraszam Edi, że Twoich uwag nie wykorzystałem :D), Arturowi (r2d2) za jego marudzenie "jak mi się chce", którym mnie czasami rozśmieszał do łez... no i wszystkim tym, którzy czytali wpisy o StageResizerze, choć się do tego nie przyznawali :)

A wpis ten ujrzeliście tak szybko dzięki temu, że na forum webesteem też są fajne ludziska w dziale flash ;)

Pakiet można pobrać stąd: stageresizerPackage.zip (zip, 52kB)

Komentarze (0)
[as2] Łindołize jurel.lel (windowizeURL, windowizeURLpath)
 Oceń wpis
   

Ot, taka zabawka stworzona z potrzeby wizualizacji ścieżki do pliku.

Wszyscy (piszący w as) wiemy, w jaki sposób flash pokazuje nam adres lokalny - jest to coś w rodzaju tego:

file:///F|/%5FMYDESIGN/%5FPUB/xyz/my%5Fapps.swf

Bardzo przyjemne i zjadliwe, nieprawdaż ? :D

No więc wyodrębnijmy elementy, które stoją nam na przeszkodzie:

- adres jest url-encoded (procenty)
- slashe zamiast backslashy
- "pipe" ( >|<) zamiast dwukropka po nazwie napędu
- określenie protokołu na dzieńdobry ("file:///")

ok, wyodrębnione, teraz przydałoby się jeszcze pokazać, gdzie znajdują się pliki lokalne - czyli pozyskać samą ścieżkę do pliku - czyli musimy odciąć nazwę pliku z rozszerzeniem. Najprościej to zrobić sprawdzając, gdzie "kończy się" nazwa foldera, w którym znajduje się nasz plik - czyli szukamy ostatniego slasha.

A oto cały kod:

 function windowizeURL(url:String):String {
  //
  return unescape((_url.substr(0,_url.lastIndexOf("/")+1)).split("file:///")[1]).split("|").join(":").split("/").join("\\");
 }
 function windowizeURLpath(url:String):String {
  //
  url = windowizeURL(url);
  return url.substr(0,url.lastIndexOf("\\")+1);
 }

Prawda, że ładnie skompresowane ?

Wynik ich działania na stringu zacytowanym u góry wygląda tak:

F:\_MYDESIGN\_PUB\xyz\my_apps.swf

F:\_MYDESIGN\_PUB\xyz\

i o to chodziło. Miłej niedzieli życzę.

MaW

Komentarze (0)
StageResizerProject - upublicznienie
 Oceń wpis
   

Prawie :)

Bo zanim wyedytuję ten post i wkleję linka do projektu, to mam do Was pytanie: czy jest ktoś chętny do testowania ? Zgłosić się we wiadomy sposób ;-) - można zostawić swój mail w komentarzach i ewentualnie jakieś info o sobie (jeśli się nie znamy ofc'rz :) ) - nie będzie publikowany.

No i zanim opublikuję kod wypadało by dokumentację metod opisać... mam nadzieję, że mi w tym pomożecie...

Taka uwaga ogólna: projekt jest pisany pod standardowym pakietem projektów flasha (*.flp), klip testujący wymaga ustawienia ścieżki do klas: [...]/system i [...]/ - z tego względu, że niefortunnie zastosowałem delegatę poprzez import system.Delegate; żeby dało się ją odróżnić od tej systemowej. Możecie za nią podziękować Semie - pozwala nie tylko na przekazywanie parametrów, ale także na ich zwracanie do obiektu wywołującego.

Podstawowe metody w postaci oznaczeń tekstowych są w plikach "predefined[Align|Offset|Scale]ModesList.as", można użyć i pojedyńczych wywołań jak stageresizer.addListener(MC,"BR"); jak i stageresizer.addListener(MC,"CL").setScaleMode("width"); oraz stageresizer.addListener(MC,"CC").setOffsetMode("none");

Zresztą po co ja to piszę ? wszystko można wyczytać z poprzednich wpisów projektu :)

Komentarze (0)
Jak przekazywać dane w MVC zbudowanym we flashu ?
 Oceń wpis
   

To bardziej prośba o rozważenie, niż pytanie :)

Tak siedzę przy tym całym "dobrodziejstwie" w postaci tysiąca linków, wskazówek, artykułów, książek - to za dużo na moją małą głowę :). Nasuwa mi się przy tym pytanie jak wyżej. Pytanie - zagadnienie.

Wielu z nas używa dziedziczenia po MC. Ja wolę stosować klasy z przekazaniem argumentu. W końcu to MC ma być dla klasy, a nie klasa dla MC (ok, to może być sporne, ale przyjmijmy, że mówimy o klasie typu manager).

Model, kontroler - singletony, rejestrowanie jak ? gdzie ? Przejmujemy wszystko tak jak leci z javy, czy mamy jakieś konstrukcje bardziej odpowiadające specyfice as2 (as3 to już całkiem inne podwórko, przyznaję - choć zasady podobne) ?

Flash jest nietypowy pod tym względem, bo przecież jeżeli używamy classmanagera przypiętego do klipa w bibliotece, to de facto zaczynamy od View, które normalnie w OOP powinno być skutkiem, a nie przyczyną...

Poza tym View flashowy też nie jest całkiem tak typowy - w odróżnieniu od javowego, jest interaktywny - działamy przecież na hitach, klipach z obsługą zdarzeń, timelinie...

Myślę, że to byłby bardzo dobry temat na flashowe spotkanie offline (Flash After Party).

Mam nadzieję, że z tego pytania wywiąże się jakaś fajna dyskusja na flabie.

//EDIT niestety, z dyskusji nic nie wynikło, Panowie Devowie mają klapki na oczach wyłącznie na frejmłorki - a szkoda...

Komentarze (3)
Skrypt dla "kroczącego wygaszania"
 Oceń wpis
   

Wyrzucam z projektu jako niepotrzebne, a by się nie zmarnowało... zostawiam na blogu.

Ten skrypt powoduje powolne "wygaszanie" (_alpha) kolejnych obiektów o nazwach group+[nr] od nr 8 do 1, ale bardzo prosto zmienić tą numerację na inną.

...wyrwane z większej całości - żeby nie było Wam za łatwo :P

 private function hideButtons (group:String, _MC:MovieClip) {
  //
  var i:Number = 8;
  var tMC:MovieClip;
  //
  do
  {
   tMC = MC[group + i];
   trace ([group, i, tMC]);
   //
   with (tMC)
   {
    if (!_visible)
    {
     i--;
     continue;
    }
    else
    {
     _alpha -= 10;
     if (_alpha <= 0)
     {
      _alpha = 100;
      _visible = false;
     }
     else
     {
      break;
     }
    }
   }
   i--;
  } while (i > 0);
  //
  if (i == 0)
  {
   timer.removeListener (_MC);
  }
 }

uwaga: potrzebuje Timer-a do inicjalizazji:

timer.addListener(_MC, 0, Delegate.create(this, hideButtons, group, _MC));

Komentarze (0)
Uwaga dla zmiennych prywatnych
 Oceń wpis
   

Zmienne prywatne - to te, których wartość ustalamy po stworzeniu nowej instancji (wywołaniu konstruktora) klasy.

O tym już było kilkakrotnie i na flabie, i na różnych blogach:

class Foo {

private var foofoo:String = String("coś");

public function foobutton (_MC:MovieClip) {

//ta metoda będzie potrzebna nam później

trace("to jest onrelease buttona "+_MC+", czy teraz jesteśmy w buttonie ? "+(_MC==this));

trace("Widzisz, że nie widzisz: " + foofoo);

}

public function Foo () {

trace("a teraz właściwość prywatna działa jak statyczna: " + foofoo);

}

}

^ tak zdefiniowana właściwość dopóki jej nie zdefiniujemy/nadpiszemy w metodach instancji, będzie funkcjonowała jak zmienna statyczna.

Ale nie o to mi teraz chodzi. Kiedyś znajomy na gg napisał mi, że w zasadzie po wyjściu z edytora (po skompilowaniu swfa) nie ma znaczenia, czy zmienne są prywatne, czy publiczne - do każdej można się odnieść bezpośrednio poprzez this.foofoo. Nieprawda. Właśnie się przekonałem, że w runtime maszyna wirtualna "pamięta", które są publiczne, a które prywatne.

Jak się przekonałem ? W prosty sposób:

//kod w klatce

import Foo;

import Delegate2;//Delegate2 pozwala na przekazywanie zmiennych - np. kod delegate z mojego bloga (choć polecam wyguglać delegate2)

var myButton:MovieClip;

var foonstance = new Foo();

myButton.onRelease = Delegate.create(foonstance, foonstance.foobutton, myButton);

myButton.onRelease();

wystarczy zmienić private na public właściwości foofoo, by jej wartość pojawiła się w output zamiast undefined.

Komentarze (0)
[as2]Singleton: czy konstruktor musi być prywatny ?
 Oceń wpis
   

Ha! Panowie FlashDeveloperzy! OOP nie kończy się tylko na standardzie ECMA :>

Tuż za rogiem maliboo głosi peany na cześć 10tego flashPlayera (żeby nie było, że "znowum przegapił" - czytaj: nie wspomniał), a ja męczę te OOP starając się wycisnąć każdą kropelkę - tfu, każdą literkę - z ust moich rozmówców.

Skończyłem właśnie rozmowę ze znajomym (nie chce się podlinkować skubany, no!), który nie jest nikim szczególnym - ot, pisze doktorat z informatyki :]. O co sprawa poszła ? Bo w końcu co osoba pracująca na całkiem innej platformie (nie wiem, czy to był .net z pythonem, czy .python przez .net - wthw ?) może powiedzieć "flashowcowi" ?

Otóż rozmawialiśmy sobie o wzorcach (czego mi jeszcze brakuje :]). Oczywiście nie można było nie wspomnieć o singletonie i o gromach, jakie zebrałem za "niezgodne ze wzorcem" zmodyfikowanie klasy, które to jak się wydaje, poleciały na mnie całkiem niesłusznie.

Ci, którzy starają się trawić OOP już w trzeciej wersji Action scriptu (as3.0) wiedzą, że nie ma tam konstruktorów prywatnych. I uważają to za ciężką przeszkodę.

Mając problem z niekończącą się pętlą przy StageResizerze pomimo zabezpieczenia singletonem nie wpadłbym na to, że takie rozwiązanie będzie podstawą "wykładu" mojego znajomego.

Otóż: programiści dzielą się na programistów różnych poziomów. Jedni zajmują się programowaniam strukturalnym, inni programowaniem poziomu aplikacji. Jego zdanie jest takie, że propgramistów aplikacji wogóle nie powinno obchodzić, czy klasa, którą będą używać, będzie singletonem, czy wielokrotną. Co oznacza, że wywołanie sinlgetona powinno się odbywać tak samo, jak wywołanie "zwykłej" klasy...

Zapewne mi nie wybaczy, jak powiem, że połowy z tego, co mówił (pisał) nie zrozumiałem, ale żeby zrozumieć ocb skoczyłem po rozum do głowy, a tam czytam:

Mający wpływ na rozwój języka Python, pracujący obecnie dla Google Alex Martelli, członek Python Software Foundation, twierdzi, że języki obiektowe tak naprawdę nie potrzebują Singletonu. Twierdzi on, że jak długo będziemy dbać o to, by współdzieliły pewien abstrakcyjny stan, tak naprawdę spełniamy warunek, (potrzebny do tego by jeśli zaistnieje taka potrzeba) ażeby ów stan był unikatowy. Kontrolowanie by liczba instancji danej klasy była najwyżej równa jeden, jest tylko jednym ze sposobów (cytat za: wikipedia, wzorzec singletonu)no i git. Mi się to też wydaje jak najbardziej logiczne.

Komentarze (0)
StageResizer - Obywatelu, w tył zwrot i jeszcze raz
 Oceń wpis
   

Zmiana kontekstu metod. Say'z'gon - jeszcze dziś w południe pisałem jak to fajnie ominąłem problem z singletonem. Pomyśleć, że na nic to było - choć wiadomo, na przyszłość w głowie conieco pozostanie (przyda się wiedzieć, jak obejść taką sytuację).

StageResizer - rzut okiem na blat...
Niestety, okazało się, że wszystko na próżno. Z mojej winy. Napisałem wczoraj, że zostawiam sobie klasy skalujące na koniec. Niewybaczalny błąd. Być może nie wystąpiłby wtedy, gdybym zajmował się tylko projektem SR, a nie brał się za niego w wolnych momentach... niestety, stało się.

Aby skalować obiekt proporcjonalnie (bo to akurat mam teraz na blacie) muszę znać jego wielkość początkową - obojętnie, czy _width i _height, czy _xscale i _yscale - muszę korzystać z wartości początkowych klipu.

Oznacza to jedno - że istnieje potrzeba przekazania większej ilości zmiennych do klasy behawioralnej, niż tylko referencja do klipu. Można to zrobić albo poprzez wyłapywanie tych zmiennych z tabeli argumentów metody, co IMHO jest wogóle nieoopowe - bo cokolwiek bym nie wyłapał, nie będę wiedział jakiego jest typu i czy jest to akurat to, co chciałem pobrać - jak również można to zrobić wywołując daną metodę w kontekście listenera, którego ta metoda dotyczy.

Taaak... oświeciła się lampka. Flashowcy mają odpowiednie metody na to - ruszyła w ruch kiedyś przeze mnie pisana delegacja.

Szkoda, że nie mogę się trzymać stricte wzorców, jak zakładałem, ale wszyscy musimy pamiętać o tym, że to nie my jesteśmy dla definicji, lecz to definicje są dla nas.

 Założenia projektu (link do wpisu).

//EDIT: I taka duża edytka: nie ma tak fajnie, jak by się chciało. Po pierwsze: nie patrzcie na moją starą delegację, jest do kitu (link usuwam). Po drugie: aby korzystając ze wzorca korzystać ze zmiennych lokalnych przy delegacie, musimy mieć je w dwóch miejscach: w klasie kontekstowej oraz w definicji klasy, której metodę będziemy delegować.

Miałem ja ci taki wzór (na skróty):

//w SRListenerze:
private var _stageresizer:StageResizer;
private var MC:MovieClip;//ok, ładnie się ustawiło
private var offsetX:Number;
var setXAlign:Function = function (MC:MovieClip, offsetX:Number) {};

//a teraz fragment podmiany:
setXAlign = Delegate.create(this, alignXBehavior.setXAlign);

//przy onresize:
setXAlign(MC,offsetX);

//wewnątrz (i na zewnątrz) przypisanej metody:
private var _stageresizer:StageResizer;
public setXAlign(MC:MovieClip,offsetX:Number) {
//
trace([MC,_stageresizer._actualWidth05,offsetX])
}

a w output:

undefined,477(lub inne wartości, zależnie od wielkości Stage'u),undefined

kto mi powie, gdzie był błąd ? a dokładniej (podpowiem :) ) - dwa (w zasadzie - jeżeli liczyć odrębnie każdą zmienną, to cztery, a jak się ktoś uprze, to nawet sześć - całkowicie pojedyńczo) ?

Komentarze (0)
StageResizer - problemy z singletonem
 Oceń wpis
   

Singleton to konstrukcja (wzorzec) zabezpieczająca nas przed stworzeniem więcej niż jednej instancji klasy. Jak ważny jest singleton, przekonałem się przy tworzeniu klas centrujących.

Korzystają one z raz wyliczonej w SR pozycji _actualWidth05 i _actualHeight05. Ponieważ żeby nie komplikować sobie sprawy z delegacją, skorzystałem z klasycznego rozwiązania wzroca strategii - podmieniam klasę - behaviora. Przez co muszę przekazać jej klip, na którym działa, oraz wartość offsetu.

W przypadku klas centrujących (i nie tylko ich, ale o tym za niedługo) muszą one także pobrać referencję do instancji SR. No więc... grzecznie i pięknie:

 public function SR_AlignX_Center () {
  //
  _stageresizer = StageResizer.getInstance ();
 }

a tak wygląda metoda SR.getInstance():

 public static function getInstance ():StageResizer {
  //
  if (myInstance == undefined)
  {
   trace ("creating new stageresizer by Singleton.");
   myInstance = new StageResizer ();
  }
  //trace ("return instance"); 
  return myInstance;
 }

efekt ? jak widać:

256 levels of recursion were exceeded in one action list.
This is probably an infinite loop.
Further execution of actions has been disabled in this movie.

Dlaczego ?

Ponieważ w kostruktorze wywołuję metodę, która definiuje podstawowe elementy tablicy ustawień - a jednym z nich jest właśnie SR_AlignX_Center, którego konstruktor zacytowałem na początku. Konstruktor ten jak ognia potrzebuje referencji do SR, a ta zaś dopiero się wywołuje, więc nie jest ustawiona. Skoro nie jest ustawiona, to znowu się wywołuje, a skoro znowu się wywołuje, to znowu definiuje elementy tablicy... i tak w koło Macieju - aż do 256 wywołań.

Jaki z tego wniosek ? myInstance dostaje referencję do tworzonej instancji dopiero po zakończeniu wywoływania konstruktora new. Co powoduje, że przez cały czas, przez kolejne polecenia zawarte w konstruktorze ma ona wartość undefined. No i dostajemy efekt (i output) jak wyżej...

Jak temu zapobiec ?

Na początku w konstruktorze SR dałem trace([myInstance,this]);

undefined,[object Object]

i to był strzał w dziesiątkę - już wiedziałem, gdzie jestem. Wystarczyło dodać jedną linię do konstruktora... oto on:

 private function StageResizer () {
  //
  myInstance = this;
  //
  _listeners = new Array ();
  setStageAreaAtStart (Stage.width, Stage.height);
  setStandardModes ();
  Stage.scaleMode = "noScale";
  Stage.align = "TL";
  Stage.addListener (this);
 }

co oczywiście pozwala też wywalić przypisanie do myInstance w metodzie SR.getInstance - no ale niech już to zostanie - w końcu tak jest klasycznie i niech tak zostanie - z przypisaniem w metodzie.

No to jeszcze tylko zostało ustawić pozostałe metody ustawiające (masło maślane) i będzie po bólu...

Komentarze (0)
StageResizer - final countdown
 Oceń wpis
   

Uff... po kilku tygodniach tworzenia (z przerwami na projekty "inne"), jeszcze trochę na bakier z wzorcami projektowymi - SR zaczyna odpowiadać. Nie pomyślałbym, że tak mnie będzie cieszyć widok takiego outputu:

system\stageresizerPackage\$test\stageresizer_test.fla:
creating new stageresizer by Singleton.
T% - unknown offset mode
T% - unknown scale mode
//--------
B% - unknown offset mode
B% - unknown scale mode
//--------
SR_Offset_NoOffset
SR_OffsetY_Bottom
B - unknown scale mode
//--------
L% - unknown offset mode
L% - unknown scale mode
//--------
SR_OffsetX_Left
SR_Offset_NoOffset
L - unknown scale mode
//--------
R% - unknown offset mode
R% - unknown scale mode
//--------
SRL_OffsetX_Right
SR_Offset_NoOffset
R - unknown scale mode
//--------
SR_OffsetX_Left
SRL_OffsetY_Top
TL - unknown scale mode
//--------
SRL_OffsetX_Center
SRL_OffsetY_Top
TC - unknown scale mode
//--------
SRL_OffsetX_Right
SRL_OffsetY_Top
TR - unknown scale mode
//--------

CL - unknown align mode
CL - unknown offset mode
CL - unknown scale mode
//--------
SRL_OffsetX_Right
SR_OffsetY_Middle
CR - unknown scale mode
//--------
SRL_OffsetX_Center
SR_OffsetY_Middle
CC - unknown scale mode
//--------
SR_OffsetX_Left
SR_OffsetY_Bottom
BL - unknown scale mode
//--------
SRL_OffsetX_Center
SR_OffsetY_Bottom
BC - unknown scale mode
//--------
SRL_OffsetX_Center
SR_OffsetY_Bottom
BR - unknown scale mode
//--------
% - unknown offset mode
//--------
%H - unknown align mode
%H - unknown offset mode
%H - unknown scale mode
//--------
%V - unknown align mode
%V - unknown offset mode
%V - unknown scale mode
//--------

Wszystko jest dokładnie tak jak trzeba - cho widać w niektórych miejscach jeszcze "SRL" - to oznaczenie klas ustawiających, które kiedyś były podpinane "poziom niżej" - dopiero przy inicjacji StageResizerListener ustawiane. Nie ma się też co martwić o "unknown mode" - oznacza to tylko tyle, że wartości podane są nieobsługiwane - to także "odziedziczone" po SR spod AS1 - teraz wszystko jest obsługiwane: jeżeli klasa zarządzająca nie znajdzie w swoich zbiorach odopwiednich instancji, to podstawi domyślne wartości. W przypadku wartości skalowanych proporcjonalnie ("%") po przystąpieniu do projektu w wersji as2 postanowiłem, że "%" będzie zawsze na drugim miejscu. No ale nie jest to żadna przeszkoda - StageResizer jest wyposażony w metody "map[]Mode" - które w bardzo prosty sposób pozwalają na przypisanie łańcuchowi "%H" metody spod łańcucha "H%".

No to będzie teraz troszeczkę dłuższa przerwa... tak do jutra :) - ponieważ czeka mnie zdefiniowanie (ponowne) klas odpowiedzialnych za ustaniewienia - najprostsze będą "top" i "left" - no może troszkę ustąpią miejsca pustym klasom "none" :).

Klasy zajmujące się skalowaniem zostawiam na koniec... to sama przyjemność:)

 Założenia projektu (link do wpisu).

//EDIT: dodatek nt. dylematu z poprzedniego wpisu - StageResizer.setListenerAlignMode(MC,XY); pozwala na zmianę align przez podanie referencji do zarejestrowanego MovieClipu; StageResizerListener.setAlignMode(XY); ustawia align konkretnej instancji -i wilk syty, i owca cała.

Komentarze (0)
StageResizer - "maleńkie" zmiany na zewnątrz
 Oceń wpis
   

No i doszedłem do momentu, w którym drogi starego i nowego StageResizera całkowicie się rozchodzą.

Powód ? Prosty: oszczędność czasu.

Dodanie słuchacza w starym SR:

stageresizer.addListener(MC:MovieClip,położenie:String,skaluj:Boolean,[włączAutoOffset:Boolean] | [wyłączAutoOffset:Boolean, offsetX:Number, offsetY:Number] )

zwraca: nic

dodanie słuchacza w nowym SR:

stageresizer.addListener(MC:MovieClip,położenie:String [, skalowanie:String]:StageResizer

 zwraca: jak widać, jest to referencja do instancji stageresizera.

Spostrzegawczy już zdążyli zauważyć, że zniknął offset przy dodaniu listenera. Dlaczego ?

Ponieważ mogę wywołać tylko: sr.addListener(MC,"BL"); i będzie to wystarczające - resztą zajmie się już klasa projektu. No a co, jeżeli potrzebuję ustawić ręcznie offset ? W tym pomoże nam zwracana referencja:

sr.addListener(MC,"BL").setListenerOffset(MC,offstx, offsty);

mam mały dylemat, czy nie zwracać referencji do StageResizerListener - czyli klasy "opiekującej się" słuchaczem - można by wtedy wywołać zmianę offsetu jeszcze krócej:

sr.addListener(MC,"BL").setOffset(offstx, offsty);

z drugiej strony, metodę sr.setListenerOffset(MC, offstx, offsty); można wywołać bezpośrednio... coprawda w moich założeniach było, że instancje klasy StageResizerListener będą prywatnymi, tylko dla SR... mam mały dylemat :)

Założenia projektu (link do wpisu).

//EDIT: dylemat rozwiązany - "upubliczniam" klasę StageResizerListener

Komentarze (0)
StageResizer - jak to wygląda ?
 Oceń wpis
   

Jeżeli ktoś byłby zainteresowany, jak wygląda projekt w działaniu, niech kliknie tutaj - musisz zmienić obszar okna przeglądarki, żeby zobaczyć ją w działaniu. Znajduje się tam wersja wcześniejsza SR, niezoptymalizowana (dziedzicząca z wersji spod as1) i nie-OOPowa. W każdym razie "tak ma to działać".

Pierwsze uruchomienie wersji OOP

Praktycznie przepisałem wczoraj wszystko od zera. Ufff... po pięciu godzinach siedzenia nad kodem kompilator nareszcie nie pluł się o dziedziczenia, prywatne członki i inne odnogi (statyczne lub nie) metod, funkcji i klas.

No i przyszła wreszcie ta chwila, kiedy mogłem kliknąć "test project" - i... nic. Tym razem przeszedłem sam siebie kombinując tak skutecznie, że nawet kompilator dał się oszukać, iż wszystko jest okey... cdn.

Założenia projektu (link do wpisu).

//EDIT: jakby ktoś pytał... od ostatniej publikacji elementów projektu parę rzeczy (metod, argumentów)  się zmieniło...

Komentarze (0)
StageResizer - StageResizerListener: przechowywanie obiektów
 Oceń wpis
   

Najprościej obiekty słuchaczy można by przechowywać pakując je w listę. Jeden push() i po bólu. Gorzej z wyjmowaniem :). Co wobec tego zrobić ? Z czego skorzystać ? Od wersji MX podstawowa klasa Array oficjalnie dziedziczy po Object - czyli można już nie tylko przypisywać elementy od 0..n, ale także podobnie jak w obiekcie, przypisywać je poprzez stringi. Tablice tego typu to tzw. "hash" - czyli tablice asocjacyjne. Tu przydatne z tego powodu, że bardzo łatwo dzięki nim obiekt wyjmiemy z listy, nie tracąc kolejności. Gdyby nie było tablicy asocjacyjnej, musielibyśmy przez push rejestrować obiekt, który pamiętał by swoją pozycję, musiałby ją uaktualniać przy każdym wyrejestrowaniu innego obiektu przed nim... itd. itp. - słowem mnóstwo roboty.

Do przechowywania informacji o słuchaczu posłuży nam klasa StageResizerListener. To instancje tej klasy będziemy wrzucać do "worka" tablicy.

_listeners[String(MC)]  = new StageResizerListener(MC);

a oto jej interfejs:

//package system.stageresizerPackage.istener;
//
interface stageresizerPackage.interfaces.IStageResizerListener {
 //
 function setScaleX (xscale:Number);
 function setWidth (w:Number);
 function setOffsetX (x:Number);
 function setX (x:Number);
 function multiplyX (sx:Number);
 //
 function setScaleY (yscale:Number);
 function setHeight (h:Number);
 function setOffsetY (y:Number);
 function setY (y:Number);
 function multiplyY (sy:Number);
 //
 function onresize ();
 function StageResizerListener (_MC:MovieClip);
}

Podobnie do przechowywania metod ustawiających - align, offset, scale - jako kontenerka użyję instancji odpowiednio przygotowanych klas. Dlaczego tak, a nie po prostu od razu referencji ? bo pamiętam o tym, że cokolwiek wrzucisz do tablicy bezpośrednio, będzie typu Object - programiści tego nie lubią :) wobec tego pierw zgodność typów, a potem do worka.

//package system.stageresizer.listener;
//
import stageresizerPackage.interfaces.IStageResizer_Scale;
//
class stageresizerPackage.ScaleModesArrayItem {
 //
 public var scaleBehavior:IStageResizer_Scale;
 //
 public function ScaleModesArrayItem (_scalebehavior:IStageResizer_Scale) {
  //
  scaleBehavior = _scalebehavior;
 }
}

//package system.stageresizer.listener;
//
import stageresizerPackage.interfaces.IStageResizer_OffsetX;
import stageresizerPackage.interfaces.IStageResizer_OffsetY;
//
class stageresizerPackage.OffsetModesArrayItem {
 //
 public var XBehavior:IStageResizer_OffsetX;
 public var YBehavior:IStageResizer_OffsetY;
 //
 public function OffsetModesArrayItem (_xbehavior:IStageResizer_OffsetX, _ybehavior:IStageResizer_OffsetY) {
  //
  XBehavior = _xbehavior;
  YBehavior = _ybehavior;
 }
}

Klasa do przechowywania alignów wygląda prawie że identycznie, więc ją pominę.

Założenia projektu (link do wpisu).

Komentarze (0)
StageResizer - pozostałe interfejsy
 Oceń wpis
   

Co robi interfejs ? W skrócie: zmusza nas do zdefiniowania w klasach implementujących interfejs metod zapisanych w interfejsie.

Po co w projekcie w typach zmiennych ? Pozwala to na podpięcie pod określoną zmienną n-różnych klas, pod warunkiem że będą implementować określony interfejs.

Co to daje ? Użycie interfejsu dla alignMode, scaleMode, offsetMode spowoduje, że nie popełnimy fatalnej pomyłki dodając klasę zajmującą się położeniem do zbioru klas zajmujących się skalowaniem obiektu.

Czy warto ? Skoro Arthwood mówi, że warto, to czemu mu nie wierzyć ? :)

//package system.stageresizer.listener;
//
interface stageresizerPackage.interfaces.IStageResizer_AlignY {
 //
 function setYAlign (offsetY:Number);
}

//package system.stageresizerPackage.listener;
//
interface stageresizerPackage.interfaces.IStageResizer_OffsetX {
 //
 function getXOffset (MC:MovieClip);
}

interface stageresizerPackage.interfaces.IStageResizer_Scale {
 //
 function setScale ();
}

Do gromadzenia sposobów ustawiania używam wzorca strategia, a to wymaga, by przekazywać do "magazynu" instancję klasy stworzoną za pomocą słowa "new". Jednym słowem odpada możliwość przekazywania w konstruktorze referencji do słuchacza - zresztą i tak niepotrzebnej, ponieważ będziemy nadpisywać tylko wywoływaną metodę, a nie przekazywać całą klasę. Dlaczego nie statycznie, tylko przez instancję ? Spróbuj użyć interfejsu do definiowania klasy statycznej :).

Jak widać po offsecie, w tym przypadku metoda predefiniowana jest metodą pobierającą. Pozostaje kwestią nierozwiązaną, czy żądać w interfejsie metody ustawiającej wartość offsetu.
W głównym projekcie offset "ręczny" zamierzam wrzucać do odpowiednich zmiennych instancji słuchacza - nie za bardzo więc będzie potrzebna odrębna metoda ustawiająca.

Najmniej zachodu jest z interfejsem klas skalujących - jedna metoda, zero parametrów - kompletny luz :). I pomyśleć, że będzie wszystko biegało na podobnych, prawie takich samych, zasadach.

Założenia projektu (link do wpisu).

Komentarze (0)
StageResizer - główny interfejs
 Oceń wpis
   

Jakie powinien posiadać metody publiczne ? Prywatne to dopiero będą się pojawiać przy zakładaniu klasy :).

Dwie podstawowe: dodanie słuchacza i zwolnienie słuchacza. Przyjmuję założenie, że słuchaczami mają być obiekty "ślepe" - czyli takie, które nie będą posiadały obsługi zdarzeń. To znaczy: grafik robi Ci top, do którego praktycznie nic nie musisz dodawać - ba, nawet masz dokładnie określone miejsce na scenie.

Trzy, cztery zarządzające sposobem ustawienia na scenie - odpowiednio align, offset, scale. Cztery, ponieważ listener może mieć niestandardowe ustawienie offsetu.

Podobnie rozszerzające - także 3-4 metody.

Ewentualne alternatywne podpinanie klipów z własną obsługą eventów ? czemu nie.

//package system.stageresizerPackage;
//
interface stageresizerPackage.IStageResizer {
 //
 function updateListener (MC:MovieClip):Boolean;
 function setStageAreaAtStart (startwidth:Number, startheight:Number);
 //
 function addAlignMode (mode:String, alignXClass:IStageResizer_AlignX, alignYClass:IStageResizer_AlignY);
 function addOffsetMode (mode:String, offsetXClass:IStageResizer_OffsetX, offsetYClass:IStageResizer_OffsetY);
 function addScaleMode (mode:String, scaleClass:IStageResizer_Scale);
 //
 function setListenerScaleMode (MC:MovieClip, mode:String);
 function setListenerAlignMode (MC:MovieClip, mode:String);
 function setListenerOffsetMode (MC:MovieClip, mode:String);
 function setListenerOffset (MC:MovieClip, offsetx:Number, offsety:Number);
 function addListener (MC:MovieClip, onstagepos:String);
 function removeListener (MC:MovieClip);
 function addEventListener (MC:MovieClip);
 function removeEventListener (MC:MovieClip);
}

Dodanie i zwolnienie słuchacza to addListener i removeListener. Dodanie i zwolnienie klipów posiadających własną obsługę zdarzeń to addEventListener i removeEventListener. To tylko alternatywa, którą teraz nie będę rozwijał - po prostu podany klip dorzucę do listy słuchaczy Stage'a.

Klasa główna będzie posiadać predefiniowane (za pomocą metod publicznych rozszerzających) rodzaje sposobów ustawienia. Ponieważ na początku przy dodaniu słuchacza jest określana tylko jedna wartość domyślna (onstagepos), będą dostępne cztery metody modyfikujące - setListenerAlignMode, setListenerOffset, setListenerOffsetMode, setListenerScale. Jak już pisałem wcześniej, offset można ustawić ręcznie za pomocą drugiej metody.

Nacisk, który jest położony na dodawanie i mapowanie klas określających położenie - tzn. użycie zmiennych określonego typu interfejsów - dodałem specjalnie, by przypadkowo podpięcie innej metody nie spowodowało "wylecenie w powietrze" aplikacji.

Dzięki takiemu dodawaniu własnych metod nie musisz się bawić w rozsszerzanie, modyfikowanie, przekształcanie - ot, "rejestrujesz" własną klasę spełniającą określone warunki i obiekty zachowują się zgodnie z Twoimi założeniami.

Czasami mam wrażenie, że programowanie obiektowe broni programistę przed nim samym :)

//EDIT: ostatnia zmiana: addEventListener (i logicznie removeEventListener) - typ słuchacza zmieniony na Object

Komentarze (0)
StageResizerProject
 Oceń wpis
   

Ok, pierw dwa słowa dla czytających mojego bloga: dziękuję za wszystkie sugestie. Jesteście super :D (te trolle też, tylko że w drugą stronę :p)

StageResizerProjekt (SR)

Założenia: SR ma maksymalnie ułatwić rozłożenie elementów na scenie, a także dopisywanie własnych metod ułożenia skalowania.

Powód:  nużące wielokrotne używanie obiektów do obsługi zdarzenia onresize i za każdym razem pisanie/importowanie odrębnych klas/metod.

Działanie: SR pozwala za pomocą jednej linijki obsłużyć zmianę położenia elementu na scenie podczas zmiany jej wielkości (onresize).

Skutek: więcej czasu, który można efektywnie użyć na zajmowanie się właściwym kodowaniem.

Przydatność: Wielokrotne wykorzystanie bez potrzeby modyfikacji projektu. Osadzone w projekcie metody/klasy zarządzające słuchaczem pozwalają na obsługę 99% potrzebnych pozycji na scenie.

Zgodność z przyzwyczajeniami: obsługa wywołań alfanumerycznych takich samych jak dla Stage.align, Stage.scaleMode z zastosowaniem dla obiektów - przykładowe przyjmowane wartości: dla align: "TL", "C", "BL"; dla scale: "exactFit", "noScale", "proportional" itp..

Modyfikacja własna, rozszerzanie itp: niepotrzebne - dodawanie własnych metod poprzez przygotowaną odpowiednią publiczną metodę interfejsu pozwala na podpinanie ich do obsługi słuchaczy bez konieczności żmudnego zagłębiania się w kod projektu.

Kod: wkrótce :)

Komentarze (0)
[as2]Timer i rozważania singletonu
 Oceń wpis
   

Po ludzku: singleton to taka klasa, która w całej aplikacji jest "niepowtarzalna" - raz załączona występuje tylko raz.

Timer jest typu singletona - ma służyć do obsługi wszystkich eventów czasowych mając wyłączność ich obsługi (czyli i to, co robią oEFy , i to, co robi setInterval realizować za pomocą jednego, przejętego od View oEFa).

No tak, ale co zrobić wtedy, kiedy mleko już się rozlało i w kilku projektach mam:

timer = new Timer(this);

wobec powyższego zmiana konstruktora na prywatny nie wchodzi w grę, ponieważ te parę projektów "trzeba by było zmienić"...

Drugim problemem jest to, że konstruktor nie może niczego zwracać... odpada w tym momencie przekazywanie referencji do już istniejącej instancji - co zostaje zrobić w takim przypadku ?

Wpadłem na coś takiego:

1. Dodajemy "zwyczajną" konstrukcję singletonową ze zmienną, która  będzie tzrymać referencję do klasy timer zaraz po var-ach: 

private static var myInstance:Timer;
 //
 public static function getInstance (_MC:MovieClip):Timer
 {
  if (myInstance == undefined)
  {
   trace ("creating new timer by Singleton.");
   myInstance = new Timer (_MC);
  }
  trace("return instance");
  return myInstance;
 }
2. Następnie modyfikujemy konstruktor (jest na końcu wpisu - wpadł w "wiry" bbloga :/):  

 i odpalamy przykładzik:

import system.Timer;

var timer = Timer.getInstance(this);
var timer = new Timer (this);
var timer = new Timer (this);
var timer = new Timer (this);

 Output:

creating new timer by Singleton.
Timer enabled
return instance
_level0,timer setted
_level0,timer earlier setted
_level0,timer earlier setted
_level0,timer earlier setted

 i jeszcze jeden:

  timer = new Timer (this);
  timer = Timer.getInstance(this);
  timer = new Timer (this);
  timer = new Timer (this);

Output:

_level0,timer setted
Timer enabled
return instance
_level0.page,timer earlier setted
_level0.page,timer earlier setted


i już można używać Timer-a w dwojaki sposób.

Po przeanalizowaniu obu wywołań preferowany jest jednak drugi sposób wywołania - poprzez Timer.getInstance(this); :)

Podobno to nieładnie tak przekazywać parametr przy wywołaniu singletonowym, ale jak nie musi być on użyty, to jest po prostu olewany - a że jest potrzebny... o wiele gorzej by było go definiować tak:

Timer.MC = this;
var timer = Timer.getInstance();

Następny w kolejce: StageResizer :)

Wszelkie uwagi mile widziane.

//zmodyfikowany konstruktorpublic function Timer (_MC:MovieClip)
{
  //
  if (myInstance == undefined)
  {
   if (_MC == undefined)
   {
    trace ("error: MC not set");
    //
   }
   else
   {
    myInstance = this;
    _listeners = {};
    trace ([_MC, "timer setted"]);
    enable ();
    MC = _MC;
   }
  }
  else
  {
   trace ([MC,"timer earlier setted"]);
  }
 }

//EDIT: to nie jest klasyczne rozwiązanie singletonu i tak się nie powinno robić, w każdym razie działa i o to chodziło - dzieci, a zwłaszcza trolle - polecam Wam lekturę własnych projektów, a nie męczenie się nad przyciskiem głosowania

Komentarze (0)
AS2: Nie chcę, ale muszę
 Oceń wpis
   

Miałem nadzieję, że uda mi się utrzymać swój styl programowania (przypinanie klas do _globala i takie inne mało użyteczne rzeczy jak dynamiczne typowanie zmiennych) do czasu, aż AS3 straci miano "prawiczka". No niestety, nie udało się.

Słysząc zewsząd głosy o tym, że mój styl programowania powoli zaczyna "trącić myszką" (no a czym, chyba nie tabletem ?:p) oraz łapiąc się na tym, że używam stałego typowania zmiennych, stwierdziłem, że niestety zamiast robić duży krok w przód, trzeba będzie zrobić kilkanaścia malutkich "tiptopów" (i podobno mi to na dobre wyjdzie :)).

Najśmieśniejsze - i zarazem najbardziej denerwujące jest to, że ten "paradygmat" nt. mojego programowania słyszę od osób, które są w stanie w projekcie bez mrugnięcia okiem użyć setProperty (no bo wyczytali gdzieś, że to działa szybciej), metody (funkcje) rozrzucają po klipach umieszczając je w onClipEvent, a żeby utrzymać typowanie zmiennych (no bo oni przecież programują w as2, bez tego kod nie może być!) używają n+1 (czyli dużo za dużo) dodatkowych zmiennych, dumnie głosząc, że oni używają as2...

No więc pora na małe kroczki... które będę dokumentował na blogu - zacznę od już opisywanej na blogu klasy TIMER. Jest ona podstawą moich wszystkich aktualnych projektów, więc dobry start to start z czasomierzem :).

Komentarze (1)
1 | 2 |

Najnowsze komentarze
2014-01-06 19:33
najlepszeprezenty.com.pl:
Flash After Party czyli o flashu w realu [EDIT]
pozdrowienia :)
2013-12-25 22:07
Powiększanie penisa:
Warto blogować ?
Trudno się z tym nie zgodzić, przez to, że są bardzo ogólne to także są bardzo trafne.
2013-12-08 22:47
ets2:
Warto blogować ?
Wartościowych blogów jest na naprawdę mało, sam staram się coś stworzyć a czy wyjdzie to się[...]
O mnie
MaW: flash, gry i cała reszta
Po prostu flashmaniak.