Handy Utilities for Making Games with Stage3D and Starling

Here are a few links to some great utilities I use for making Starling Projects.
Most are free. The ones that are not are really worth it.

Explosion Generators:
Positech games Explosion Generator (Windows Only)

Nuvorm Explosion Generator: Flash based generator. Source code provided

Bitmap Font Generator:

Free for Windows: http://www.angelcode.com/products/bmfont/

And Fee For Mac: http://glyphdesigner.71squared.com/

http://www.bmglyph.com/

Sprite Sheet Packer

TexturePacker - buy this now. It is the best.

 

 

Posted in Tutorials | Leave a comment

Rotate the Shortest Direction

Here is this so I will never have to search to find this code again: How to rotate an object to face some other object, and always rotate the shortest path between the two angles. With a gradual easing no less.
If the class below is too much for you, the magic formula is this:

var rotationdifference:Number = Math.atan2(Math.sin(targetrotation-originalrotation),Math.cos(targetrotation-originalrotation));

And here is a demo of what the code below will produce:

This movie requires Flash Player 10

package 
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
 
	/**
	 * ...
	 * @author Zachary Foley
	 */
	public class Main extends Sprite 
	{		
		static public const RADIANS_TO_DEGREES:Number = 57.2957795;
		static public const DEGREES_TO_RADIANS:Number = 0.0174532925;
		static public const EASE_AMOUNT:Number = 0.05;
		private var circle:Shape
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			// Add a label for this swf.
			var text:TextField = new TextField();
			text.text = "ROTATE SHORTEST PATH";
			text.autoSize = TextFieldAutoSize.CENTER;
			text.width = stage.stageWidth;
			addChild(text);
			// Add a circle to show it works.
			circle = new Shape();
			circle.graphics.lineStyle(1, 0, 1);
			circle.graphics.beginFill(0xFF6767, 1);
			circle.graphics.drawCircle(0, 0, 25);
			circle.graphics.moveTo(0, 0);
			circle.graphics.lineTo(-25, 0);
			addChild(circle);
			circle.x = stage.stageWidth / 2;
			circle.y = stage.stageHeight / 2;
 
			// Add a background color.
			graphics.beginFill(0x999999);
			graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
 
			// Listen for updates
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
 
		private function onEnterFrame(e:Event):void 
		{
			// Rotate towards Mouse.
			var p:Point = new Point(circle.x, circle.y);
			p.x -= this.mouseX;
			p.y -= this.mouseY;
			// If you just need to look at the target, use this.
			//circle.rotation = rotateTowards(p) * RADIANS_TO_DEGREES; // Look right at mouse.
			var originalrotation:Number = circle.rotation * DEGREES_TO_RADIANS;
			var targetrotation:Number = Math.atan2(p.y, p.x);
			var rotationdifference:Number = Math.atan2(Math.sin(targetrotation-originalrotation),Math.cos(targetrotation-originalrotation));
			// To look at it just like "Look at mouse" use this.			
			//circle.rotation += rotationdifference*RADIANS_TO_DEGREES;			
			// To ease, we apply only a percentage of the rotation needed.
			circle.rotation += rotationdifference*RADIANS_TO_DEGREES* EASE_AMOUNT;		
		}
 
		// This is the old "Look at mouse" effect.
		public function rotateTowards(point:Point):Number {						
			return Math.atan2(point.y, point.x);
		}
 
	}
 
}

Get the source from Github.

Posted in Tutorials | 1 Comment

How to get the Facebook Profile Pictures Album With FQL and Flash

In the past when I wanted to get a users’s profile picture album, I asked for all the users albums, and then found the one who’s name was “Profile Pics”. Then I discovered that some users have over 500 photo albums. And “Profile Pics” was not always returned in the query. Plus the response was getting bigger and slower, and who was to say there isn’t a user with 5000 albums?

A more surgical approach was needed. And so for the first timer ever, I tried out FQL (Facebook Query Language) with the graph API, to get the graph to return only the users profile pic album.

From now on this is the way I will always do it, because its the best..

var url:String = 'https://graph.facebook.com/me/fql?q=select+object_id+from+album+where+owner=me()+and+type="profile"&access_token=' + PUT_YOUR_ACCESS_TOKEN_HERE;
Posted in Tutorials | Tagged , , | Leave a comment

Changing the pitch of a looped sound at runtime with Actionscript.

I’m so excited to put a link to the game I am working on at work. Its a driving game for a summer sci-fi blockbuster. And that’s about all i can say about it right now. But in the process of making the game, I had to figure out how to change the pitch of a sound in AS3.

As a starting place I found this excellent blog post from Andre Michelle. It showed me everything i needed to know about how to change the pitch. But it did not work with sounds that looped. And since the engine noise for the game was a 10 second loop, I had to make some modifciations.

And then my friend Ian told me he was working on a new breed of fart app, one in which you can control the pitch of the fart as it plays. Next thing you know, this short code post:

package sound
{
	import flash.events.Event;
	import flash.events.SampleDataEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
 
	/**
	 * @author Andre Michelle (andr...@gmail.com)
         * Modified by Zach Foley aka The Plastic Sturgeon
	 */
	public class MP3Pitch
	{
		private const BLOCK_SIZE: int = 3072;
 
		private var _mp3: Sound;
		private var _sound: Sound;
 
		private var _target: ByteArray;
 
		private var _position: Number;
		private var _rate: Number;
		private var repeat:SoundChannel;
		private var _volume:Number = 1;
		private var byteArray:ByteArray;
 
                // Pass in your looped Sound
		public function MP3Pitch( pitchedSound: Sound)
		{
			_target = new ByteArray();
			_mp3 =  pitchedSound;
 
			_position = 0.0;
			_rate = 0.0;
 
			_sound = new Sound();
			_sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
			repeat = _sound.play();
		}
 
		public function get rate(): Number
		{
			return _rate;
		}
 
                // Also added a handy volume setter
		public function set volume( value: Number ): void
		{
			_volume = value;
			repeat.soundTransform = new SoundTransform(_volume);
		}
 
                // use this to set the pitch of your sound
		public function set rate( value: Number ): void
		{
			if( value < 0.0 )
				value = 0;
 
			_rate =  value;
		}
 
		private function sampleData( event: SampleDataEvent ): void
		{
			//-- REUSE INSTEAD OF RECREATION
			_target.position = 0;
 
			//-- SHORTCUT
			var data: ByteArray = event.data;
 
			var scaledBlockSize: Number = BLOCK_SIZE * _rate;
			var positionInt: int = _position;
			var alpha: Number = _position - positionInt;
 
			var positionTargetNum: Number = alpha;
			var positionTargetInt: int = -1;
 
			//-- COMPUTE NUMBER OF SAMPLES NEED TO PROCESS BLOCK (+2 FOR INTERPOLATION)
			var need: int = Math.ceil( scaledBlockSize ) + 2;
 
			//-- EXTRACT SAMPLES
			var read: int = _mp3.extract( _target, need, positionInt );
 
			var n: int = read == need ? BLOCK_SIZE : read / _rate;
 
			var l0: Number;
			var r0: Number;
			var l1: Number;
			var r1: Number;
 
			for( var i: int = 0 ; i < n ; ++i )
			{
				//-- AVOID READING EQUAL SAMPLES, IF RATE < 1.0
				if( int( positionTargetNum ) != positionTargetInt )
				{
					positionTargetInt = positionTargetNum;
 
					//-- SET TARGET READ POSITION
					_target.position = positionTargetInt << 3; 	 					//-- READ TWO STEREO SAMPLES FOR LINEAR INTERPOLATION 					l0 = _target.readFloat(); 					r0 = _target.readFloat(); 					l1 = _target.readFloat(); 					r1 = _target.readFloat(); 				} 				 				//-- WRITE INTERPOLATED AMPLITUDES INTO STREAM 				data.writeFloat( l0 + alpha * ( l1 - l0 ) ); 				data.writeFloat( r0 + alpha * ( r1 - r0 ) ); 				 				//-- INCREASE TARGET POSITION 				positionTargetNum += _rate; 				 				//-- INCREASE FRACTION AND CLAMP BETWEEN 0 AND 1 				alpha += _rate; 				while( alpha >= 1.0 ) --alpha;
			}
 
			//-- FILL REST OF STREAM WITH ZEROs
			if( i < BLOCK_SIZE )
			{
				while( i < BLOCK_SIZE ) 				{ 					data.writeFloat( 0.0 ); 					data.writeFloat( 0.0 ); 					 					++i; 				} 			} 			//-- INCREASE SOUND POSITION 			_position += scaledBlockSize;                        // My little addition here: 			if (_position > _mp3.length * 44.1) {
				_position = 0;
				_target.position = 0;
			}
		}
	}
}

To use it just create a new MP3 Pitch:

pitched = new MP3Pitch(new CarLoopLow())

To set the rate just call:

pitched.rate = 0;

To set the volume:

pitched.rate = 0;

Also, make sure your audio is exported as MP3 and I strongly suggest using at a minimum the 64kbps quality.

Posted in Tutorials | Tagged , , , | 3 Comments

Flare3d: Preloading Assets using URLLoader

I ran into a problem while working with Flare3D on a game. I was making a racing game, and the player drives through five areas. The problem was that each area the user drives through was a very detailed envirnment. About 4-10 megabytes a piece. Far too large for  player to download up front.

So I decided to build a progressive preloader, that loads the levels as the player plays. At first I tried this using the Flare3DLoader class. In using it I encountered two problems, one of which was a fatal problem for the approach:

Problem 1:

The Flare3DLoader class will never fire a Complete event unless it is attached to a scene. It makes sense in a way, in that your model is not ready to be accessed through the Flare3D api until it has been parsed. But the downside is that you can’t know the load is complete unless add the loaded resource to the scene.

While I got this to work, it could easily cause problems as all these items get unpacked into your limited OpenGL memory. Another drawback is that you cannot re-load the asset either. Once you call dispose() on the loaded asset, its gone.

Problem 2:

When the asset finishes loading, the entire flash plugin freezes for a second or more while your model is parsed and written to the GPU. This was the deal-breaker for me, as the end result was that the game would hang for one or more seconds at an arbitrary point in time. I needed to have specific control over when the model gets parsed so that the user experience is not disrupted.

The solution:

The solution was two part. I realized that underneath the Flare3DLoader there must be a URLLoader that was loading the model file and then parsing it. So I loaded one up and tried to pass it to the Flare3DLoader constructor. After some trial and error I found that by setting the URLLoader dataFormat to Binary, this worked.

 

var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;				
loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
loader.addEventListener(Event.COMPLETE, onLoadComplete);

The second part was using ByteArray to make a copy of the loaded data so that the level could be loaded more than once. This was crucial to being able to click “replay” on the game.

var data:ByteArray = new ByteArray();
// This line copies the loader.data.
data.writeObject(loader.data); 
// reset the byte array to be read.
data.position = 0; 
// pass the copy of the data into flare 3D as a loader.
var model:Flare3DLoader = new Flare3DLoader(data.readObject()); 
// Add the loader to the scene.
scene.addChild(model);
// You may want to listen for when you model is parsed and ready.
// In that case just add:
model.addEventListener(Scene3D.COMPLETE_EVENT, onModelLoaded);
Posted in Tutorials | Tagged , , | 4 Comments