Actionscript 3: part 3!
The evolution of my ActionScript 3 project has continued. Here is the current swf (remember you will need the Flash Player 8.5 to view it):
As you can see, it’s a whole heap more exciting now… It still creates the mosaic tiles from the original jpeg in the same way as the previous examples but now each tile also listens for an EventType.ENTER_FRAME event. This is basically the same as having a MovieClip.onEnterFrame event handler in older versions of Flash. Each tile is repulsed by the mouse using Barslund Repulsion (thanks to a script I grabbed from Solid Ether).
Here is the code for the example in it’s entirety:
{
import flash.display.Sprite;
import flash.display.DisplayObjectContainer;
import flash.display.Bitmap;
import flash.util.trace;
import flash.display.Loader;
import flash.display.StageScaleMode;
import flash.display.BitmapData;
import flash.net.URLRequest;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.filters.BlurFilter;
import flash.events.Event;
import flash.events.EventType;
[SWF(width="500", height="400", backgroundColor="#869CA7")]
public class Mosaic2 extends Sprite
{
private var picLoader:Loader;
public function Mosaic2()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
picLoader = new Loader();
picLoader.addEventListener(EventType.COMPLETE, onPicLoaded);
picLoader.load(new URLRequest("IMG_6032.jpg"));
}
private function onPicLoaded(event:Event):Void
{
var mt:MosaicTray = MosaicTray(this.addChild(new MosaicTray(picLoader, picLoader.content)));
}
}
private class MosaicTray extends Sprite {
private var TILE_SIZE:uint = 8;
public function MosaicTray(picSprite:DisplayObjectContainer, bitmap:Bitmap)
{
this.x = 150;
this.y = 65;
var sourceBitmapData:BitmapData = bitmap.bitmapData;
var blurFilter:BlurFilter = new BlurFilter(255, 255, 3);
var halfTile:uint = Math.round(TILE_SIZE/2);
var p:Point = new Point();
for (var i:uint=0; i<picSprite.width; i+=TILE_SIZE) {
for (var j:uint=0; j<picSprite.height; j+=TILE_SIZE) {
var bd:BitmapData = new BitmapData(TILE_SIZE, TILE_SIZE, false);
var r:Rectangle = new Rectangle(i, j, TILE_SIZE, TILE_SIZE);
// blur the bitmap so we get a more acurate "average" for
// each tile
bd.applyFilter(sourceBitmapData, r, p, blurFilter);
var col:uint = bd.getPixel(halfTile, halfTile);
var mt:MosaicTile = new MosaicTile(i, j, col, TILE_SIZE);
this.addChild(mt);
}
}
}
}
private class MosaicTile extends Sprite {
private var xHome:uint;
private var yHome:uint;
private var force:uint = 300; // experiment with different values
public function MosaicTile(x:uint, y:uint, colour:uint, size:uint)
{
this.x = xHome = x;
this.y = yHome = y;
graphics.beginFill(colour);
graphics.drawRect(0, 0, size-1, size-1);
graphics.endFill();
this.addEventListener(EventType.ENTER_FRAME, onEnterFrame);
}
public function onEnterFrame(evt:Event)
{
// after trying to come up with this code myself and failing I found an
// implementation of "Barslund Repulsion" here (and ever so slightly
// adapted it to AS3):
// http://www.solidether.com/luminance/examples/barslundRepulsion.html
var xDif:Number = parent.mouseX - x;
var yDif:Number = parent.mouseY - y;
var distance:Number = Math.sqrt(xDif*xDif+yDif*yDif);
var tempX:Number = x - (force/distance)*(xDif/distance);
var tempY:Number = y - (force/distance)*(yDif/distance);
x = (xHome - x)/2+tempX;
y = (yHome - y)/2+tempY;
}
}
}
Fairly simple really… And if anything it seems way more efficient and responsive than my attempt at bounce tweening in the last example…
Comments or suggestions for improvements appreciated :)

— Jon Bradley Oct 31, 15:47 #
Hard to explain but try it on the code above and you might see what I mean (or maybe you will see what I mean without cacheAsBitmap if your computer is faster than mine!).
Anyway, amazing the difference it made and would definitely recommend it in situations where you were rendering bigger images than this.
Thanks for the feedback :)
— Kelvin Oct 31, 22:29 #