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 ;)

Enabling Scripts for IE 8+ and Firefox, Safari and Non-IE Browsers.

So we had this weird bug, that we were likely the culprit of, but that we didn’t have time to properly find/fix involving SWFAddress, and some JSON and IE 6 & 7. Namely with anything less then IE 8 inclusion of the SWFAddress javascript file was killing the app when we removed it, things worked fine, albeit without deep link or browser history support.

So we needed to have a way for IE8, Firefox, Safari, Chrome (why not even Opera) load SWFAddress, but the rest not, behold:

<!--[if gte IE 8]>-->
<script type="text/javascript" src="js/swfaddress.2.3.js"></script>
<!--<![endif>-->

Clever eh? it’s the extra -->s that do it, so all browers but IE ignore the only the (otherwise standard) conditional code, but still use the script, like we just put a couple of regular old comments up in there. This has only been tested on a few machines so your milage may vary. Lemme know if things workout (or don’t).

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;
		}
	}
}

Why we use the MIT license for all our work.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Plenty that’s been heard and said before, but with some good jokes, and relevant to the fans / obedient followers of Shepard Fairey and his arrest in Boston. (Glad I live in Somerville).

I still think his arrest has to do with the upcoming mayoral race.