F9 for actions

Some possibly useful and definitely unuseful ActionScript 3.0 code.

Posts tagged as3

Oct 17

Exploration of Radial Collision

I was fortunate enough to meet Terry Paton at this year’s MAX conference. If you don’t know, he’s a Flash game developer that produces some great work and contributes a lot of knowledge to the online web of Flash resources - definitely a recommended follow.

Anyway, he made a blog post showing simple distance-based radial collision technique that he uses often in his games. The technique wasn’t new to me, but something about his post lit a fire in me to explore the idea to an extent that I’ve never put down in code before.

While playing around with the concept, I thought to myself that knowing when something hits something else is great, but often for games you want to know where something hit the other thing and usually you want one or the other or both of those objects to react upon that collision, much like things react to collisions in the physical world. It’s also useful knowing if something collides with a certain coordinate, such as the current position of the mouse.

So I took Terry’s code and expanded upon it with the idea that instead of getting back a true or false on whether objects are colliding, instead if there is a collision, you get back a data object with some really useful information about that collision. Here is the Collider Class:

package  {
	import flash.display.Sprite;
	import flash.display.DisplayObject;
	
	public class Collider {
		
		public static var lastCollision:Object;
		private static var pointsprite:Sprite;

		public function Collider() {
			// constructor code
		}
		
		public static function checkPointCollision( px:Number, py:Number, o1:DisplayObject, customRadius:Number = 0 ):Object {
			
			if( !pointsprite ) {
				pointsprite = new Sprite();
				pointsprite.graphics.beginFill( 0, 0 );
				pointsprite.graphics.drawCircle( 0, 0, 1 );
				pointsprite.graphics.endFill();
			}
			
			pointsprite.x = px;
			pointsprite.y = py;
			return Collider.checkCollision( pointsprite, o1, customRadius );
		}


		public static function checkCollision( o1:DisplayObject, o2:DisplayObject, customRadius1:Number = 0, customRadius2:Number = 0 ):Object {
			
			var dx:Number = o1.x - o2.x;
			var dy:Number = o1.y - o2.y;
			
			var csquared:Number = dx*dx+dy*dy;
			var dist:Number = Math.abs(Math.sqrt(csquared));
		
			var r1:Number;
			var r2:Number;
			
			if( customRadius1 != 0 ) {
				r1 = customRadius1;
			} else {
				r1 = (o1.width*.5);
			}
			
			if( customRadius2 != 0 ) {
				r2 = customRadius2;
			} else {
				r2 = (o2.width*.5);
			}
			
			var tr:Number = r1+r2;
			
			if (dist = 360 ) {
				realDegrees -= 360;
			}
			while ( realDegrees < 0 ) {
				realDegrees += 360;
			}
			return realDegrees;
		}
	}
}

And here it is in action, followed by the timeline code for the swf

import flash.display.Sprite;
import flash.display.DisplayObject;

var bumpers:Vector.<Bumper> = new Vector.<Bumper>();
var collision:Object = {};
init();

function init():void {
	
	for( var i:int = 0; i < 40; i++ ) {
		var b:Bumper = new Bumper();
		
		//b.x = Math.random()*stage.stageWidth;
		//b.y = Math.random()*stage.stageHeight;
		b.x = 90*Math.cos(i) + stage.stageWidth*.5;
		b.y = 90*Math.sin(i) + stage.stageHeight*.5;
		
		bumpers.push(b);
		addChild(b);
	}
	
	this.addEventListener( Event.ENTER_FRAME, onFrame );
}

function onFrame( e:Event ):void {
	
	for( var i:int = 0; i < bumpers.length; i++ ) {
		
		collision = Collider.checkCollision( player, bumpers[i] );
		if( collision ) {
			
			arrow.rotation = collision.angle;
			arrow.x = collision.x;
			arrow.y = collision.y;
			
			player.xvel =  8*Math.cos( collision.radians );
			player.yvel =  8*Math.sin( collision.radians );
			
			bumpers[i].xvel +=  Math.cos( collision.oppositeRadians );
			bumpers[i].yvel +=  Math.sin( collision.oppositeRadians );
			
		}
		
		collision = Collider.checkPointCollision( mouseX, mouseY, player );
		if( collision ) {
			player.xvel = 5*Math.cos( collision.oppositeRadians );
			player.yvel = 5*Math.sin( collision.oppositeRadians );
		}
	}
}

It’s not perfect, but for getting you up and running with collisions it does a pretty decent job. Enjoy

DOWNLOAD THE SOURCE


May 10

Converting a JSFL Object to JSON

I couldn’t find any online resource to talk about how people are passing data from JSFL scripts to their Flash Panels. When you use MMExecute you can return a String value back to Flash, or if you’re making a function available via ExternalInterface you can also pass primitive datatypes into the functions. However when you start talking about passing Objects of any significant structure, things get a little hairy.

So it was my conclusion that I needed to serialize my data object in JSFL in order to pass it to Flash. And when you talk serialize in Javascript you should think JSON, so I set in search for an out-of-the-box Javascript Object to JSON serializing function - should be easy to find right? Unfortunately, after two days of struggling with different implementations, I found that some of the String functions like match and replace cause errors (not saying they aren’t implemented, just for whatever reason they didn’t work for me like they do in regular JS).

So without further delay, here is my very less-than perfect, less-than optimized JSFL Object to JSON String functions. (Also note that these will convert any Arrays nested in your Objects to Objects themselves with keys being the string equivalent of their indexes.

— UPDATE —

I wrote this post before testing it completely against sending the JSON string over to Flash via the SWFPanel.call() method. What I found out while trying to do this is that you can not, for whatever reason, send literal single or double quotes embedded within the string variable. So I changed up my function to use tildes (~) instead of quotes, which I then replaced with quotes over on the AS3 side of things.

function serializeObject( o ) {
	var s = '{';
	s += so( o );
	//remove the last comma
	s = s.slice( 0, s.length-1 );
	s += '}';

	return s;
}

function so( o ) {
	var s = '';

	for( var key in o ) {
		if( o[key].toString() == '[object Parameter]' ) {
			s +=  '~' + key + '~:{';
			s += so( o[key] );

			//remove the last comma
			s = s.slice( 0, s.length-1 );
			s += '},';
		} else if(o[key].constructor === Array ) {

			for( var key2 in o[key] ) {
				if(key2 != "" && o[key][key2].value != '""') {
					s += '~' + key2 + '~:~' + o[key][key2].value + '~,';
				}
			}

		}else {
			if(key != "" && o[key] != '""') {
				s += '~' + key + '~:~' + o[key].toString()  + '~,';
			}
		}
	}

	return s;
}

And here is what I do on the AS3 side to convert it into an Object from JSON (note I’m using the as3corelib to JSON decode the string).

//function exposed via ExternalInterface and called from JSFL
public function setParameters( s:String ):void {

	var p:RegExp = /~/g;
	var t:String = s.replace(p, '"');		

	var o:Object = JSON.decode(t);

}

Like I said it’s not a perfect implementation, but it works pretty well for nested Objects. To put this in perspective, I’m using this so I can pass all the attributes of multiple selected components on the stage (via the fl.getDocumentDOM().selection Array) to my WindowSWF Panels which will allow me to change and configure the components’ properties.