Equalizer explained

Some time ago I’ve made this Equalizer (sorry, you need to close all other swfs like youtube player etc). I’ve been thinking of describing it here for quite a long time.. No excuse, I ve been lazy ;) Ok, let’s cut to the chase.

First we need to grab music data. Code below gets global spectrum data, converts sound from stereo to mono, simplifies wave to given amount of values and counts wave average value (some kind of wave normal).

 
package pl.szataniol.equalizer.music {
 
	import flash.events.EventDispatcher;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundMixer;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
 
	/**
	 * @author Andrzej Korolczuk (http://blog.szataniol.pl)
	 */
	public class Equalizer extends EventDispatcher {
 
		private static const CHANNEL_LENGTH : uint = 512;
 
		private var music : Sound = new Sound();
		private var channel : SoundChannel;
 
		private var output : ByteArray = new ByteArray();
 
 
		public function Equalizer() {
 
			super();
			initEqualizer();
		}
 
		private function initEqualizer() : void {
 
			music.load(new URLRequest("jam.mp3"));
			channel = music.play();
		}
 
		public function step() : void {
 
			SoundMixer.computeSpectrum(output);
		}
 
		public function getData(numValues : uint = 16) : EqualizerData {
 
			var simplifiedWave : Vector.<Number> = getSimplifiedWave(numValues);
 
			var average : Number = 0;
 
			for (var i : int = 0;i < simplifiedWave.length;i++) {
 
				average += simplifiedWave[i];
			}	
 
			average /= numValues;
 
			return new EqualizerData(simplifiedWave, average);
		}
 
		public function getSimplifiedWave(numValues : uint = 16) : Vector.<Number> {
 
			var waveValues : Vector.<Number> = new Vector.<Number>(numValues, true);
 
			var valueIndex : uint = 0;
 
			while(valueIndex < CHANNEL_LENGTH / 2) {
 
				waveValues[Math.floor(valueIndex / CHANNEL_LENGTH * numValues)] = Math.abs(output.readFloat());		
				valueIndex++;	
			}
 
			while(valueIndex < CHANNEL_LENGTH) {
 
				waveValues[Math.floor((valueIndex - CHANNEL_LENGTH / 2) / CHANNEL_LENGTH * numValues)] += Math.abs(output.readFloat());			
				valueIndex++;	
			}
 
			for (var i : int = 0;i < waveValues.length;i++) {
 
				waveValues[i] /= 6;
			}
 
 
			return waveValues;
		}
 
		public function getOutput() : ByteArray {
 
			return output;
		}
	}
}

Now the part that might not be so clear. Equalizer is created by drawing a movieclip into a bitmap and aplying some effects. Movieclip (i called it Ghost) is consisted of 16 particles (GhostParticles) with blend mode set to “add”. Every GhostParticle contains a blurred white circle:

GhostParticle

Here’s how Ghost looks on stage:

Ghost

Final effect applied on Ghost is glow with knockout:

Ghost Final

GhostParticle class looks like this:

package pl.szataniol.equalizer.display.ghost {
	import flash.display.Sprite;
 
	/**
	 * @author Andrzej
	 */
	public class GhostParticle extends Sprite {
 
		private const MIN_ANGULAR_SPEED : uint = 2;
		private const MAX_ANGULAR_SPEED : uint = 8;
 
		private const MIN_SCALE : Number = .6;
		private const MAX_SCALE : Number = 1;
 
		private const MIN_OFFSET : int = 0;
		private const MAX_OFFSET : uint = 50;
 
		private var gamma : Number;
		private var angularSpeed : Number;
		private var offset : Number;
		private var scale : Number;
 
		public var mc : Sprite;
 
		private var _boost : Number = 0;
 
		public function GhostParticle() {
 
			initGhostParticle();
		}
 
		private function initGhostParticle() : void {
 
			initParams();
 
			mc.y = offset;
			rotation = gamma;
			scaleX = scaleY = scale;
			alpha = Math.random() * 5 + .5;
		}
 
		private function initParams() : void {
 
			scale = MIN_SCALE + Math.random() * (MAX_SCALE - MIN_SCALE);
			offset = MIN_OFFSET + Math.random() * (MAX_OFFSET - MIN_OFFSET);
			gamma = Math.random() * 360;
			angularSpeed = (Math.random() < .5 ? 1 : -1) * (MIN_ANGULAR_SPEED + Math.random() * (MAX_ANGULAR_SPEED - MIN_ANGULAR_SPEED));
		}
 
 
		public function step() : void {
 
			gamma += angularSpeed;
			rotation = gamma;
			mc.y += ((offset - _boost * 40) - mc.y) / 4;
			mc.y += (offset - mc.y) / 8;
			_boost *= .9;
			scaleX =  scale + _boost * 2;
		}
 
		public function set boost(boost : Number) : void {
 
			_boost = boost;
		}
	}
}

Particles have several randomized variables: alpha, angularSpeed, offset and scale. Offest is circle sprite “y” value. Each particle is moving in a circular motion with radius based on offset and “boost”, which represents current simplified sound wave value.

Ghost class calls step() function and delegates boost value to each particle.

Ok now that we have our base MovieClip ready we can start some fun with BitmapData. The cycle looks like this:

- calculate color for ColorTransform (each channel value is based on sine function)
- if wave normal is greater then some value and last glow wasn’t applied in 6 frames apply it.
- recalculate perlin noise used for DisplacementMapFilter
- apply DisplamcentMapFilter
- draw ghost MovieClip with alpha based on wave normal
- scroll BitmapData by value based on wave normal
- apply ColorTransform
- apply BlurFilter

Here’s the code:

package pl.szataniol.equalizer.display {
	import flash.filters.DisplacementMapFilterMode;
	import flash.filters.DisplacementMapFilter;
	import flash.display.BitmapDataChannel;
	import flash.geom.Rectangle;
	import flash.filters.GlowFilter;
 
	import pl.szataniol.equalizer.display.ghost.Ghost;
	import pl.szataniol.equalizer.music.Equalizer;
	import pl.szataniol.equalizer.music.EqualizerData;
 
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.BlurFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
 
	/**
	 * @author Andrzej
	 */
	public class EqualizerMain extends Sprite {
 
		private var equalizer : Equalizer = new Equalizer();
 
		public var ghost : Ghost;
 
		private var perlinBitmapData : BitmapData = new BitmapData(160, 120, true, 0x0);
		private var bitmapData : BitmapData = new BitmapData(640, 480, true, 0x0);
		private var bitmap : Bitmap = new Bitmap(bitmapData);
		private var zero : Point = new Point(0, 0);
 
		private var matrix : Matrix ;
		private var colorTransform : ColorTransform = new ColorTransform(0.98, .98, 1, .92);
 
		private var redMultiplier : Number;
		private var redGamma : Number = Math.random() * Math.PI * 2;
		private var blueMultiplier : Number;
		private var blueGamma : Number = Math.random() * Math.PI * 2;
		private var greenMultiplier : Number;
		private var greenGamma : Number = Math.random() * Math.PI * 2;
 
		private var redSpeed : Number = 0.01 + Math.random() * 0.02;
		private var blueSpeed : Number = 0.01 + Math.random() * 0.02;
		private var greenSpeed : Number = 0.01 + Math.random() * 0.02;
 
		private var bitmapDataRect : Rectangle;
 
		private var lastBoost : int = 0;
		private var blurFilter : BlurFilter = new BlurFilter(2, 8, 3);
 
		public function EqualizerMain() {
 
			initEqualizerMain();
		}
 
		private function initEqualizerMain() : void {
 
			addChild(bitmap);		
			removeChild(ghost);
 
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);	
 
			matrix = new Matrix(ghost.scaleX, 0, 0, ghost.scaleY, ghost.x, ghost.y);
			bitmapDataRect = bitmap.bitmapData.rect;
			perlinBitmapData.perlinNoise(120, 120, 1, Math.random(), false, true, BitmapDataChannel.RED | BitmapDataChannel.GREEN);
 
		}
 
		private function enterFrameHandler(event : Event) : void {
 
			step();
		}
 
		private function step() : void {
 
			equalizer.step();
			ghost.step();
 
			handleColors();
 
			var eqData : EqualizerData = equalizer.getData(16);
			ghost.boost = eqData.wavesData;
 
			matrix.a = matrix.d = Math.max(.75, Math.min(eqData.average, 1.2));
			lastBoost++;
 
			if(eqData.average > .7 && lastBoost > 6) {
 
				lastBoost = 0;
				bitmap.bitmapData.applyFilter(bitmap.bitmapData, bitmap.bitmapData.rect, zero, new GlowFilter(0xffffff, .8, 32, 32, .25 + eqData.average * 1.8, 3)); 
			}
 
			perlinBitmapData.perlinNoise(120, 120, 1, Math.random(), false, true, BitmapDataChannel.RED | BitmapDataChannel.GREEN);
 
 
			bitmap.bitmapData.applyFilter(bitmap.bitmapData, bitmapDataRect, zero, new DisplacementMapFilter(bitmap.bitmapData, zero, BitmapDataChannel.RED, BitmapDataChannel.GREEN, 12, 12, DisplacementMapFilterMode.IGNORE, 0));			
			bitmap.bitmapData.draw(ghost, matrix, new ColorTransform(1, 1, 1, .1 + Math.max(.9, eqData.average)));
			bitmap.bitmapData.scroll(0, -2 - eqData.average * 10);
			bitmap.bitmapData.colorTransform(bitmap.bitmapData.rect, colorTransform);
			bitmap.bitmapData.applyFilter(bitmap.bitmapData, bitmap.bitmapData.rect, zero, blurFilter);
		}
 
		private function handleColors() : void {
 
			redGamma += redSpeed;
			greenGamma += greenSpeed;
			blueGamma += blueSpeed;
 
			redMultiplier = .95 + Math.sin(redGamma) * .05;
			blueMultiplier = .95 + Math.sin(blueGamma) * .05;
			greenMultiplier = .95 + Math.sin(greenGamma) * .05;
 
			colorTransform.redMultiplier = redMultiplier;
			colorTransform.blueMultiplier = blueMultiplier;
			colorTransform.greenMultiplier = greenMultiplier;
		}
	}
}

That’s about it. You can download sources here. Song I used is Eastern Jam by Chase and Status.

Posted in actionscript | Tagged , , | Leave a comment

O zabezpieczaniu gier powiastka

Below is the article I wrote for Software Development Journal about protecting games and applications against hackers. Unfortunately it is in polish. If you feel this article could be valuable for you please let me know and I will translate it.

Zabezpieczanie gier i aplikacji w Adobe Flash

Dowiesz się:

- jak zabezpieczać  swoje gry i aplikacje przed hackerami

Powinieneś wiedzieć:

- jak programować w ActionScript 3.0 na poziomie przynajmniej średnio-zaawansowanym

Wstęp

Tylko nieliczne aplikacje i gry w Internecie są należycie zabezpieczone. Programując w technologii Adobe Flash musisz mieć na uwadze kilka „furtek”, z których korzystają hakerzy przy włamywaniu się do aplikacji. W niniejszym artykule postaram się pokazać Ci co zrobić, aby zabezpieczyć owoce swojej pracy. Skupimy się głównie na grach, jako że to one najczęściej są atakowane przez hackerów.

Flash jest technologią typu client-side. W praktyce oznacza to, że jeśli nie przeniesiesz logiki na serwer (tzw. „cienki klient”) nigdy nie możesz mieć stuprocentowej pewności, że  Twoja aplikacja będzie bezpieczna. Możesz jednak utrudnić zadanie potencjalnemu hakerowi  na tyle, by się zniechęcił.

Cienki klient

Cienki klient jest bezapelacyjnie najpewniejszym rozwiązaniem. Polega na przeniesieniu całej logiki gry lub aplikacji na serwer, podczas gdy Flash zajmuje się jedynie wyświetlaniem wyników i przekazywaniem do serwera kolejnych ruchów klienta. Jest jednak poważna wada takiego podejścia: wszystkie obliczenia wykonywane dotychczas na komputerze klienta zostaną przeniesione na serwer, co w praktyce oznacza dużo wyższe koszty hostingu. Jeżeli bezpieczeństwo jest priorytetem, np. w konkursie z cennymi nagrodami, warto przekonać klienta, by przeznaczył dodatkowe fundusze na utrzymanie serwerów w zamian za spokojny przebieg rywalizacji. Dodatkowym atutem takiego rozwiązania jest brak konieczności wprowadzania innego typu zabezpieczeń, co pozwala na skrócenie czasu produkcji.

W zależności od aplikacji cienki klient może być oparty na przykład na Flash Media Server (gry typu Memo, Snake, proste „turówki”) lub sesji w PHP (np. quiz). W przypadku FMS’a jeśli nie posiadasz licencji możesz skorzystać z usług firm hostingowych, np. Influxis (www.influxis.com) wybierając plan z dużą iloscią jednoczesnych połączeń i małym transferem, jako że zazwyczaj przesyłane są nieduże ilości danych. Dużym atutem FMS’a jest możliwość weryfikacji komunikującego się z nim SWF’a oraz szyfrowany kanał komunikacyjny RTMPE.

Jeśli jednak zastosowanie tego rozwiązania jest z jakiejś przyczyny niemożliwe musisz zadbać, by zminimalizować ryzyko włamania się do Twojej aplikacji. Musisz jednak mieć na uwadze, że niezależnie od ilości zabezpieczeń Twoja gra lub aplikacja nigdy nie będą w 100% bezpieczne, jeżeli logika nie jest ukryta po stronie serwera.

Furtki, czyli o czym musisz pamiętać.

Obfuscator

Absolutną podstawą przy zabezpieczaniu swf’ów jest obfuscator. Jest to program, który na celu ma takie zmodyfikowanie pliku wynikowego, by był on zrozumiały dla maszyny wirtualnej, ale niezrozumiały dla dekompilatora. Przykładowe obfuscatory to np. secureSWF firmy Kindisoft lub SWF Encrypt stworzony przez Amayeta. Przez długi czas prezentujący się obiecująco secureSWF był liderem na rynku, niestety istnieje już oprogramowanie (www.swf-reader.com) odwracające proces, któremu secureSWF poddaje pliki. W praktyce oznacza to, że swf potraktowany secureSWF’em może jednym kliknięciem zostać z powrotem odbezpieczony.

Dlaczego jest to takie ważne? Największym niebezpieczeństwem jest podmiana zmodyfikowanego przez hackera swf’a przez proxy lub bezpośrednio w pamięci procesu przeglądarki. Jeżeli kod Twojego swfa jest jasny i czytelny hacker bez większych trudności może go zmodyfikować i podmienić, co jest niemożliwe do wykrycia. Innymi słowy jeżeli nie zabezpieczysz obfuscatorem swojego swf’a  wszystkie inne zabezpieczenia zawiodą.

Komunikacja klient – serwer

Wysyłając do serwera ważne dane musisz zadbać o to, by dla trzeciej osoby były niemożliwe do zmodyfikowania. Warto pomyśleć o szyfrowaniu i sumach kontrolnych – im więcej tym lepiej. Algorytmy szyfrujące dzielimy na symetryczne i asymetryczne. W przypadku szyfrowania po stronie klienta nie ma większej różnicy, z którego typu korzystasz. Jeżeli odpowiednio nie ukryjesz klucza przed osobą korzystającą z dekompilatora całe zabezpieczenie zda się na nic.

Najczęściej używane algorytmy szyfrującesymetryczne to AES, DES iBlowfish. Zazwyczaj są one mniej obciążające dla komputera niż algorytmy asymetryczne (np. RSA), dlatego powinieneś skupić się właśnie na nich. Najpopularniejsze algorytmy generujące sumy kontrolne to MD5 lub SHA-1.

Ukrywanie klucza

Musisz mieć na uwadze fakt, iż obfuscator nie zabezpieczy Twojego klucza (!). Dobry dekompilator może być w stanie wyciągnąć wartość zmiennej.  Najlepszym sposobem jest dynamiczne wstrzyknięcie klucza do generowanego po stronie serwera swfa. Niestety realia projektów rzadko kiedy pozwalają na poświęcenie znacznej ilości czasu na zabezpieczenia. Jeżeli ilość zer w budżecie Twojego projektu nie pozwala na tego typu wyszukane metody musisz ratować się półśrodkami.

Dobrym, prostym sposobem jest generowanie klucza z transformowanego MovieClipa. Na przykład:

private function getKey():void{
 
	keyDefinition = getDefinitionByName("keyGetter") a sClass;
	var keyClip:Sprite = new keyDefinition();
	keyClip.rotation = 14;
	var i :int = 16;
	while(i--){
		keyClip.rotation+= 17;
		key += (Math.round(keyClip.width+keyClip.height)%keyClip.rotation);
	}
}

Klucz ukryty w taki sposób jest już względnie bezpieczny, aczkolwiek wyciągnięcie go jest tylko kwestią większego nakładu pracy ze strony hackera.

Logowanie przebiegu gry

Bardzo dobrym pomysłem jest logowanie przebiegu gry – im więcej informacji zbierzesz tym łatwiej będzie Ci przesiać nieuczciwe wyniki. Możesz zapisywać wszystko – od ilości punktów w danym momencie rozgrywki, poprzez wykonywane  co jakiś czas kontrolne screeny, aż do zapisywania wszystkich pozycji kluczowych MovieClip’ów, ruchów myszką, kliknięć i uderzeń klawiszy. Im pełniejszy zapis gry tym trudniej będzie go podrobić. Dobrze jest poświęcić trochę czasu na optymalizację tej czynności: dowiedz się jakiego mniej więcej ruchu w swojej aplikacji możesz się spodziewać, jaki jest limit transferu, który możesz wykorzystać i dobierz do tego maksymalną wagę pliku, w którym będziesz przechowywać dane przebiegu gry.

Modyfikowanie pamięci

Furtką, o której często zapominają developerzy jest stosowanie przez nieuczciwych graczy programów typu Cheat Engine lub Memory Hacking Software. Programy te pozwalają na modyfikowanie pamieci procesu „w locie”. Dzięki tego typu oprogramowaniu hacker może znaleźć w pamięci wartość zmiennej odpowiadającą np. za uzyskane punkty lub czas i dowolnie ją zmodyfikować. Cały proces jest dziecinnie prosty i zajmuje kilkanaście sekund. W równie prosty sposób możesz zabezpieczyć się przed tego typu atakami:

package com.nobagames.utils{
 
	/**
	 * @author Andrzej Korolczuk
	*/
	public class ProtectedInt{
 
		private var _value :Number;
		private var shift:int;
 
		public function ProtectedInt(){
 
			shift = 10+int(Math.random()*990);
			_value = shift;
		}
 
		public function setZero():void{
 
			_value = shift;
		}
 
		public function add(value:int):void{
 
			var nextShift:int = 10+int(Math.random()*990);
			_value += nextShift-shift+value;
			shift = nextShift;
		}
 
		public function subtract(value:int):void{
 
			add(-value);
		}
 
		public function multiply(value:Number):void{
 
			var nextShift:int = 10+int(Math.random()*990);
			_value -= shift;
			_value *= value;
			_value += nextShift;
			shift = nextShift;
		}
 
		public function divide(value:Number):void{
 
			multiply(1/value);
		}
 
		public function getValue():int{
 
			return _value -shift;
		}
		public function toString():String{
 
			return String(getValue());
		}
	}
}

Klasa ta przesuwa wartość prawdziwej zmiennej o losową wartość uniemożliwiając wyszukanie jej wyżej wymienionymi programami. Po każdej operacji przesunięcie jest wyliczane ponownie, by jeszcze bardziej zmylić hackera. Jeżeli cały proces modyfikowania pamięci nie jest dla Ciebie jasny, obejrzyj na Youtube dowolny filmik z wyników wyszukiwania frazy „Cheat Engine”.

Programy te nie ograniczają się jedynie do modyfikowania pamięci. Używając ich można również spowolnić lub przyspieszyć proces przeglądarki, co może być wykorzystywane na przykład do wydłużenia czasu na reakcję w grę zręcznościowej. Najlepszą obroną na tego typu sztuczki jest porównanie czasu, który upłynął po stronie serwera z czasem, który upłynął po stronie klienta.

Boty

Niedawno spotkałem się z przypadkiem, w którym osoba biorąca udział w konkursie napisała program w C#, który imitował odkrywanie kart w grze typu Memo, korzystając z Windows API. Po odsłonięciu wszystkich kart po kolei program wiedział, gdzie dokładnie znajdują się kolejne pary i w błyskawicznym tempie odkrywał je.

Stanowczo jest to najbardziej pracochłonny sposób na nieuczciwe rywalizowanie, ale też jest najcięższy do wykrycia. Analizując logi lub pliki przebiegu gry warto zwrócić uwagę na powtarzające się interwały zdarzeń, sztuczne, mechaniczne ruchy myszką itp.

Inne

Dobrym pomysłem jest zmienianie jakiegoś detalu w swoim SWF’ie. Może być to kolor przycisku lub zmienna wysyłana na serwer. Dzięki temu, jeżeli obfuscator zawiedzie i hackerowi uda się podmienić SWFa na swoją wersję możesz być w stanie udowodnić mu, że oszukiwał. Najlepszym pomysłem jest wprowadzanie takiej zmiany codziennie. Prawdopodobieństwo, że potencjalny haker będzie sprawdzał codziennie czy plik na serwerze się nie zmienił jest raczej znikome.

Podsumowanie

Żadna kombinacja opisanych przeze mnie zabezpieczeń nie gwarantuje stuprocentowej pewności, jeżeli logika działania aplikacji znajduje się w pliku SWF. Prawdopodobnie też istnieje wiele innych sposobów, wykorzystywanych przez hackerów, o których nawet nie słyszałem. Jedynym sposobem dającym pełne bezpieczeństwo jest cienki klient i najprawdopodobniej wraz z kolejnymi wersjami Flash Playera nic się w tym temacie nie zmieni.

Posted in actionscript | 1 Comment

Redkroft’s clients effect

Recently we’ve launched a new Redkroft website. We are getting a lot of positive feedback, which is really great. :)

If you launch the clients section you’d see a couple of logos with a nice highlighting effect. It was actually developed on the train while I was on terrible hangover. ;) Here are step-by-step instructions on how to achieve something similar.

First of all we need our logotypes or whatever graphics you’d like to apply this effect to.

Next we create a copy of it and apply some nice glow filter:

Now is the interesting part. We need to create a MovieClip which would behave like a moving cloud. To do this, we first create a MovieClip with a circle inside of it. Next step is to shift the shape inside of our MovieClip to change it’s pivot point:

Next we create a simple classic tween setting with a single CW or CCW rotation. Later we’ll use a few of those circles. To make the effect more random you should use different rotation directions and number of frames.

Now apply a Blur Filter to the MovieClip (try to avoid low quality). You should get something like this (click to launch swf file):

[flash http://blog.szataniol.pl/assets/redkroft/circles.swf w=300 h=200 preview={http://blog.szataniol.pl/assets/redkroft/circles.jpg|150|100} mode=3]

Final step is to combine a few of those blurred Movie Clips into a sort of cloud. Try putting them together with different scales and angles. As I’ve mentioned above good idea is to maximise randomness by using different number of frames in a MovieClip so your cloud won’t have animation cycles.

This might not be very important, but if you set blendMode of those Movie Clips to ADD your mask would cover the middle of your graphics more and the edges less and this was exactly what I’ve wanted to achieve. Check out the final clouds below. The one on the right is using BlendMode.ADD:

[flash http://blog.szataniol.pl/assets/redkroft/masks.swf w=400 h=200 preview={http://blog.szataniol.pl/assets/redkroft/masks.jpg|200|100} mode=3]

Last thing to do, is to set your mask and graphics MovieClips cacheAsBitmap values to true (this is the only way to make masks with alpha channel work) set the mask and make it follow the mouse with a nice slowing-down ease.

You can check the final effect here:

[flash http://blog.szataniol.pl/assets/redkroft/clients.swf w=850 h=400 preview={http://blog.szataniol.pl/assets/redkroft/clients_preview.jpg} mode=3]

The sources and code are avaible here. Enjoy!

Posted in Uncategorized | 1 Comment

I’m a lucky bastard!

Every six months Adobe is granting one of RIA Devs members with 2000$ software voucher. This year Christmas came a little bit earlier for me as I became a lucky winner. :) Woo woo!

PS. RIA Devs is open group so please join us if you are capable of attending events once a month in Warsaw. It’s a great opportunity to exchange experience and occasionally get some stuff from Adobe.

Posted in Uncategorized | 1 Comment

Case Study: Ying-Yang Preloader

I’ve been thinking about posting this one for a long time. It was created when I was working at Publicis Modem, in project for Garnier. Later it was used as a recruitment assignment. As far I as remember only one person dealed with it properly.

Developer was given .fla file with graphics, so at first he needed to prove his knowledge of JSFL to create about 180 movieclips (or he could do this manually – happy clicking :) ). Next he had to create multiple instances of ball classes holding reference to it’s movieclip. Balls were randomly sorted and later added to stage with increasing loading progress (0% – 0 balls in stage, 100% – all balls on stage)

Second part of task was to figure out what the hell is going on there. As you can see the balls are moving chaotically at first. The more data is loaded the slower and more smooth becomes the speed vector to stop at last and form a ying-yang symbol.

The trick was to create several points, which were attracting balls. Several months ago I wrote post about mouse avoiding. You can easily achieve attraction effect just by reversing the vector.

Those points where moved by TweenLite, sliding from one position to another within a circle. The more data were loaded, the less was the attraction force.

Final effect:

[flash http://blog.szataniol.pl/assets/preloader.swf w=550 h=400 preview={http://blog.szataniol.pl/assets/preloader_thumb.jpg|137|134} mode=3 caption={Ying Yang Preloader}]

Force spots are those red, little balls. If you find this description not clear enough please post and I will upload the source.

Posted in Uncategorized | 4 Comments

Perlin noise, papervision3D, particles

Time to break the silence! Some people were asking me recently why I dropped blogging.. Well, I’ve never made any decision like that, just didn’t have a lot of time.. or (what’s most proabable) I was just too lazy. ;) Today I’m posting this little demo of.. I don’t really know what the hell is this. It’s just some stuff I made while I was sick. It actually does not make any sense, however some of you might find something useful in the code.

Demo:

[flash http://blog.szataniol.pl/assets/fun/fun.swf w=640 h=450 preview={http://blog.szataniol.pl/assets/fun/fun_thumb.jpg|108|108} mode=3]

Source

Posted in Uncategorized | Leave a comment

Unity3D Paintball Demo

Well “demo” is not enough to express awesomeness of this stuff. Check it out! It’s hard to admit, but based on multiplatform game development tool called Unity3D it totally kicks flash games ass!

Posted in Uncategorized | Leave a comment

JigLib ported to Flash

JigLib is a 3D physics engine written in C++. Ported to ActionScript 3.0 by muzerly using Papervision3D it can be downloaded here. Demo looks very promising!

Posted in Uncategorized | Leave a comment

Help do CS4 po polsku!

Dzisiaj post wyjątkowo po polsku ;) swiezy przypadkiem :D znalazł na sieci polskie tłumaczenie helpa do Flasha CS4. Całość wygląda dość zgrabnie i profesjonalnie. Helpa można przeglądać online lub pobrać na dysk w formacie PDF.

Posted in Uncategorized | 1 Comment

25lines.com finalists

You can take a look at swfs and code of 12 finalists of The 25 Lines ActionScript Contest. Personally I am stunned. This stuff is just awesome. I have no idea which one is my favourite!

Posted in Uncategorized | Leave a comment