Tag #Actionscript

Flash + Interner Explorer + SSL = #2032: Stream Error

Problem nie nowy, ale wciąż spotykany. Otóż próba komunikacji aplikacji flashowej z serwerem w bezpiecznym połączeniu HTTPS, w przeglądarce Internet Explorer 6 oraz 7 ma spore szanse zakończyć się niepowodzeniem:

#2032: Stream Error. URL: https://www.serwer.pl/internal_api.php

Tego typu błąd otrzymamy w aplikacji napisanej w ActionScript3. W starszej wersji 2 języka problem może być jeszcze bardziej irytujący, gdyż nie otrzymamy żadnego widocznego komunikatu o błędzie, ale nasz program też nie będzie działać.

Błąd występuje niezależnie od wersji flash playera. Odporny na ten przypadek jest Internet Explorer dopiero w wersji 8. Lekarstwem na bolączkę jest wysłanie w zasadzie dowolnej nieprawidłowej wartości dla nagłówka Pragma, np.:

header (”Pragma: internet-explorer-is-my-life”);

Co ciekawe, wysłanie nagłówka “Pragma: no-cache”, nie dosyć że powoduje opisany wyżej problem, to wcale nie zapobiega cachowaniu zawartości podczas połączenia bez szyfrowania SSL.

Zobacz także:

Nota techniczna Adobe
Powiązany błąd na stronie Microsoftu

Tetris – zagrajmy w to jeszcze raz

Ten rok rozpoczęliśmy od zaprogramowania remaków kilku klasycznych gier. Tetris – to mój faworyt :)

Aby zagrać kliknij w obrazek.

Maziagenerator

W toku jakże intensywnych prac nad efektami specjalnymi we flashu, przez przypadek stworzyłem maziageneratora – program, który także tobie pozwoli poczuć się prawdziwym impresjonistą.

Tak się kończą zabawy z Bitmap.draw, BlendMode.OVERLAY i krzywymi lissajou:

(kliknij i zacznij rysować)

Prosto z Commodore 64: tunel

Kolejny sympatyczny efekt, wykorzystywany bardzo często w produkcjach demosceny to tunel. W milionach różnych wersji, wyewoluował od całkiem prostej realizacji rysowanych okręgów do hiper-super-triple teksturowanego tunelu z dynamicznym oświetleniem, cieniami i bajerami.

Realizacja tego efektu we flashu jest jak najbardziej możliwa. Sprawa wygląda prosto:

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
 
	[SWF(width="500", height="500", backgroundColor="0x000000")]
	public class TunnelEfect extends Sprite
	{
		private var w:int = 250;
		private var h:int = 250;
		private var texWidth:int = 256;
		private var texHeight:int = 256;
 
		private var texture:Array = new Array(texWidth);
		private var distanceTable:Array = new Array(w * 2);
		private var angleTable:Array = new Array(w * 2);
 
		private var animationShift:Number = 0;
 
		private var bitmap:BitmapData = new BitmapData(w * 2, h * 2, false, 0x000000);
 
		public function TunnelEfect()
		{
                        var angle:int, distance:int, ratio:Number = 32;
 
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
			this.stage.frameRate = 20;
			this.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
 
			this.addChild(new Bitmap(bitmap));			
 
			for(var x:int = 0; x < texWidth; x++)
			{
				texture[x] = new Array(texHeight);
 
				for(var y:int = 0; y < texHeight; y++)
				{
					texture[x][y] = ((x) ^ (y)) * 256;
				}			
			}			 
 
			for(x = 0; x < w * 2; x++)
			{
				distanceTable[x] = new Array(h * 2);
				angleTable[x] = new Array(h * 2);
 
			    for(y = 0; y < h * 2; y++)
			    {
			    	distance = (ratio * texHeight / Math.sqrt(((x - w) * (x - w) + (y - h) * (y - h)))) % texHeight;
			        angle = Math.abs(0.5 * texWidth * Math.atan2((y - h), (x - w)) / 3.1416);
 
			        distanceTable[x][y] = distance;
			        angleTable[x][y] = angle;
			    }			 
			}
		}
 
		private function draw():void
		{
			var shiftX:int, shiftY:int, shiftLookX:int, shiftLookY:int, color:Number;
 
			shiftX = (texWidth * 1.0 * animationShift);
			shiftY = (texHeight * 0.25 * animationShift);  
 
			shiftLookX = w / 2 + (w / 2 * Math.cos(animationShift));
	        shiftLookY = h / 2 + (h / 2 * Math.sin(animationShift * 2.0));	
 
	        for(var x:int = 0; x < w; x++)
	        {
		        for(var y:int = 0; y < h; y++)
		        {
				    color = texture[Math.abs(distanceTable[x + shiftLookX][y + shiftLookY] + shiftX)  % texWidth][Math.abs(angleTable[x + shiftLookX][y + shiftLookY] + shiftY) % texHeight];
		        	bitmap.setPixel(x * 2, y * 2, color);
		        }			
			}
		}
 
		private function onEnterFrame(e:Event):void
		{
			draw();	
			animationShift += 0.05;
		}
 
	}
}

A oto i gotowy tunel:

Prosto z Commodore 64: efekt plazmy

Od pewnego czasu wracam wspomnieniami do czasów demosceny, a od kilku dni odświeżam stare umiejętności i przekładam to, co kiedyś robiło się w assemblerze, na Flasha i Actionscript. Jednym z wynalazków koderów z demosceny, był efekt plazmy.

Opisowo efekt ten polegał na uzyskaniu interesujących graficznie animacji “rozlewających” się kolorów. Ponieważ jednak ówczesne komputery były zbyt wolne na obliczanie co ramke wartości każdego pixela na ekranie, koderzy użyli jednej ze swoich sztuczek: tylko raz na starcie rysowało się obraz pixeli na ekranie, a potem podmieniano jedynie paletę kolorów używaną przez układ graficzny. W ten sposób nawet ZX-Spectrum dawało radę:

W takim razie, skoro ZX-Spectrum ze swoim Zilogiem Z80 dawało radę, jak poradzi sobie flash na procesorach taktowanych gigaherzami? :) Nie możemy niestety operować bezpośrednio na palecie ( zabawa z ColorTransform również odpada), więc jednak musimy za każdym razem odrysować wszystkie pixele na ekranie. Spróbujmy:

package {
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.events.Event;
	import flash.display.BitmapData;
 
	[SWF(width="300", height="300", backgroundColor="0x000000")]
	public class PlasmaEffect extends Sprite
	{
		private var w:int = 150;
		private var h:int = 150;
		private var colors:Array = new Array();
		private var plasma:Array = [w];
		private var paletteShift:int;
 
		public function PlasmaEffect()
		{
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
			this.stage.frameRate = 10;
			this.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
 
			generatePalette();
			generatePlasma();
		}
 
		private function draw():void
		{
			this.graphics.clear();
 
	        for(var x:int = 0; x < w; x++)
	        for(var y:int = 0; y < h; y++)
	        {
	            this.graphics.lineStyle(1, colors[(plasma[x][y] + paletteShift) % 256]);
	            this.graphics.moveTo(x * 2, y * 2);
	            this.graphics.lineTo(x * 2, y * 2 + 1);  
	        }			
		}
 
 
		private function generatePlasma():void
		{
			var colorIndex:int;
 
		    for(var x:int = 0; x < w; x++)
		    {
		    	plasma[x] = [h];
 
			    for(var y:int = 0; y < h; y++)
			    {		    	
			        colorIndex =
			        (
			              128.0 + (128.0 * Math.sin(x / 16.0))
			            + 128.0 + (128.0 * Math.sin(y / 32.0))
			            + 128.0 + (128.0 * Math.sin(Math.sqrt(((x - w / 2.0)* (x - w / 2.0) + (y - h / 2.0) * (y - h / 2.0))) / 8.0))
			            + 128.0 + (128.0 * Math.sin(Math.sqrt((x * x + y * y)) / 8.0))
			        ) / 4;			        
 
			        plasma[x][y] = colorIndex;       
			    }			
		    }
		}
 
		private function generatePalette():void
		{
			var r:int;
			var g:int;
			var b:int;
 
			for(var x:int = 0; x < 256; x++)
			{
			    r = 128.0 + 128 * Math.sin(3.1415 * x / 16.0 );
			    g = 128.0 + 128 * Math.sin(3.1415 * x / 128.0 );
			    b = 0;
			    colors.push(r * 256 * 256 + g * 256 + b);
			} 			
		}
 
		private function onEnterFrame(e:Event):void
		{
			draw();	
			paletteShift += 1;
		}
	}
}

No cóż, na moim, całkiem współczesnym komputerze nie daje rady – ledwo 5 klatek na sekundę, i macierz pixeli o rozmiarach 150×150. Winowajcą jest metoda lineTo – zbyt wolna jak na nasze potrzeby.
Ale, drobna zmiana kodu, zastąpienie rysowanie poprzez graphics.lineTo na bezpośrednie ustawianie pixelów bitmapy:

package {
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.events.Event;
 
	import flash.display.BitmapData;
	import flash.display.Bitmap;
 
	[SWF(width="300", height="300", backgroundColor="0x000000")]
	public class PlasmaEffect extends Sprite
	{
		private var w:int = 300;
		private var h:int = 300;
		private var colors:Array = new Array();
		private var plasma:Array = [w];
		private var paletteShift:int;
 
		private var bitmap:BitmapData = new BitmapData(w, h, false);
 
		public function PlasmaEffect()
		{
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
			this.stage.frameRate = 20;
			this.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
 
			this.addChild(new Bitmap(bitmap));
 
			generatePalette();
			generatePlasma();
		}
 
		private function draw():void
		{
			this.graphics.clear();
 
	        for(var x:int = 0; x < w; x++)
	        for(var y:int = 0; y < h; y++)
	        {
	        	bitmap.setPixel(x, y, colors[(plasma[x][y] + paletteShift) % 256]);
	            //this.graphics.lineStyle(1, colors[(plasma[x][y] + paletteShift) % 256]);
	            //this.graphics.moveTo(x * 2, y * 2);
	            //this.graphics.lineTo(x * 2, y * 2 + 1);  
	        }			
		}
 
 
		private function generatePlasma():void
		{
			var colorIndex:int;
 
		    for(var x:int = 0; x < w; x++)
		    {
		    	plasma[x] = [h];
 
			    for(var y:int = 0; y < h; y++)
			    {		    	
			        colorIndex =
			        (
			              128.0 + (128.0 * Math.sin(x / 16.0))
			            + 128.0 + (128.0 * Math.sin(y / 32.0))
			            + 128.0 + (128.0 * Math.sin(Math.sqrt(((x - w / 2.0)* (x - w / 2.0) + (y - h / 2.0) * (y - h / 2.0))) / 8.0))
			            + 128.0 + (128.0 * Math.sin(Math.sqrt((x * x + y * y)) / 8.0))
			        ) / 4;			        
 
			        plasma[x][y] = colorIndex;       
			    }			
		    }
		}
 
		private function generatePalette():void
		{
			var r:int;
			var g:int;
			var b:int;
 
			for(var x:int = 0; x < 256; x++)
			{
			    r = 128.0 + 128 * Math.sin(3.1415 * x / 16.0 );
			    g = 128.0 + 128 * Math.sin(3.1415 * x / 128.0 );
			    b = 0;
			    colors.push(r * 256 * 256 + g * 256 + b);
			} 			
		}
 
		private function onEnterFrame(e:Event):void
		{
			draw();	
			paletteShift += 1;
		}
	}
}

i… sukces! :) Tym razem macierz 300×300 i 20 klatek na sekundę:

daje radę :)

Kalkulator położenia słońca

Do większego projektu, potrzebowałem napisać program obliczający położenie (wysokość i azymut) słońca na nieboskłonie. O tym “większym” projekcie mam nadzieję, że napiszę niebawem, a na razie oddaję do dyspozycji gotowy kalkulator położenia słońca – parametry wejściowe to lokalizacja, data i godzina; wynik – azymut i wysokość. Program napisany w Adobe Flex.

FemtoPlayer – mini free mp3 flash player

Kilka dni temu szukałem malutkiego mp3 playera, który wyświetlał by jedynie ikonkę z przyciskiem play i odgrywał wskazany dźwięk mp3. Poszukiwania w googlu dały kilka rezultatów, ale każdy z nich albo był “za bardzo”, albo miał złą licencję. Zamiast tracić dalej czas napisałem te kilkanaście linijek kodu i stworzyłem swój własny FemtoPlayer – Femto to brzmi dumnie ;)

Parametry:

file = pathToMP3 //ścieżka do pliku mp3
autoplay = true|false //czy automatycznie odgrywać dźwięk po wczytaniu

Przykład użycia:

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="20" height="25" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="FlashVars" value="file=test.mp3&amp;autoplay=true" /><param name="src" value="FemtoPlayer.swf" /><param name="wmode" value="transparent" /><param name="flashvars" value="file=test.mp3&amp;autoplay=true" /><embed type="application/x-shockwave-flash" width="20" height="25" src="FemtoPlayer.swf" wmode="transparent" flashvars="file=test.mp3&amp;autoplay=true"></embed></object>

SWF do pobrania: download

getURL w ActionScript 3

Dobrze znanej z ActionScript2 metody getURL nie znajdziemy w wersji 3 języka. Zamiast niej możemy posłużyć się metodą

flash.net.navigateToURL(request:URLRequest, window:String):void

Rzucanie cieni w Papervision3D

Andy Zupko, współautor Papervision3D, napisał klasę dzięki której dostajemy możliwość rzucania cieni przez dowolne obiekty na naszej scenie 3D. Muszę przyznać, że działa to znakomicie – oraz dużo szybciej od pierwszej wersji, którą zaprezentował w ubiegłym roku. Klasa ShadowCaster nie została na razie dodana do pakietu z Papervision3D, ale można pobrać jej źródło bezpośrednio ze strony Andiego – tam też znajdziecie demo i przykład wykorzystania.

Wywoływanie metod pomiędzy plikami SWF

Problem: Plik swf utworzony w actionscript2 będzie osadzony w innym pliku swf utworzonym w actionscript3. W jaki sposób z jednego pliku swf wywołać metodę w drugim?

Rozwiązaniem jest użycie klasy LocalConnection. Oto przykładowy kod:

embeded.swf (actionscript 2):

on(release) {
	var localConnection:LocalConnection = new LocalConnection();
	localConnection.send("holderConnection", "myMethod");
}

holder.swf (actionscript 3):

import flash.net.LocalConnection;
 
public class Holder
{
    public function Holder()
    {
        var localConnection:LocalConnection = new LocalConnection();
	localConnection.client = this;
	localConnection.connect("holderConnection");
    }
 
    public function myMethod():void
    {
        trace('metoda myMethod została wywołana');
    }
}

Należy zwrócić uwagę, aby metody które chcemy wywołać były zdefiniowane jako metody publiczne.

Copyright © Kubiczek devblog
I'm lovin' it ;)

Built on Notes Blog Core
Powered by WordPress