Visuals til Se mor! fødselsdagsfest

Kategori: Egne projekter | Kommentarer (2)
Gemt: 2008-03-3 14:42


Der var lidt stille her på bloggen i sidste uge, og det skyldes simpelthen at vi i fredags d. 29. februar holdt en stor 1 års fødselsdagsfest for det firma som jeg er medstifter af, Se mor!.
Derfor gik det meste af min tid i sidste uge med de praktiske forberedelser til festen, samt ikke mindst, på at lave nogle sjove visuals der kunne vises på projektor.

Resultatet blev en lille applikation med både almindelige videoklip, såvel som lidt interaktivt webcamsjov.

Da det hele ikke giver sig selv, skulle kun betjenes af os, så kommer der her en lille forklaring, link følger til sidst.

Det overordnede
Vi ville gerne have en applikation som kunne køre hele aftenen, uden at vores almindelige skrivebord nogensinde blev synligt for gæsterne, så derfor valgte vi at lave en samlet applikation med det hele i, som vi kunne betjene via tastaturet, nærmere betegnet med tasterne 1-5 samt 0.

NB: Virker kun på de almindelige tal, ikke på det numeriske tastatur.

Tast 1

En lille stiliseret video hvor man ser en papirflyver blive foldet.

Tast 2

En række stills med farvekridt sat sammen til en video.

Tast 3

Igen række stills sat sammen til en video.

Tast 4

Viser indholdet fra et webcam 24 gange, men med et delay på 100 millisekunder mellem hvert billede.
Derudover ændrer trekanternes mønster sig også tilfældigt.

Tast 5

Papirflyvere som genereres automatisk og herefter flyver henover skærmen mens de trækker et røgslør efter sig.
Selvom man ikke lige kan se det, så gør denne applikation også brug af webcammet.

Hver gang en ny papirflyver genereres, så tager den et snapshot fra webcammet og beregner gennemsnitsfarven på det, og det er så denne farve som bruges til røgsløret.
Prøv selv at vifte med hænderne foran de webcam, eller at holde noget med en kraftigt farve hen foran det.

Tast 0
De fleste af disse visuals er ganske korte, og eftersom vi helst også skulle have tid til gæsterne, så kunne vi jo ikke bruge hele aftenen foran skærmen.
Derfor er 0 simpelthen en selvkørende random-funktion, hvor den med jævne mellemrum selv skifter mellem de forskellige visuals.

Effekt
Meget mod min forventning, så opførte Flash sig eksemplarisk hele aftenen, så vi havde faktisk ikke et eneste nedbrud på vores visuals, hvilket i sig selv var fedt.
Og, derudover viste det sig at være rigtig fedt at kunne skifte hurtigt mellem de forskellige scener med tastaturet, noget som vi blandt andet brugte til at ramme takten under koncerten med Turboweekend.

Link
Og her kommer linket så, men inden du klikker på det, så husk at det er en applikation som egentlig er lave til offline brug, og derfor er der ikke nogen loader, på trods af at den fylder 12 MB.
Når den kommer frem og beder om adgang til webcammet, så er den loadet, og herefter kan du trykke på 1-5 samt 0 for at se hvad den kan.

Se mor! party visuals

Invitationen
I øvrigt, så er invitationen også lavet i Flash, med brug af Turboweekends musik og lidt sjov med ComputeSpectrum:
Se mor! 1 års fødselsdagsfest


Extend en klasse del 3: Funktion på funktion

Kategori: Tips og tricks | Kommentarer (0)
Gemt: 2008-02-19 14:00


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

Kategori: Tips og tricks | Kommentarer (2)
Gemt: 2008-02-14 17:38


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

Kategori: Tips og tricks | Kommentarer (0)
Gemt: 2008-02-14 16:50


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.


ActionScript 3: Fremtving garbage collection

Kategori: Tips og tricks | Kommentarer (3)
Gemt: 2008-02-11 11:18


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!

Kategori: Tips og tricks | Kommentarer (0)
Gemt: 2008-02-8 12:10


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.


Fysik i ActionScript 3 - Nu meget nemmere!

Kategori: Diverse | Kommentarer (0)
Gemt: 2008-01-23 11:21


Har du gået og drømt om at lave et spil eller site i AS3 med noget der minder om rigtig fysik, men har du indtil nu syntes at det virkede som for stor en mundfuld? Så er hjælpen på vej!

Herry Jones har lavet en lille liste med 4 open-source ActionScript 3 fysik moduler, som gør det væsentligt nemmere at komme igang:
ActionScript 3 Physics Engines

Og, som om det ikke var nok, så er der endnu et modul som ikke er på hans liste, nemlig WOW-Engine som er et 3D fysik modul der bygger på Papervision og Sandy:
AS3 3D Physics Engine : WOW-Engine

Kan til stadighed blive imponeret over hvor meget open-source hjælp der er tilgængeligt derude, fantastisk!


ActionScript 3 - Send events fra dine egne klasser

Kategori: Tips og tricks | Kommentarer (3)
Gemt: 2007-12-13 11:30


Et super hurtigt lille tip: Hvis du har lavet en klasse som extender en allerede eksisterende klasse, eksempelvis Sprite eller Movieclip, så er det super nemt at sende events.

Der hvor du vil starte en event indsætter du bare følgende kode:

dispatchEvent(new Event(Event.COMPLETE));

Her er det en Event.COMPLETE, men man kan naturligvis sende en hvilken som helst eventtype på denne måde.


Julehjerte i ActionScript 3

Kategori: Diverse | Kommentarer (0)
Gemt: 2007-12-12 12:32


Julen er over os, og det inspirerede mig lige til at lege lidt med drawing apien i ActionScript 3, og resultatet blev en klasse til at lave julehjerter.

Som demonstration, lige et lille eksempel hvor man kan stille på størrelsen, antallet af striber og farverne:

Koden der skal til inde i Flash for at lave et julehjerte er ganske minimal:

import semor.graphics.XmasHeart;
var heart:XmasHeart = new XmasHeart();
addChild(heart);
heart.init(200, 5, 0xFFFFFF, 0x89C64C);

Download
Eksempel fla
AS3 klassen - XmasHeart

Brug den til lige hvad du har lyst til, men smid gerne en mail - er jo nysgerrig :-)

Glædelig jul!


ActionScript 3 - Objektet der ikke var der, endnu!

Kategori: Tips og tricks | Kommentarer (0)
Gemt: 2007-11-29 11:45


En klassisk metode i ActionScript 2 når man skulle manipulere med objekter i et movieclip var følgende:

MitMC.gotoAndStop("login");
MitMC.Login_txt.text = "Klik for at logge ind";

Men, forsøger du at gøre det i AS3, så får du en fejl, da Login_txt først eksisterer i kodemæssig forstand når det er blevet renderet, det eksisterer ikke blot fordi du er hoppet hen i en frame hvor du ved at det er.

Ved hjælp af eventen RENDER er der dog en måde at gøre noget tilsvarende på:

MitMC.gotoAndStop("login");
MitMC.addEventListener(Event.RENDER, initiateLogin);

function initiateLogin(e:Event) {
MitMC.Login_txt.text = "Klik for at logge ind";
}

Det kræver lidt mere kode end tidligere, men det fungerer fint.

Hvorvidt det så er bad practice eller ej, det vil jeg lade op til andre om at vurdere, men engang imellem er det jo helt okay at hoppe over hvor gærdet er lavest :-)