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: