Arkiv for februar 2008

Adobe AIR 1.0 officielt i luften!

mandag, 25. februar 2008

Adobe Air

Så skete det som mange har ventet på i rigtig lang tid, Adobe har netop officielt frigivet Adobe Air 1.0, så i min verden er deres potentielt vigtigste nye produktrelease siden, ja, siden Flash faktisk!

Muligheden for at kunne lave rigtige croos-platform desktop-applikationer med eksisterende webteknologier er et kvantespring i forhold til at skulle bruge svært tilgængelig software som eksempelvis Visual Studio, og selv her ville man jo skulle lave forskellige versioner af sit program til de forskellige platforme.

Nu kan tiden så kun vise hvorvidt det bliver en kæmpe succes eller blot ender med at være en kæmpe vision, det er jo set før.

Læs mere om Adobe Air her:
Adobe AIR product page

Adobe AIR SDK

Adobe AIR showcase applikationer

Og sidst men ikke mindst, siden der hjælper en godt igang med at lave AIR applikationer via Flash:
Adobe AIR for Flash developers

Red Bull Flugtag Flight Lab - Potentialet i Papervision

fredag, 22. februar 2008

Red Bull Flugtag Flight Lab
Red Bull har til alle tider været et firma som er gået foran når det drejer sig om ekstrem markedsføring, og deres Red Bull Flugtag Flight Lab er absolut ingen undtagelse!

Her får man lejlighed til gennem et relativt simpelt interface at lave et “fly” i 3D, og efterfølgende mulighed for at se hvor langt man kan få det til at flyve.
Hele herligheden er lavet i Flash, blandt andet med brug af Papervision.

Udover at det er super lækkert lavet, så støtter det også perfekt op omkring Red Bull Flugtag, som er en årlig begivenhed hvor rigtige mennesker bygger tossede fly og kaster sig ud fra en bro med dem.
Så, det er helt fortjent at det er kåret til FWA site of the day, og mon ikke det som minimum også bliver kåret til månedens bedste?

Du finder sitet her:
Red Bull Flugtag Flight Lab

Og, du kan læse lidt om udfordringer i forbindelse med udviklingen af spillet her:
Developing Flight Lab

Extend en klasse del 3: Funktion på funktion

tirsdag, 19. februar 2008

Hvis din kode er struktureret fornuftigt, så kan de funktioner du selv har tilføjet til en klasse også genbruges i nye funktioner.
Så, denne gang genbruger vi vores random() funktion fra 2. del til at lave en funktion som er kritisk for ethvert spil kort, og også nyttig i andre sammenhænge, nemlig en shuffle-funktion.

Koden er super simpel, så den får næsten lov til at stå for sig selv:


public function shuffle() {
	var _temp_arr:SuperArray = new SuperArray();
	while (this.length > 0) {
		_temp_arr.push(this.random(true))
	}
	while (_temp_arr.length > 0) {
		this.push(_temp_arr.shift());
	}
}

De to ting der primært er værd at bemærke er at _temp_arr også er af SuperArray typen, hvilket gør at vi kan genbruge random() funktionen fra tidligere, hvilket sker her:

_temp_arr.push(this.random(true))

Og, selvom det jo er et meget simpelt eksempel, så viser det hvordan man med meget få linier og en masse genbrug kan tilføje lækker ny funktionalitet.

Den komplette SuperArray klasse ser nu sådan her ud:


package {
	dynamic public class SuperArray extends Array {

		public function SuperArray(... optionalArgs) {
			for each (var value:* in optionalArgs){
				this.push(value);
			}
			//trace(length);
		}

		public function random(_delete:Boolean = false):* {
			var _random:Number = Math.floor(Math.random() * this.length);
			var _obj:*;
			if(_delete) { //hvis true fjernes elementet
				_obj = this.splice(_random, 1);
			} else { //Ellers returneres det bare
				_obj = this[_random];
			}
			return _obj;
		}

		public function shuffle() {
			var _temp_arr:SuperArray = new SuperArray();
			while (this.length > 0) {
				_temp_arr.push(this.random(true))
			}
			while (_temp_arr.length > 0) {
				this.push(_temp_arr.shift());
			}
		}

	}
}

Som skrevet tidligere, så sig endelig til hvis du har en ide til noget ny funktionalitet som du mener vores SuperArray mangler.

Note: Den kode som kopierer de sorterede elementer fra _temp_arr og tilbage til hovedarrayet kan sagtens optimeres, men denne måde at gøre det på var temmeligt selvforklarende.

Extend en klasse - del 2: Returner en tilfældig

torsdag, 14. februar 2008

Med basen på plads er det nu tid til at lave den egentlige funktionalitet, nemlig en funktion som kan returnere et tilfældigt element fra vores SuperArray.

For at kunne få returneret et tilfældigt element, så skal vi have lidt hjælp af Math.random() funktionen.
Det er en funktion som returnerer et tilfældigt tal fra 0 til 1, og hvis vi kombinerer det med at vi ved hjælp af length kender antallet af elementer i vores SuperArray, så er det såre simpelt at vælge et tilfældigt:

Og det skal vi så have bygget ind i en funktion som på baggrund af tallet returnerer et element:


public function random():* {
	var _random:Number = Math.floor(Math.random() * this.length);
	var _obj:* = this[_random];
	return _obj;
}

Og koden som man så ville bruge i Flash, eller et andet sted, for at bruge den nye funktion i vores SuperArray kunne se sådan her ud:


import SuperArray;
var Super_arr:SuperArray = new SuperArray("kat","hest","hund");
trace(Super_arr.random()); //Viser tilfældigt kat, hest eller hund

Ingen gentagelser
Men men men, hvad nu hvis der er tale om unikke værdier og at hver værdi kun måtte eksistere én gang?

Tag for eksempel et spil kort, her skal man helst ikke kunne få returneret “Spar es” hver gang man kalder funktionen, da der kun må være en “Spar es” i spil ad gangen.
Men, det er jo ikke trods alt ikke altid at værdierne er unikke, så lad os udvide funktionen med en valgfri variabel kaldet _delete:


public function random(_delete:Boolean = false):* {
	var _random:Number = Math.floor(Math.random() * this.length);
	var _obj:*;
	if(_delete) { //hvis true fjernes elementet
		_obj = this.splice(_random, 1);
	} else { //Ellers returneres det bare
		_obj = this[_random];
	}
	return _obj;
}

Og nu kan vi så bruge klassen på følgende måde, hvor hvert dyrt kun vil blive returneret én gang:


import SuperArray;
var Super_arr:SuperArray = new SuperArray("kat","hest","hund");
trace(Super_arr.random(true));
trace(Super_arr.random(true));
trace(Super_arr.random(true));

Samlet klasse
Så, nu ser den komplette SuperArray klasse sådan her ud:


package {
	dynamic public class SuperArray extends Array {

		public function SuperArray(... optionalArgs) {
			for each (var value:* in optionalArgs){
				this.push(value);
			}
			//trace(length);
		}

		public function random(_delete:Boolean = false):* {
			var _random:Number = Math.floor(Math.random() * this.length);
			var _obj:*;
			if(_delete) { //hvis true fjernes elementet
				_obj = this.splice(_random, 1);
			} else { //Ellers returneres det bare
				_obj = this[_random];
			}
			return _obj;
		}
	}
}

I næste artikel bygger vi endnu en smule på, nemlig en funktion som også er kritisk for et spil kort.

Har du i øvrigt en ide til en funktion som du også mener vores SuperArray bør indeholde, så smid endelig en kommentar.

Update: Arg, dammit, så fik jeg trykket udgiv allerede nu så i fik to indlæg i dag, men well, så garanterer jeg ikke for at der også kommer et i morgen ;-)

Extend en klasse - del 1: Grundstrukturen til et SuperArray

torsdag, 14. februar 2008

En af de ting som jeg tit har brug for rundt omkring i min kode, er en funktion som kan returnere et tilfældigt element fra et array.
Så hvorfor ikke lave en ny klasse der kan hjælpe med det, og som kan være grundlag for en lille artikelserie her på omFlash?

First things first
Hovedparten af alle klasserne i ActionScript 3 kan extendes, det vil sige at man laver en ny klasse som tager udgangspunkt i en af de eksisterende.
I dette tilfælde er det oplagt at tage udgangspunkt i den eksisterende Array-klasse, sådan så man ikke skal bruge tid på at skrive logik til alle de eksisterende funktioner som eksempelvis push, pop m.fl. men kan koncentrere sig om at tilføje ny funktionalitet.

Så, derfor kunne den første skabelon se sådan ud:


package {
	dynamic public class SuperArray extends Array {
	}
}

Constructor
Alle klasser har en constructor funktion, som er den funktion der automatisk kaldes når man laver en ny instance af sin klasse.
I dette tilfælde, hvor vores nye klasse hedder SuperArray, ville koden se sådan ud:

var Super_arr:SuperArray = new SuperArray();

Constructor funktionen er altid en public function inde i klassen som hedder det samme som klassen, hvilket gør at vores klasse nu ser sådan her ud:


package {
	dynamic public class SuperArray extends Array {
		//Constructor funktion
		public function SuperArray() {
			trace("nu er jeg oprettet!");
		}
	}
}

For et array gælder der dog det specielle, at man ofte gerne vil oprette arrayet med værdier fra start, eksempelvis sådan her:

Hvis vores nye SuperArray skal have samme funktion, så skal vores constructor udvides så den også kan modtage nogle parametre, og så ser hvor klasse sådan her ud:


package {
	dynamic public class SuperArray extends Array {
		//Constructor funktion
		public function SuperArray(... optionalArgs) {
			for each (var value:* in optionalArgs){
				this.push(value);
			}
		}
	}
}

Note: Hvis du undrer dig over hvad stjernen betyder (*), så er det fordi at man ikke på forhånd kan vide hvilken type parametre der skal modtages.
Det kan være strings som i eksemplet med dyrene, men der kunne lige så godt være tale om movieclips, tal - ja, hvad som helst.

Nu har vi et SuperArray der kan præcis det samme som et standard Array - for vildt - nu er det så tid til at udvide det!

Og det gør vi i del 2 som kommer i morgen.

Aviary - Billedredigering online i Flash Player

tirsdag, 12. februar 2008

Der har længe været snak om, at Adobe et på vej med en online version af Photoshop bygget i Flex, men hvis de ikke passer på, så kan de hurtigt komme bagud.

Bare se nedenstående video der viser Aviary i funktion:

Det må siges at se rigtigt godt ud!

Der hvor jeg synes at online applikationer typisk halter er, at de virker sløve fordi der altid er lidt større forsinkelse på en når man arbejder lokalt, men uanset, så er det vildt at se hvor lækre ting der efterhånden bliver lavet i Flash.

Se mere hos Aviary selv:
Hillary Clinton sheds some skin in Aviary

ActionScript 3: Fremtving garbage collection

mandag, 11. februar 2008

I AS3 er der et par objekter der kan sluge hukommelse så hurtigt, at garbage collectoren ikke på almindelig vis kan følge med, hvilket kan medføre at applikationerne bliver så ustabile så Flash Player crasher.

Eksempelvis har jeg lige lavet en løsning med nogle store BitmapData objekter, her steg hukommelseforbruget fra 100 MB til 800 MB på få sekunder, hvorefter det faldt til 100 MB når garbage collectoren automatisk startede, for så at stige igen.

Løsningen for mig blev at fremtvinge garbage collection stort set hele tiden, og dermed forblev hukommelsesforbruget rimelig stabilt på omkring 150MB.
Ulempen ved det er at garbage collection bruger en del CPU, men i mit tilfælde var hukommelsesforbruget den store flaskehals, så det var til at leve med.

Måden man fremtvinger den på er absolut et hack, men det virker og der findes ikke nogen officielle måder at gøre det på.
Man forsøger simpelthen at oprette to localconnections til det samme objekt, og det genererer en fejl der fremtvinger garbage collection:


try {
	new LocalConnection().connect('foo');
	new LocalConnection().connect('foo');
} catch (e:*) { }

Men husk, brug det med omtanke!
Normalt kan Flash Player selv håndtere det fornuftigt, og da det er et hack er der ingen garanti for at det bliver ved med at virke.

Garbage collection i ActionScript 3 - Husk scope!

fredag, 8. februar 2008

En af de nye ting i AS3 er en “rigtig” garbage collector, som fungerer ligesom i mange andre programmeringssprog, men det betyder også at man lige skal være opmærksom på et par ting i forhold til AS2.

Et problem jeg selv stødte på for nylig, var en programmeret tween, som nægtede at gøre det den skulle, på trods af at koden ikke fejlede noget og havde virket i tidligere versioner af samme prohekt.

Her er et eksempel svarende til den kode der drillede, og som i øvrigt var en del af en større klasse:


private function moveSomething():void {
	var myTween:Tween = new Tween(
					Mit_mc,
					"x",
					Strong.easeOut,
					Mit_mc.x,
					Mit_mc.x + 50,
					2,
					true
					);
}

Har du fundet fejlen?
Nej, det tog også mig lidt tid - for der er ikke nogen fejl, det er fuldt lovlig kode!

Det jeg fandt ud af var den primære forskel på den tidligere version af projektet, hvor tweenet virkede, og den nye var, at der var blevet tilføjet nogle ekstra elementer som var ekstremt hukommelsesintensive.
Og, når man presser Flash i ActionScript 3, så betyder det at garbage collectoren rydder op oftere, da Flash Player kæmper for at minimere ressourceforbruget og dermed optimere performance.

Har du fundet fejlen nu?

Fejlen er simpelthen den, at objektet myTween defineres inde i den private funktion, hvilket betyder at når garbage collectoren rydder op, så finder den ikke nogen referencer til objektet, og det på trods af at animationen måske kun er halvfærdig.

Derfor er løsningen så simpel som at definere objektet uden for funktionen:


var myTween:Tween;
private function moveSomething():void {
	myTween = new Tween(
				Mit_mc,
				"x",
				Strong.easeOut,
				Mit_mc.x,
				Mit_mc.x + 50,
				2,
				true
				);
}

Så, i ActionScript 3 skal man tænke endnu mere over at definere variabler og objekter i det rigtige scope, ellers så kan der opstå nogle finurlige problemer.

Winter wonderland i Papervision

tirsdag, 5. februar 2008

For nogle år tilbage var der en person som havde synkroniseret julelysene på sit hus til sangen “Wizards In Winter”, og nu er der en der har brugt det som inspiration til at lave det samme, men i Papervision:
Winter Wonder Land Animation - I’m a little late

Glimrende eksempel på hvor langt Papervision er kommet og på hvordan man nemt kan spilde en masse tid ;-)