Dec 21 2008

Rotozoomer in Actionscript3.0

One oldschool demoscene effect I still love is the so called Rotozoomer. Rotozoomer by its name rotates and zooms an image in and out. The effect is really stunning and it is well known among oldschool amiga sceners. Reading the very good tutorial about Actionscript’s Transformation Matrix class by senocular.com inspired me to have a try to do a rotozoomer in pure ActionScript3.0.

If you cross-read to senocular’s tutorial and my source code you see how easy the pixel tranformation matrix work to come up with the effect.

The flash movie requires at least Flash Player9.0 - just press on the screenshot to run it. The fantastic “bunny” image was made by the artist called made.

Rotozoom Screenshot

Finally, here is the source code. I tried to comment it as best as I can. Have fun with it.

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.events.MouseEvent;
	import flash.net.*;
 
	/**
	  * Simple rotozoomer in actionscript3.0
	  *
	  * @author benny!weltenkonstrukteur.de
	  */
	public class RotoZoom2 extends Sprite
	{
		// Declaring class constants
		private const ZOOM_MAX:Number 		= 3;
		private const ZOOM_MIN:Number 		= -2.0;
		private const ZOOM_DELTA:Number 	= 0.015;
		private const ROTATE_DELTA:Number	= 0.05;
 
		/// Initialisate private class members
		private var angle:Number = 0, zoom:Number = ZOOM_MIN, isZoomIncreasing:Boolean = true;
		private var logo:Bitmap = null, logoBitmapData:BitmapData;
		private var sw:uint, sh:uint;
 
		// Declare embedded assets
		[Embed(source = "made-bunny.png")]
		private var LogoBitmap:Class;
 
		/**
		 * Constructor
		 */
		public function RotoZoom2()
		{
			init();
			addEventListener("enterFrame", loop);
		}
 
		/**
		 * Initialize needed sprites and bitmaps
		 */
		private function init():void
		{
			// Create logo bitmap and retrieving the bitmapData
			logo = new LogoBitmap();
			logoBitmapData = logo.bitmapData;
 
			// Setting canvas dimensions
			sw = stage.stageWidth;
			sh = stage.stageHeight;
		}
 
		/**
		 * Calcualte roto matrix and draws the scene
		 * @param	ev, onEnter event
		 */
		private function loop(ev:Event):void
		{
			// If we want to zoom in
			if ( isZoomIncreasing )
			{
				// Add increase value to zoom
				zoom = zoom + ZOOM_DELTA;
			}
			else
			{
				// Otherwise decrement value from zoom
				zoom = zoom - ZOOM_DELTA;
			}
 
			// Calculate new rotation angle
			angle = angle + ROTATE_DELTA;
 
			// If angle is greater than 360
			if ( angle > 360 )
			{
				// Reset it to zero
				angle = 0;
			}
 
			// If zoom is higher than maximum value
			if ( zoom > ZOOM_MAX )
			{
				// Change to zoom out
				isZoomIncreasing = false;
				zoom = ZOOM_MAX;
			}
			// If zoom is less than minimum value
			else if ( zoom < ZOOM_MIN )
			{
				// Change to zoom in
				isZoomIncreasing = true;
				zoom = ZOOM_MIN;
			}
 
			// Calculate matrix for rotation an zooming
			var rotoMatrix:Matrix = new Matrix(Math.cos(angle) * zoom, Math.sin(angle), -Math.sin(angle), Math.cos(angle) * zoom, 0, 0);
 
			// Fill scene with bitmap using the rotoMatrix
			graphics.clear();
			graphics.beginBitmapFill(logoBitmapData, rotoMatrix,true, true);
			graphics.drawRect(0, 0, sw, sh);
			graphics.endFill();
 
			// Set it free for gargabe collection
			rotoMatrix = null;
 
		}
	}
 
}