Arkiv for kategorien 'Tips og tricks'

ActionScript 3: Picture klasse med indbygget load, brightness, contrast, saturation og hue

onsdag, 27. august 2008

Det fede ved at alle deler med alle, er at man har mulighed for at “stå på andres skuldre” som det så populært hedder, og det er netop grundlaget for min nyeste klasse: Picture.

For ikke så lang tid siden havde jeg en post om hvordan man nemt kan konvertere et billede til sort/hvid.
I den post kom der en kommentar fra Thonbo som viste en anden måde at gøre det på, nemlig ved hjælp af ColorMatrixFilter, som jeg hidtil har afholdt mig fra at bruge, da det er en anelse tungt at sætte sig ind.

Men, det fik mig til at søge lidt rundt, hvorefter jeg fandt en ColorMatrix klasse fra Grant Skinner, hvor man kan inputte de normale værdier for brightness, contrast, saturation og hue, som man kender dem fra f.eks. filtrene i selve Flash, såvel som Photoshop.

Stadigvæk synes jeg dog at det var lidt bøvlet at man skulle hen og lave et nyt objekt hver gang man skulle stille på en enkelt værdi, og derudover gør den fremgansmåde det særdeles svært at tweene værdierne.
Så, for at gøre det endnu nemmere, i hvert fald i forhold til der hvor jeg skulle bruge funktionen, så har jeg wrappet den klasse i min egen, nemlig Picture klassen.

Den nye klasse har to funktioner:
load(url:String)
setColors(brightness:int, contrast:int, saturation:int, hue:int)

Og 4 properties man kan stille på:
- brightness
- contrast
- saturation
- hue

Og nogle properties som man kan aflæse:
- bytesLoaded
- bytesTotal
- bytes Percent
- loadingComplete

Samt 2 events man kan lytte på:
- Event.COMPLETE
- ProgressEvent.PROGRESS

Ønsker man kun at ændre en enkelt ting ved billedet, så er det nemmest blot at opdate den specifikke property, men skal man ændre mange ting på en gang, så er det smartere (og mindre performance krævende) at kalde funktionen setColors.

Et ekstremt simpelt eksempel kunne se sådan her ud:

var picture:Picture = new Picture();
picture.addEventListener(Event.COMPLETE, loadCompleted);
picture.load("test.jpg");
addChild(picture);

function loadCompleted(_e:Event):void {
	picture.saturation = -100;
}

Download
For at gøre det nemt at komme igang, så er alt det nødvendige, inklusive en CS3 fla-fil med et simpelt eksempel, samlet til download her:
Download picture.zip

Forslag til forbedringer eller nye funktioner modtages som altid gerne :-)

ActionScript 3: Tiles på den nemme måde

onsdag, 20. august 2008

Nogen gange har man brug for at tile (gentage det samme stykke grafik mange gange) for eksempelvis at fylde en baggrund ud.
En oplagt måde er at lave et loop, som kopierer og placerer det stykke grafik der skal tiles, men der findes en meget, meget nemmere måde, nemlig funktionen beginBitmapFill.

Først skal vi bruge det stykke grafik som skal tiles, så i dette eksempel har jeg importeret en png ind i mit library og efterfølgende sat den til at blive eksporteret til ActionScript som klassen Tile:

ActionScript 3 Tile

Og herefter er det såre simpelt:

var tile:BitmapData = new Tile(0, 0);
var background:Sprite = new Sprite();
background.graphics.beginBitmapFill(tile, null, true, false);
background.graphics.drawRect(0, 0, 500, 500);
background.graphics.endFill();
addChild(background);

Voila, en baggrund på 500×500 pixels.

En ting der er værd at bemærke er, at hvis man har brug for efterfølgende at ændre størrelsen på baggrunden, så er det ikke nok bare at sætte en ny højde og bredde, da det vil strække tilen, fremfor at kopiere den.

I stedet skal man bruge graphics.clear() og tegne et nyt område:

background.graphics.clear()
background.graphics.beginBitmapFill(tile, null, true, false);
background.graphics.drawRect(0, 0, 2000, 2000);
background.graphics.endFill();

Dynamisk load
I det første eksempel har jeg brugt et stykke grafik fra mit library, men det kan naturligvis også gøres med en jpg eller lignende som man loader dynamisk:

var url:String = "tile.jpg";
var loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, tileLoadComplete);
loader.load(new URLRequest(url));

function tileLoadComplete(_e:Event):void {
	var tile:Bitmap = Bitmap(_e.target.loader.content);
	var background:Sprite = new Sprite();
	background.graphics.beginBitmapFill(tile.bitmapData, null, true, false);
	background.graphics.drawRect(0, 0, 500, 500);
	background.graphics.endFill();
	addChild(background);
}

Så nu er der ingen undskyld for ikke at tile på livet løs, men please, ingen hjerter eller killinger!

ActionScript 3: Konverter farvebilleder til sort/hvid

torsdag, 14. august 2008

Nogen gange har man brug for det samme billede både i farver og i sort/hvid, men hvorfor bruge tid på at konvertere dem manuelt og ikke mindst, spilde båndbredde på at loade dobbelt så mange billeder, når man kan konvertere dem fra farver til sort/hvid automatisk i ActionScript 3?

Funktion:

function convertToBW(_image:Bitmap):Bitmap {
	var _image_bw:Bitmap = new Bitmap(_image.bitmapData);
	var _r:Rectangle = new Rectangle(0, 0, _image_bw.width, _image_bw.height);
	var _p:Point = new Point(0,0);
	_image_bw.bitmapData.copyChannel(_image_bw.bitmapData, _r, _p, 2, 1);
	_image_bw.bitmapData.copyChannel(_image_bw.bitmapData, _r, _p, 2, 2);
	_image_bw.bitmapData.copyChannel(_image_bw.bitmapData, _r, _p, 2, 4);
	return _image_bw;
}

Tutorial: Komplet site med dynamisk indhold og SwfAddress - del 3

tirsdag, 17. juni 2008

Menuen er lavet, men nu skal der til at ske noget når man klikker på den, så derfor er det tid til at tage hul på den del af sitet som har med SwfAddress at gøre.

Som det første, er det derfor nu tid til at downloade SwfAddress, hvilket kan ske herfra:
http://www.asual.com/swfaddress/

Efter du har udpakket zip-filen, så finder du de filer som skal bruges til denne tutorial finder i mappen:
Samples\CS3

Herfra skal du kopiere de to mapper swfobject og swfaddress, såvel som filerne SWFAddress.as og SWFAddressEvent.as, og de skal placeres i samme mappe som din fla-fil.
Det kunne se nogenlunde sådan her ud:

Mappestruktur

Det første der skal til, er at vi udvider den funktion der kaldes når man klikker på en knap til, udover blot at trace et id, også at kalde en funktion fra SwfAddress:

function menuClick(_e:Event):void {
	trace(_e.currentTarget.menuid);
	SWFAddress.setValue(menuItems[_e.currentTarget.menuid].address);
}

setValue funktionen bruges til at ændre url’en, hvis sites url eksempelvis er www.mitsite.dk og du kalder funktionen med værdien produkter, så vil url’en ændre sig til www.mitsite.dk/#/produkter/

SwfAddress har en event der holder øje med ændringer i url’en, og det er den event man skal fange for så at loade det rigtige indhold når url’en skifter, den event hedder SWFAddressEvent.CHANGE.

Det er en lidt større funktion, så her kommer først koden og nedenunder forklaringen:

var idPrevious:Number;
var idCurrent:Number;
var idLoading:Number;

const SITE_LABEL:String = "Mit site - ";
function handleSWFAddress(_e:SWFAddressEvent) {
	//try {
		trace("swfaddress: " + _e.value);
		var _address = _e.value.split("/");
		if(_address.length > 2) {
			for(var _i = 0; _i < menuItems.length; _i++) {
				if(menuItems[_i].address == _address[1]) {
					idCurrent = _i;
					break;
				}
			}
		} else {
			idCurrent = 0;
		}
		trace("id: " + idCurrent);
		SWFAddress.setTitle(SITE_LABEL + menuItems[idCurrent].label);
		contentLoad(idCurrent);
	/*
	} catch(err) {
		trace("swfaddress error");
	}
	*/

}
SWFAddress.addEventListener(SWFAddressEvent.CHANGE, handleSWFAddress);

De 3 første variabler bruges til at holde styr på hvilken side der blev vist før (idPrevious), hvilken side der vises nu (idCurrent) og hvilken side der er igang med at blive loadet (idLoading).

Dernæst er der en konstant der hedder SITE_LABEL, og den bruger jeg til når titlen på siden ændres. Hvis man eksempelvis er kommet ind på produktsiden, så skal siden title helst ikke kun være “Produkter”, men derimod “Mit site - Produkter”. Det giver et langt bedre overblik når man har mange tabs åbne, og derudover er det også den tekst der vil være default hvis man laver et bogmærke.

Så kommer selve funktionen der kaldes når url’en ændrer sig, og her er det vigtigt at bemærke en ting:
I eksemplet er der en try/catch som jeg har udkommenteret, og det er den fordi, at når man udvikler er det rarest at se den præcise fejl der måtte blive genereret, fremfor en “pæn” fejlmeddelelse man selv har lavet.
Til gengæld bør man overveje at lave en pæn fejlmeddelelse til når sitet i sidste ende går live, sådan så det opfører sig fornuftigt overfor brugerne - men nok om det.

Sammen med eventen får man en value, som er den del af url’en der kommer efter # og den skal så parses for at finde den korrekte side.
Der er tusind måder at parse strenge på, i eksemplet har jeg valgt den allermest simple, nemlig at splitte ved / og så loope igennem arrayet, men har man et større site er det også en oplagt mullighed at bruge Regular Expressions.

Den værdi der sammenlignes med url’en er address, som er den 2. værdi fra dette kald (som er beskrevet nærmere i del 2):

menuItemAdd("Kontakt os","kontakt-os","kontakt.swf");

Som det sidste, inden det korrekte indhold loades, så ændres titlen med funktionen setTitle, jævnfør det jeg skrev længere oppe.

Og, det var sådan set det!
Der er en række andre funktioner i sitet, men de er mere almindelige og har intet med SwfAddress at gøre, så dem vil jeg ikke gå ind i, men blot opfordre dig til at downloade det komplette site med fla-filer und alles.

Se den komplette demo af sitet her:
Site med SwfAddress (Bemærk det lækre design ;-) )

Og filen med det komplette eksempel kan nappes her:
site_med_swfaddress.zip

Håber det kunne bruges, og spørgsmål er som altid velkomne.

Tutorial: Eksport af video fra Flash CS3

torsdag, 5. juni 2008

Man har de sidste mange versioner af Flash haft mulighed for at eksportere til video, men problemet har været at det ikke har fungeret ret godt, medmindre der var tale om helt simpel timeline animation.

I Flash CS3 er video-eksporteren heldigvis blevet væsentligt bedre, så den nu også tager højde for ActionScript og giver mulighed for at neste animation, så nu var det på tide med en lille, hurtig gennemgang af hvordan man gør.

Hvad skal vi eksportere?
For at have noget at eksportere, som tester de nye muligheder, så har jeg lavet en fla-fil med følgende:
- En stage på 1920×1080 - kan man have andet i disse HD-tider?
- En Pacman-figur der bevæges frem og tilbage via ActionScript, men som indeholder nestet timeline animation der åbner og lukker munden.
- En cirkel med en gradient, der har en nestet timeline animation som stiller på alphaen. Denne cirkel er så kopieret ud et antal gange og skaleret samt er blevet tintet for at ændre farven.

Fla-en indeholder absolut ingen hokus pokus, men for en god ordens skyld så kan den alligevel hentes her:
video_export.fla

Eksport
For at eksportere til video, så skal man gå ind i File -> Export -> Export Movie

Her er det første man bliver præsenteret for valg af filformat.
Der er en del forskellige formater på listen, men hvis du ønsker adgang til den nye funktionalitet, så er det vigtigt at du vælger Quicktime (*.mov).

Når du har gjort det kommer følgende dialogboks:

Quicktime Export Settings

Det nye er her primært, at man under “Stop exporting” kan vælge “After time elapsed”, hvilket gør at man kan bede om en eksport der har en bestemt længde, og i det tidsrum så optager Flash, billed for billed, en video.

Det fungerer rigtig godt, der er kun én ting man skal være opmærksom på:
Hvis din swf hakker når du tester animationen, så vil den eksporterede video komme til at hakke tilsvarende.
Med andre ord, så kan man ikke bruge det til at lave animation som kræver mere CPU, end at den maskine man sidder på kan afvikle det flydende.

Hvis man klikker på “Quicktime settings” (og det gør man), så kommer man hen til denne boks:

Indstilling af film

Og herfra man vælge præcis hvilken egenskaber filmen skal komprimeres med, noget som er meget afgørende for kvaliteten.
Man kan godt vælge at tweake meget på settings herinde for at få det bedste forhold mellem størrelse og kvalitet, men når vi arbejder med video, så gør vi altid det at vi eksporterer i bedst mulige kvalitet fra Flash.

Ved denne korte video har jeg valgt helt ukomprimeret, hvilket får det ene minuts video til at fylde 14,4GB.
Som oftest vælger jeg dog et format med noget komprimering, eksempelvis H.264 sat til “Optimal”, da filerne ellers bliver uhensigtsmæssigt store at arbejde med.

Pointen er dog, at vi aldrig forsøger at lave slutkomprimeringen i Flash, men blot at eksportere den flottest mulige video, der dermed bliver en slags råfilm, som man efterfølgende kan arbejde videre med.

Slutkomprimering
Til den sidste del af komprimeringen findes der et utal af program man kan bruge, selv plejer jeg at bruge Sorenson Squeeze, da det passer godt til mit workflow.
Der er en række standard presets af komprimeringer at vælge imellem, ligesom man kan lave sine egne, og har man brug for at croppe videoens størrelse eller længde kan det gøres med det samme.

Her et screenshot (klik for stor version) hvor jeg laver en flv, mp4 i høj kvalitet med H.264 og en version til iPod i et hug - ligesom at man naturligvis kan tune kvaliteten inden for det samme format hvis man har lyst til det:

Sorenson Squeeze 5 Pro

Slutresultat
Naturligvis skal det meget smukke slutresultat uploades til en online videotjeneste, så det har jeg også gjort:

Håber at det kunnes bruges :-)

Tutorial: Komplet site med dynamisk indhold og SwfAddress - del 2

tirsdag, 3. juni 2008

Med introduktionen overstået er det nu tid til at dykke ned i selve koden af for vores site.

Hvad er det første man har brug for i en menu? I vores tilfælde er det en simpel knap, med en tekst som kan udskiftes alt efter hvilket menu punkt der er tale om.

Derfor har jeg lavet et movieclip med følgende struktur:
- Top-lag med et dynamisk tekstfelt kaldet Label_txt (husk at embedde de nødvendige tegn!).
- Bund-lag med et movieclip kaldet Background_mc, som indeholder en farvet kasse der er baggrund for teksten.

I mit library har jeg herefter sat den til at blive eksporteret til ActionScript med navnet SiteButton:

SiteButton - Properties

Ingen klasser og i Flash
For at gøre denne tutorial så nem at følge som muligt, så er al koden lavet direkte på første frame i Flash og uden brug af underklasser, men skal man igang med et større projekt, så er det naturligvis oplagt at dele det op samt at bruge en ekstern kode-editor som eksempelvis FlashDevelop.

Menuen genereres
Som første skridt i at generere menuen er her først en funktion som samler de nødvendige informationer i et lille objekt som tilføjes til et array, der kommer til at indeholde alle vores menupunkter:

var menuItems:Array = new Array();

function menuItemAdd(_label:String, _address:String, _file:String):void {
	var _temp:Object = new Object();
	_temp.label = _label;
	_temp.address = _address;
	_temp.file = _file;
	menuItems.push(_temp);
}

De værdier som man sender med til funktionen er:
Label: Det som der skal stå på menupunktet, eksempelvis “Forside”.
Address: Det der skal tilføjes til url’en og som bruges i forbindelse med SwfAddress, eksempelvis “forside”.
File: Den fil der skal loades når man klikker på menupunktet, eksempelvis “forside.swf”.

Angående address, så er det værd at bemærke at værdien skal være unik, og da den bruges som url, så er det også bedst at undgå mellemrum og specialtegn.
Et menupunkt som hedder “Vores øl” kan derfor med fordel have address-værdien “vores-oel”.

Det site som vi laver i denne tutorial har 4 menupunkter, og derfor kaldes funktionen 4 gange:

menuItemAdd("Forside","forside","forside.swf");
menuItemAdd("Produkter","produkter","produkter.swf");
menuItemAdd("Profil","profil","profil.swf");
menuItemAdd("Kontakt os","kontakt-os","kontakt.swf");

Menuen vises
Nu har vi et array med alle vores menupunkter, og ved hjælp af det er det nu tid til at lave og vise selve menuen.

For at gøre det simpelt at ændre placeringen på menuen, er der først et par konstanter:

const MENU_X:Number = 10;
const MENU_Y:Number = 10;
const MENU_PADDING:Number = 10;

X og Y er startplaceringen for det første menupunkt, mens padding er mellemrummet mellem de forskellige menupunkter.

Her så selve funktionen som laver menuen:

function menuCreate():void {
	for(var _i = 0; _i < menuItems.length; _i++) {
		var _temp:SiteButton = new SiteButton();
		_temp.Label_txt.text = menuItems[_i].label;
		_temp.menuid = _i;
		_temp.x = MENU_X + (_temp.width * _i) + (MENU_PADDING * _i);
		_temp.y = MENU_Y;
		_temp.mouseChildren = false;
		_temp.buttonMode = true;
		_temp.useHandCursor = true;
		_temp.addEventListener(MouseEvent.CLICK, menuClick);
		addChild(_temp);
	}
}

Den looper vores array igennem, og for hvert objekt, så indsætter den en ny SiteButton, hvor teksten på Label_txt sættes.
Menuid refererer til knappens position i arrayet, sådan så knappen senere kan finde tilbage til det objekt den er lavet udfra.

mouseChildren = false fortæller Flash at objekter inde i SiteButton ikke kan interagere med musen, mens buttomMode og useHandCursor fortæller Flash at menupunktet skal opføre sig som en knap og at hånden skal vises ved mouseOver.

Hvis du compiler koden nu, så kommer der en fejl, for i denne funktion tilføjer vi også en eventListener, der lytter efter hvornår der klikkes på menupunktet, men den funktion den refererer til er jo ikke defineret endnu.
Den kommer til gengæld her:

function menuClick(_e:Event):void {
	trace(_e.currentTarget.menuid);
}

I først omgang er alt som denne funktion gør, at trace menuid’et, så vi kan se hvilken knap der er blevet klikket på.

Hvis du nu kører al koden, og såfremt du er en ligeså god designer som mig *host*, så vil burde du ende med et resultat nogenlunde i stil med det her:

Step 2

Og den samlede kode, efter lidt restrukturering, kunne se sådan her ud:

//////////////// MENU
const MENU_X:Number = 10;
const MENU_Y:Number = 10;
const MENU_PADDING:Number = 10;

var menuItems:Array = new Array();

menuItemAdd("Forside","forside","forside.swf");
menuItemAdd("Produkter","produkter","produkter.swf");
menuItemAdd("Profil","profil","profil.swf");
menuItemAdd("Kontakt os","kontakt-os","kontakt.swf");

menuCreate();

function menuItemAdd(_label:String, _address:String, _file:String):void {
	var _temp:Object = new Object();
	_temp.label = _label;
	_temp.address = _address;
	_temp.file = _file;
	menuItems.push(_temp);
}

function menuCreate():void {
	for(var _i = 0; _i < menuItems.length; _i++) {
		var _temp:SiteButton = new SiteButton();
		_temp.Label_txt.text = menuItems[_i].label;
		_temp.menuid = _i;
		_temp.x = MENU_X + (_temp.width * _i) + (MENU_PADDING * _i);
		_temp.y = MENU_Y;
		_temp.mouseChildren = false;
		_temp.buttonMode = true;
		_temp.useHandCursor = true;
		_temp.addEventListener(MouseEvent.CLICK, menuClick);
		addChild(_temp);
	}
}

function menuClick(_e:Event):void {
	trace(_e.currentTarget.menuid);
}

Nu har vi noget der ligner en menu, som man endda kan klikke på!

I næste del får vi ting til at ske når der bliver klikket :-)

Tutorial: Komplet site med dynamisk indhold og SwfAddress - del 1

torsdag, 29. maj 2008

Som jeg skrev i forbindelse med lanceringen af den sidste version af Se mor! - Digital konceptudvikling og design, så ville jeg benytte erfaringerne med SwfAddress derfra til at lave en lille tutorial, og i dag kommer så første del af den.

Mål
Målet med tutorialen er at lave et komplet og dynamisk microsite, der kan konfigureres via xml og loader alt indhold ind særskilt.
Og, som det måske mest interessante, så integreres det med SwfObject og SwfAddress, sådan så man kan bookmarke og linke til sektioner på sitet.

SwfAddress != SEO
Som noget af det første vil jeg gerne starte med at slå en tyk streg igennem en stor misforståelse som jeg ser flere steder:
SwfAddress har i sig selv intet med SEO (Search Engine Optimisation) at gøre.

SwfAddress gør det muligt forholdsvis enkelt, at lave et site i Flash, hvor man kan linke til og bookmarke bestemte sider og sektioner, med alle de fordele som det nu engang giver.

SwfAddress gør IKKE et Flash-site mere søgevenligt, da Google og andre søgemaskiner stadig ikke kan indeksere dynamiske Flash-sites, og derfor har det altså ingen effekt på det.

Ønsker man er SEO-optimere sit Flash-site, så er det oplagt at bruge SwfAddress som en del af sådan en løsning, men derudover kræver det også en del ændringer server-side.

Bare så vi lige har det på plads :-)

Flow
Det adskiller sig i bund og grund ikke ret meget at lave et site med SwfAddress og et uden, men der kommer en lille ændring i flowet, som jeg har forsøgt at skitsere her:

SwfAddress - Flow

Med andre ord så er det der sker, at der er en speciel event i SwfAddress som bliver aktiveret når url’en ændrer sig, her modtager man så den nye url som en streng, og så kan man ellers begynde og parse den og finde ud af hvad det var som der blev klikket på.

Så, det var introduktionen til det hele, i næste del tager vi hul på koden.

Nemmere debugging: Runtime errors med linienummer

tirsdag, 29. april 2008

Er der noget mere irriterende end at få en runtime i ActionScript 3, som bare lister at der gik noget galt i en funktion?
Eksempelvis at en unavngiven variabel ikke var defineret?

Hvis man har en stor funktion og fejlen ikke lige springer en i øjnene med det samme, så er det nemlig rent et spørgsmål om trial-and-error for at få fundet stedet hvor det går galt.
Eller, det vil sige, det er det faktisk ikke!

Man kan lige i “Publish settings” sætte et flueben i “Permit debugging”, hvilket gør at man får den fejlbesked man hele tiden har fået PLUS det præcise linienummer hvor fejlen er opstået.
Så bliver det ikke meget nemmere!

Permit debugging

Skal ikke kunne sige om det er almen viden for alle andre, men jeg havde i hvert fald ikke lige luret det.

Fundet via denne blog.

currentFrame og totalFrames i ActionScript 3

mandag, 21. april 2008

Et lille hurtigt tip:
I ActionScript 3 findes værdierne currentFrame og totalFrames kun på MovieClips, ikke på stagen, og derfor er det ikke umiddelbart lige til at finde ud af hvor mange frames der er i stagen.

Men, man kan heldigvis få ActionScript 3 til at behandle stagen som om den var et MovieClip, og voila, så findes værdierne:

MovieClip(root).currentFrame

Hvilken skrifttype bruger du til udvikling?

mandag, 7. april 2008

Faldt over en artikel forleden, som handlede om hvilken font man bruger når man udvikler.

Selv har jeg for længst droppet Courier New og har i stedet igennem en del år brugt Verdana, men jeg havde ikke lige tænkt tanken så langt, at der jo naturligvis findes specielle fonte derude som er ekstra velegnede til udvikling, eller måske ovenikøbet udviklet til udvikling (badabing).

På baggrund af artiklen installerede jeg Consolas og jeg må tilstå at jeg har været meget tilfreds med den. Den står helt skarpt og fungerer godt i en lille størrelse, og modsat Verdana er den mono-spacieret (alle bogstaver har samme bredde) hvilket jo er vigtigt, da den dermed aligner bedre.

Så, hermed en opfordring til om ikke andet lige at prøve et par andre skrifttyper, så kan man jo altid skifte tilbage til den man havde hvis man ikke finder noget bedre.

Du ændrer skrifttypen her:
Edit –> Preferences –> ActionScript

Se artiklen her:
Development Tip: Change Your Coding Font

Og her eksempler på en række andre fonte:
Programming fonts