Archive for the 'Flash AS 3.0' Category

Tabs and Linefeeds (Newlines) in XML driven TextFields

Man Flash can be annoying sometimes. So I’m showing some settings as a list, like
Item: value1
Item Two: value2
Item Three: value3

And the client asks if we can align the values vertically, and thinking like a programmer who likes to keep his code clean I’m thinking «Sure, that shouldn’t be a problem, I’ll just add some \t‘s to the XML file and we should be all set,» but all that comes out is, “Sure, should only take a few minutes to add.”

So I add some \t‘s to the XML and what does flash do with them, it prints out all literal backslashes and ts.

SO then what? Well I was being lazy and specifying xml.node not xml.node.text() to get the text values. Switching it does nothing. So then I start tracing things and looking around the Goog. Finally it becomes apparent that Flash is urlencoding the XML text in the background when processing it, and when it urldecodes it, some things are kept that shouldn’t be, like all escaped string characters that would normally not print.

Oh yeah, condenseWhite was false.

So I start with just doing a simple replace(/\\t/g, “!!!!”) to find out if I can even find the damn things, and I get no exclamation marks… or dirty words. Then a forum entry that was so buried I haven’t even found it again to link to, suggested using unescape(xml.node.text()) for a close, but ultimately unrelated problem.

To make a long story short here’s the solution:

?View Code ACTIONSCRIPT
1
2
3
	var tabs:RegExp = /\\t/g;
	var newlines:RegExp = /\\n/g;
	txt.htmlText = unescape(wagerText).replace(tabs, "\t").replace(newlines, "\n");

Go figure right?

As always if anyone has a better solution I’m all ears, or at least all comment-reading… eventually.

External Interface Callbacks with Jquery

So first off, NEVER use this most lazy of hacks to reference the flash object when calling a method in a flash file:

?View Code JAVASCRIPT
1
2
3
4
// some code
function test() {
	flashID.ner("hello"); // BAAAAAAD!
}

For some reason it works… Some of the time. On Safari when testing running from Flex. On my Mac.

I was being lazy and not really thinking back to how things work in Javascript at the time, then having recently started using Jquery, I tried:

?View Code JAVASCRIPT
1
2
3
4
5
// some code
function test() {
	var flashMovie = $('#flashID');
	flashMovie.ner("hello"); // ALSO BAAAAAAD!
}

Also doesn’t work, for some reason Jquery removes the methods associated with the embed tag that is written, and replaces them with only the Jquery methods. So in order for this to work the code needs to be simply:

?View Code JAVASCRIPT
1
2
3
4
function test() {
	var flashMovie = document.getElementByID("flashID");
	flashMovie.ner("hello"); // FINALLY! It worked.
}

Box2D Shortcuts (Round 1)

Since leaving Hunt & Gather, I’ve been (besides relishing the peace and quiet a bit) playing around with some of those Flash libraries I hadn’t had time for. Most tantalizing of which is the Box2D library. I’d attempted to use it for this auto layout class for LDa Architects, but because of time constraints ended up settling for APE which as you can see is a bit out of date at this point. Anyway APE is fine if the number of bodies is small and you only need very basic simulation capabilities (boxes don’t rotate unless they are attached to 2 or more wheels for instance…), but once you wanna do more advanced things, like robots or buoyancy you’ll need a faster more complete engine.

Box2D seems to be the fastest and most current option out there, but it’s got kind of a funky API due in part to being a fairly direct port from C++. The complicated setup is in fact what had kept me from using it for so long, but some better documentation and turorial files available on the Box2D Wiki is making getting started easier. And to make things even simpler to play with, I’m creating a series of wrapper classes that reduce the amount of code needed to get things started.

World.world

?View Code ACTIONSCRIPT
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
package com.paperclipped.physics
{
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
 
	import flash.display.Sprite;
 
	/**
	 * This is a container class to make the creation of Box2D World simpler.
	 * Box2D r47 or greater required.
	 * (c) 2009 Collin Reisdorf MIT License
	 * 
	 * @author Collin Reisodrf
	 */	
	public class World
	{
//-----------------------------------------Variables-----------------------------------------//
		private var _scale:Number;
		private var _world:b2World;
//-------------------------------------------------------------------------------------------//
 
//------------------------------------------Getters------------------------------------------//
		/**
		 * @return Scale set by the user when the world is constructed.
		 */				
		public function get scale():Number		{ return _scale;	}
		/**
		 * @return The world object made by the constructor.
		 */		
		public function get world():b2World		{ return _world;	}
//-------------------------------------------------------------------------------------------//
 
//----------------------------------------Constructor----------------------------------------//		
		public function World(width:uint, height:uint, debugSprite:Sprite=null, showCenterOfMass:Boolean=false, gravity:b2Vec2=null, scale:Number=30, padding:uint=1000, doSleep:Boolean=true)
		{
			var worldAABB:b2AABB = new b2AABB();
				worldAABB.lowerBound.Set(-padding, -padding);
				worldAABB.upperBound.Set(width+padding, width+padding);
 
			gravity = (gravity)? gravity:new b2Vec2(0, 10.0);
			_world = new b2World(worldAABB, gravity, doSleep);
 
			if(debugSprite)
			{
				var	debugDraw:b2DebugDraw = new b2DebugDraw();
					debugDraw.SetSprite(debugSprite);
					debugDraw.SetDrawScale(scale);
					debugDraw.SetFillAlpha(0.3);
					debugDraw.SetLineThickness(1.0);
					debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | uint((showCenterOfMass)? b2DebugDraw.e_centerOfMassBit:0));
				_world.SetDebugDraw(debugDraw);
			}
		}
//-------------------------------------------------------------------------------------------//
 
//--------------------------------------Private Methods--------------------------------------//
//-------------------------------------------------------------------------------------------//
 
//--------------------------------------Public  Methods--------------------------------------//
//-------------------------------------------------------------------------------------------//
	}
}

Chain

?View Code ACTIONSCRIPT
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.paperclipped.physics
{
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.Joints.b2Joint;
	import Box2D.Dynamics.Joints.b2RevoluteJointDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2World;
 
	/**
	 * This is a container class to make the creation of a chain simpler
	 * Box2D r47 or greater required.
	 * (c) 2009 Collin Reisdorf MIT License
	 * 
	 * @author Collin Reisodrf
	 */	
	public class Chain
	{
//-----------------------------------------Variables-----------------------------------------//
		public static const HORIZONTAL:String = 'h';
		public static const VERTICAL:String = 'v'; // not supported yet
 
		private var _bodies:Array;
		private var _joints:Array;
//		private var _parent:
		private var _world:b2World;
//-------------------------------------------------------------------------------------------//
 
//------------------------------------------Getters------------------------------------------//
		public function get bodies():Array 	{ return _bodies;								}
		public function get end():b2Body 	{ return _bodies[_bodies.length-1] as b2Body;	}
		public function get joints():Array	{ return _joints;								}
		public function get start():b2Body	{ return _bodies[0] as b2Body;					}
//-------------------------------------------------------------------------------------------//
 
//------------------------------------------Setters------------------------------------------//
//-------------------------------------------------------------------------------------------//
 
//----------------------------------------Constructor----------------------------------------//
		public function Chain(world:b2World, numLinks:uint=3, anchorX:int=0, anchorY:int=0, direction:String="h", swingLimit:uint=0, /*parent=null,*/ scale:uint=30)
		{
			_world = world;
			_bodies = new Array();
			_joints = new Array();
//			_parent = parent; // not sure what/how to attach this to yet...
 
			var ground:b2Body = world.GetGroundBody();
			var i:int;
			var anchor:b2Vec2 = new b2Vec2();
			var body:b2Body;
			var joint:b2Joint;
 
			var sd:b2PolygonDef = new b2PolygonDef();
			sd.SetAsBox(24 / scale, 5 / scale);
			sd.density = 100.0;
			sd.friction = 0.8;
 
			var bd:b2BodyDef = new b2BodyDef();
 
			var jd:b2RevoluteJointDef = new b2RevoluteJointDef();
			if(swingLimit > 0)
			{
				jd.lowerAngle = -swingLimit / (180/Math.PI);
				jd.upperAngle = swingLimit / (180/Math.PI);
				jd.enableLimit = true;
			}else
			{
				jd.enableLimit = false;
			}
 
			var prevBody:b2Body = ground;
			for (i = 0; i < 3; ++i)
			{
//				if(i == 0)
//				{
//				trace("enabled motor damnit");
//					jd.enableMotor = true;
//					jd.motorSpeed = 1;
//					jd.maxMotorTorque = 100;
//				}else
//				{
//					jd.enableMotor = false;
//
//				}
 
				bd.position.Set((anchorX + 22 + 44 * i) / scale, anchorY / scale);
				body = world.CreateBody(bd);
				body.CreateShape(sd);
				body.SetMassFromShapes();
 
				anchor.Set((anchorX + 44 * i) / scale, anchorY / scale);
				jd.Initialize(prevBody, body, anchor);
				joint = world.CreateJoint(jd);
 
				prevBody = body;
				_bodies.push(body);
				_joints.push(joint);
			}
		}
//-------------------------------------------------------------------------------------------//
 
//--------------------------------------Private Methods--------------------------------------//
//-------------------------------------------------------------------------------------------//
 
//--------------------------------------Public  Methods--------------------------------------//
//-------------------------------------------------------------------------------------------//
	}
}

Keep an eye out for more, I’m working on robot leg linkages next. And also trying to get a new job 😉

SWFAddress, if You Aren’t Using it for All Your Flash, Start to

We’ve been using SWFAddress for a while now, and while I was cleaning old project files out of Flex I came across my first Flex Test using it. It’s simple, and in fact, SWFAddress has been improved a bunch since this test was made (mostly involving SEO, and fallback links + Google Analytics). Now we’re using it for running our entire navigation schemes for all Flash sites, mini-sites, components, and even in our pitches.

Check out my example (click anywhere to move the box, then use the back/forward buttons for undo/redo).

?View Code ACTIONSCRIPT
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
package {
	import com.asual.swfaddress.SWFAddress;
	import com.asual.swfaddress.SWFAddressEvent;
 
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
 
	public class SWFAddress_test extends Sprite
	{
		private var _square:Shape;
 
		public function SWFAddress_test()
		{
			SWFAddress.addEventListener(SWFAddressEvent.INIT, init);
		}
 
		private function init(evt:SWFAddressEvent):void
		{
			SWFAddress.addEventListener(SWFAddressEvent.CHANGE, handleSWFAddressChange);
			stage.addEventListener(MouseEvent.CLICK, gotoAddress);
 
			_square = new Shape();
			_square.graphics.beginFill(0x0);
			_square.graphics.drawRect(0,0,50,50);
			this.addChild(_square);
		}
 
		private function handleSWFAddressChange(evt:SWFAddressEvent):void
		{
			trace(evt.path);
			var address:Array = evt.path.split("/", 3);
			var xLoc:Number = Number(address[1]);
			if(!isNaN(xLoc)) moveSquare(xLoc);
 
		}
 
		private function gotoAddress(evt:MouseEvent):void
		{
			SWFAddress.setValue(this.mouseX.toString());
		}
 
		private function moveSquare(loc:Number):void
		{
			_square.x = loc;
		}
	}
}

Flex Custom Validator Email Confirmation

Pretty simple stuff. This was driving me a bit crazy at the beginning of the day so I decided to just cut and paste my source code hoping this will help someone else out. Basically I just want to create a custom validator that makes sure one field is equal to another in flex. Pretty simple but if you are a noob you will find this task a bit sucky…. Her is the code

Actionscript Custom Validator.

?View Code ACTIONSCRIPT
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
package com.flextradeshow.classes
{
	import flash.text.TextField;
 
	import mx.controls.TextInput;
	import mx.validators.ValidationResult;
	import mx.validators.Validator;
 
	public class EqualValidator extends Validator
	{
		private var results:Array;
 
		[Bindable]
		public var textbox:TextInput = new TextInput();
 
		public function EqualValidator()
		{
			super();
 
		}
		override protected function doValidation(value:Object):Array
		{
			results = [];
			results = super.doValidation(value);
			if(results.length > 0)
			{
				return results;
			}
			if(value!=textbox.text || !value)
			{
				results.push(new ValidationResult(true,null,"NaN","Not a matching value sorry"));
				return results;
			}
			return results;
		}
	}
}

This is the code you need in your view to use the validator.

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
<?xml version="1.0" encoding="utf-8">
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:tsclasses="com.flextradeshow.classes.*" >
	<mx:StringValidator
		id="nameValidator"
		source="{_iname}"
		property="text"
		minLength="4"
	/>
	<mx:EmailValidator
		id="emailValidator"
		source="{_iemail}"
		property="text"
	/>
	<mx:EmailValidator
		id="emailConfirmationValidator"
		source="{_iconfirmemail}"
		property="text"
	/>
	<tsclasses:EqualValidator id="sameEmailValidator" source="{_iconfirmemail}" textbox="{_iemail}" property="text" />
 
	<mx:Form labelWidth="100" width="302" height="100%" horizontalScrollPolicy="off">
		<mx:FormItem label="Full Name" required="true">
			<mx:TextInput  id="_iname"/>
		</mx:FormItem>
		<mx:FormItem label="Email" required="true">
			<mx:TextInput id="_iemail"/>
		</mx:FormItem>
			<mx:FormItem label="Confirm Email" required="true">
			<mx:TextInput id="_iconfirmemail" />
		</mx:FormItem>
		<mx:FormItem label="Birthday">
			<mx:DateField  id="_ibirthday" />
		</mx:FormItem>
		<mx:Spacer height="15"/>
		<mx:Label text="Free mimoDesk Sample (Choose One)"></mx:Label>
		<mx:Box paddingLeft="110">
			<mx:RadioButtonGroup id="freemimodesk"/>
			<mx:RadioButton label="Star Wars" groupName="freemimodesk" selected="true"/>
			<mx:RadioButton label="Tokidoki" groupName="freemimodesk"/>
			<mx:RadioButton label="Original Core Series" groupName="freemimodesk"/>
			<mx:RadioButton label="Not Interested" groupName="freemimodesk"/>
		</mx:Box>
		<mx:Spacer height="15"/>
		<mx:Label text="Subscribe to any of the following Newsletters"></mx:Label>
		<mx:Box paddingLeft="110">
			<mx:CheckBox label="Consumer" selected="true"/>
			<mx:CheckBox label="Press"/>
			<mx:CheckBox label="Wholesale"/>
		</mx:Box>
		<mx:Box horizontalAlign="right" width="100%">
			<mx:Button label="Subscribe"/>
		</mx:Box>
	</mx:Form>
</mx:Panel>