Category Archives: AS3

Playing with Blend Mode

Recently, I tried some BlendMode in AS3. Thanks to them we can reproduce some cool effects of Photshop.
This is a simple script to do that. I thought it’s a nice effect !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package {
 
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.geom.Point;
 
	[SWF(backgroundColor="#000000", frameRate="31", width="600", height="500")]
 
	/**
	 * @author Aymeric
	 */
 
	public class MouseFollower extends Sprite {
 
		private var _container:Sprite;
 
		private var _bData:BitmapData;
		private var _img:Bitmap;
		private var _circle:Shape;
 
		public function MouseFollower() {
 
			_container = new Sprite();
                        _container.visible = false;
			this.addChild(_container);
 
			_bData = new BitmapData(600, 500, true, 0x00FF00);
 
			_img = new Bitmap(_bData);
 
			_circle = new Shape();
 
			this.addChild(_img);
 
			_container.addChild(_circle);
 
			this.addEventListener(Event.ENTER_FRAME, _ef);
		}
 
		private function _ef(evt:Event):void {
 
			_circle.graphics.clear();
			_circle.graphics.beginFill(Math.random()*0xFFFFFF);
			_circle.graphics.drawCircle(0, 0, 10);
			_circle.graphics.endFill();
 
			var diffx:int =	mouseX - _circle.x;
			var diffy:int = mouseY - _circle.y;
 
			_circle.x +=diffx * 0.05;
			_circle.y +=diffy * 0.05;
 
			_bData.draw(_container, null, null, BlendMode.ADD);
			_bData.applyFilter(_bData, _bData.rect, new Point(), new BlurFilter(5, 5, 2));
		}
	}
}

This two lines are important if you want to keep an eye on your CPU usage :
_circle.graphics.clear();
_circle.graphics.endFill();
BlendMode are more than ever CPU’s eater !

Dynamic variable in AS3

An other short practical script to access to dynamic variable into a loop :

var fiole1:Fiole1, fiole2:Fiole2, fiole3:Fiole3, fiole4:Fiole4, fiole5:Fiole5;
for (var i:uint = 1; i < 6; ++i) {
 
	this["fiole" + i].addEventListener(MouseEvent.MOUSE_OVER, _over);
	this["fiole" + i].addEventListener(MouseEvent.MOUSE_OUT, _out);
}

Box2D with the WorldConstructionKit

Before the weekend, I suggest to dig into the Box2D API for Flash with the great WorldConstructionKit.
Box2D is a physical engine wrote in C++ and translated into many languages such as Java, Objective-C, AS3, JavaScript…

For ActionScript3, there are 2 ports : Boris the brave’s port, and the WCK. You can find a performance comparison here made by Allan Bishop.
The WCK is the best thanks to the Alchemy port : it translates the C++ into something which can be understable by Flash. More information here.

The WCK provides a “a toolset / framework for rapidly developing physics based games / websites within the Flash IDE. WCK allows you to layout your 2d worlds / game levels entirely within Flash and have them hook into the physics simulation without writing any code.”

Continue reading Box2D with the WorldConstructionKit

Php’s print_r for as3

Here is really useful class tools for as3 based on php function found on http://dev.base86.com website.

Exemple use :

import com.base86.Tools;
 
var obj:Array = new Array();
obj['a'] = { one: 1, two: 2, three: 3 };
obj['b'] = [ 'one', 'two', [ 'three' ] ];
obj['c'] = new MovieClip();
 
Tools.pr(obj);

The console will display:

(array) {
	[a] => (object) {
		[two] => (number) 2
		[three] => (number) 3
		[one] => (number) 1
	}
	[b] => (array) {
		[0] => (string) one
		[1] => (string) two
		[2] => (array) {
			[0] => (string) three
		}
	}
	[c] => (object) [object MovieClip]
}

And the class now :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.base86 {
	public class Tools {
		/**
		 * An equivalent of PHP's recursive print function print_r, which displays objects and arrays in a way that's readable by humans
		 * @param obj    Object to be printed
		 * @param level  (Optional) Current recursivity level, used for recursive calls
		 * @param output (Optional) The output, used for recursive calls
		 */
		public static function pr(obj:*, level:int = 0, output:String = ''):* {
			if(level == 0) output = '('+ Tools.typeOf(obj) +') {\n';
			else if(level == 10) return output;
 
			var tabs:String = '\t';
			for(var i:int = 0; i < level; i++, tabs += '\t') { }
			for(var child:* in obj) {
				output += tabs +'['+ child +'] => ('+  Tools.typeOf(obj[child]) +') ';
 
				if(Tools.count(obj[child]) == 0) output += obj[child];
 
				var childOutput:String = '';
				if(typeof obj[child] != 'xml') {
					childOutput = Tools.pr(obj[child], level + 1);
				}
				if(childOutput != '') {
					output += '{\n'+ childOutput + tabs +'}';
				}
				output += '\n';
			}
 
			if(level == 0) trace(output +'}\n');
			else return output;
		}
 
		/**
		 * An extended version of the 'typeof' function
		 * @param 	variable
		 * @return	Returns the type of the variable
		 */
		public static function typeOf(variable:*):String {
			if(variable is Array) return 'array';
			else if(variable is Date) return 'date';
			else return typeof variable;
		}
 
		/**
		 * Returns the size of an object
		 * @param obj Object to be counted
		 */
		public static function count(obj:Object):uint {
			if(Tools.typeOf(obj) == 'array') return obj.length;
			else {
				var len:uint = 0;
				for(var item:* in obj) {
					if(item != 'mx_internal_uid') len++;
				}
				return len;
			}
		}
	}
}

Dynamic variable to parse in a XML

A current problem in AS3 with XML : if you want to parse a XML with a dynamic variable as a root, you can’t with a for each statement. It doesn’t recognize the variable.

The XML Format :

<?xml version="1.0" encoding="UTF-8"?>
 
<boite>
 
	<Box name="Box1">
		<lien nom="BENCHMARK">http://www.google.fr</lien>
		<lien nom="FOCUS GROUP">http://www.google.fr</lien>
	</Box>
 
	<Box name="Box2">
		<lien nom="FORMATION">http://www.google.fr</lien>
		<lien nom="COACHING">http://www.google.fr</lien>
	</Box>
 
</boite>

The way which doesn’t work (N.B. in this case the XML is Box1…/Box1 Box2…/Box2:

var myBox:String = "Box1";
for each (var box:XML in myXML.myBox) {
	trace(box);
}

The good way :

private function _xmlLoaded(mEvt:Event):void {
 
	mEvt.target.removeEventListener(Event.COMPLETE, _xmlLoaded);
	_xml = new XML(mEvt.target.data);
 
        _boiteNom = "Box1";
 
	_textes = [];
	_liens = [];
 
	var indexBoite:uint = _getIndexBox(_boiteNom);
	_nbrFiches = _xml.Box[indexBoite].lien.length();
 
	for (var i:uint; i < _nbrFiches; ++i) {
		_textes.push(_xml.Box[indexBoite].lien[i].@nom);
		_liens.push(_xml.Box[indexBoite].lien[i]);
	}
 
	_ajoutFiche();
}
 
private function _getIndexBox($name:String):uint {
 
  	for(var i:uint; i < _xml.Box.length(); ++i) {
   		if(String(_xml.Box[i].@name) == $name)
   			return i; 
   	}
   return 666; // The devil's number, too evil to be real
 }

Testing as3isolib

Hi, folks !

I know my last post was taken a while, the sandwich course is really intensive. However I will try to post more article. I’ve made many experiments since two months that I would like to share : stuff on games engine and datastructure.

For this firts post of 2011 (already !), I will introduce the actionscript isometric library : as3isolib. There are two others actionscript isometric library : TheoWorlds and OpenSpace but they are not free !

We will create an isometric world and add random boxes, if you click on one it will be removed. The result.

The code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package {
 
	import as3isolib.display.IsoView;
	import as3isolib.display.primitive.IsoBox;
	import as3isolib.display.scene.IsoGrid;
	import as3isolib.display.scene.IsoScene;
	import as3isolib.enum.RenderStyleType;
	import as3isolib.geom.IsoMath;
	import as3isolib.geom.Pt;
	import as3isolib.graphics.SolidColorFill;
 
	import eDpLib.events.ProxyEvent;
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	public class Main extends Sprite {
 
		private const _CELL_SIZE:uint = 50;
 
		private var _grid:IsoGrid;
		private var _scene:IsoScene;
		private var _view:IsoView;
 
		private var _box:IsoBox;
		private var i:uint;
 
		private var _timerCreationBox:Timer;
 
		public function Main() {
 
			this.addEventListener(Event.ADDED_TO_STAGE, _init);
		}
 
		private function _init(evt:Event):void {
 
			this.removeEventListener(Event.ADDED_TO_STAGE, _init);
 
			_grid = new IsoGrid();
			_grid.setGridSize(10, 10, 1);
			_grid.showOrigin = false;
			_grid.cellSize = _CELL_SIZE;
 
			_scene = new IsoScene();
			_scene.hostContainer = this;
			_scene.addChild(_grid);
 
			_view = new IsoView();
			_view.setSize(800, 600);
			_view.centerOnPt(new Pt(200, 200, 0));
			_view.addScene(_scene);
			this.addChild(_view);
 
			_timerCreationBox = new Timer(300, 0);
			_timerCreationBox.addEventListener(TimerEvent.TIMER, _createNewBox);
			_timerCreationBox.start();
 
			this.addEventListener(Event.ENTER_FRAME, _ef);
		}
 
		private function _createNewBox(tEvt:TimerEvent):void {
 
			_box = new IsoBox();
			_box.styleType = RenderStyleType.SHADED;
			var couleur:uint = Math.random() * 0xFFFFFF;
			var alpha:Number = Math.random();
			_box.fills = [new SolidColorFill(couleur, alpha), new SolidColorFill(couleur, alpha), new SolidColorFill(couleur, alpha), new SolidColorFill(couleur, alpha), new SolidColorFill(couleur, alpha), new SolidColorFill(couleur, alpha)];
 
			_box.setSize(_CELL_SIZE, _CELL_SIZE, _CELL_SIZE);
			_box.moveTo(_CELL_SIZE * Math.floor(Math.random() * 10), _CELL_SIZE * Math.floor(Math.random() * 10), 0);
 
			_box.id = "box" + i;
			++i;
 
			_box.addEventListener(MouseEvent.CLICK, _deleteBox);
			_scene.addChild(_box);
		}
 
		private function _deleteBox(mEvt:ProxyEvent):void {
 
			mEvt.proxyTarget.removeEventListener(MouseEvent.CLICK, _deleteBox);
			_scene.removeChildByID(mEvt.target.id);
		}
 
		private function _ef(evt:Event):void {
			_scene.render();
		}
	}
 
}

The _scene.render() function is really important : it updates the scene of all your graphical change !

Later it will be a post on Box2d, stay tuned !

Resize an image and make a thumb !

Hey !
After two months without any article, I’m ready to start again activity on this blog ! For sure, it’s the start of the new school year !

So today, a little script really useful to make a thumb in ActionScript 3 !
EDIT : deleted my previous script, this one coming from Cult Creative is awesome :

/**
* fitImage
* @ARG_object   the display object to work with
* @ARG_width    width of the box to fit the image into
* @ARG_height   height of the box to fit the image into
* @ARG_center   should it offset to center the result in the box
* @ARG_fillBox  should it fill the box, may crop the image (true), or fit the whole image within the bounds (false)
**/
 
private function fitImageProportionally( ARG_object:DisplayObject, ARG_width:Number, ARG_height:Number, ARG_center:Boolean = true, ARG_fillBox:Boolean = true ):Bitmap {
 
    var tempW:Number = ARG_object.width;
    var tempH:Number = ARG_object.height;
 
    ARG_object.width = ARG_width;
    ARG_object.height = ARG_height;
 
    var scale:Number = (ARG_fillBox) ? Math.max(ARG_object.scaleX, ARG_object.scaleY) : Math.min(ARG_object.scaleX, ARG_object.scaleY);
 
    ARG_object.width = tempW;
    ARG_object.height = tempH;
 
    var scaleBmpd:BitmapData = new BitmapData(ARG_object.width * scale, ARG_object.height * scale);
    var scaledBitmap:Bitmap = new Bitmap(scaleBmpd, PixelSnapping.ALWAYS, true);
    var scaleMatrix:Matrix = new Matrix();
    scaleMatrix.scale(scale, scale);
    scaleBmpd.draw( ARG_object, scaleMatrix );
 
    if (scaledBitmap.width > ARG_width || scaledBitmap.height > ARG_height) {
 
        var cropMatrix:Matrix = new Matrix();
        var cropArea:Rectangle = new Rectangle(0, 0, ARG_width, ARG_height);
 
        var croppedBmpd:BitmapData = new BitmapData(ARG_width, ARG_height);
        var croppedBitmap:Bitmap = new Bitmap(croppedBmpd, PixelSnapping.ALWAYS, true);
 
        if (ARG_center) {
            var offsetX:Number = Math.abs((ARG_width -scaleBmpd.width) / 2);
            var offsetY:Number = Math.abs((ARG_height - scaleBmpd.height) / 2);
 
            cropMatrix.translate(-offsetX, -offsetY);
        }
 
        croppedBmpd.draw( scaledBitmap, cropMatrix, null, null, cropArea, true );
        return croppedBitmap;
 
    } else {
        return scaledBitmap;
    }
 
}

An other method coming from Thibault Imbert !

package {
 
	import flash.display.BitmapData;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
 
	/**
	 * @author Maxime Cousinou
	 */
	public class BitmapManager {
 
		public static function reduceBitmapData(bmp:BitmapData, ratio:Number, transparent:Boolean = true):BitmapData {
 
			var bmpData:BitmapData = new BitmapData(Math.round(bmp.width * ratio), Math.round(bmp.height * ratio), transparent, 0x00FFFFFF);
			var scaleMatrix:Matrix = new Matrix(bmpData.width / bmp.width, 0, 0, bmpData.height / bmp.height, 0, 0);
			bmpData.draw(bmp, scaleMatrix);
 
			return bmpData;
		}
 
		public static function resizeBitmapData(bmp:BitmapData, ratio:Number, transparent:Boolean = true):BitmapData {
 
			var bmpData:BitmapData = new BitmapData(Math.round(bmp.width * ratio), Math.round(bmp.height * ratio), transparent, 0x00FFFFFF);
			var scaleMatrix:Matrix = new Matrix(bmpData.width / bmp.width, 0, 0, bmpData.height / bmp.height, 0, 0);
			var colorTransform:ColorTransform = new ColorTransform();
			bmpData.draw(bmp, scaleMatrix, colorTransform, null, null, true);
 
			return bmpData;
		}
 
		public static function resampleBitmapData(bmp:BitmapData, ratio:Number, transparent:Boolean = true):BitmapData {
 
			if (ratio >= 1) {
				return BitmapManager.resizeBitmapData(bmp, ratio, transparent);
			} else {
				var bmpData:BitmapData = bmp.clone();
				var appliedRatio:Number = 1;
 
				do {
					if (ratio < 0.5 * appliedRatio) {
						bmpData = BitmapManager.resizeBitmapData(bmpData, 0.5, transparent);
						appliedRatio = 0.5 * appliedRatio;
					} else {
						bmpData = BitmapManager.resizeBitmapData(bmpData, ratio / appliedRatio, transparent);
						appliedRatio = ratio;
					}
				} while (appliedRatio != ratio);
 
				return bmpData;
			}
		}
	}
}

The final Countdown

Hey there ! This is a little script to made a simple countdown on 12/12/2012 at 12:12:12. You know, the end of the world 😉
The result.

And the code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
 
	/**
	 * @author Aymeric
	 */
	public class Countdown extends Sprite {
 
		private var target:Date;
		private var now:Date;
		private var currentTime:Number;
		private var targetTime:Number;
		private var time:TextField;
		private var format:TextFormat; 
 
		public function Countdown() {
 
			target = new Date(2012, 11, 12, 12, 12, 12); // january = 0 -> december = 11
 
			time = new TextField();
			format = new TextFormat("Arial", 30);
			time.textColor = 0xFF0000;
			time.x = stage.stageWidth/2 - 100;
			time.y = stage.stageHeight/2 - 50;
			time.embedFonts = true;
 
			addChild(time);
 
			addEventListener(Event.ENTER_FRAME, refresh);
		}
 
		private function refresh(e:Event):void {
 
			now = new Date();
			currentTime = now.getTime();
			targetTime = target.getTime();
 
			var nbrSeconds:Number = (targetTime - currentTime)/1000;
			var seconds:Number = Math.floor(nbrSeconds%60);
			var minutes:Number = Math.floor(nbrSeconds/60%60);
			var hours:Number = Math.floor(nbrSeconds/3600%24);
			var days:Number = Math.floor(nbrSeconds/3600/24);
 
			var secondText:String;
			var minuteText:String;
			var hourText:String;
 
			if (seconds < 10) {
				secondText = "0" + seconds;
			} else {
				secondText = seconds.toString();
			}
 
			if (minutes < 10) {
				minuteText = "0" + minutes;
			} else {
				minuteText = minutes.toString();
			}
 
			if (hours < 10) {
				hourText = "0" + hours;
			} else {
				hourText = hours.toString();
			}
 
			time.text = days.toString() + " : " + hourText + " : " + minuteText + " : " + secondText;
			time.autoSize = TextFieldAutoSize.LEFT;
			time.setTextFormat(format);
		}
	}
}

I used an EnterFrame to refresh the countdown, but I have hesitated with a Timer which is called each seconds. I think the EnterFrame is better because the Timer depends of user’s computer. If you can highlight me, do not hesitate !