Getting started with Actionscript 3 Page 3/4 Previous page Next page
[ July 06, 2006 ] Milan Toth (MilGra)
A 4 chapter long, in-depth introduction to the new characteristics of Actionscript 3 and the Flash player 9 framework.
The author will guide you through all the new features by constructing a real application step by step. A must read for all Flash enthusiasts.

Getting started with AS3 - Third Part - loading external assets

We would like to load a bitmap to our ball, and play a sound at bounce. Let's talk about 5 things first:

- packages. Packages are folders, where task-specific classes are placed. If we have several hundred classes, it is hard to overview, but the code hierarchy is still clear thanks to packages.

- variable naming. Clear, recognizable names are very important, but long names make the code unclear. A very good practice to put a short type id after the name of non-primitve types. ( chatSO : SharedObject used to spread chat text , userNameARR: array containing user names )

- skin handling. skins, sounds and all other assets should be loaded by a central class, which sends them to the specific objects after loading. And MVC ( Model - View - Controller ) paradigm is one step away : controller logics must be written as abstract logics - they have to work independently from the skin and other visuals ( MODEL ), then we can create our CONTROLLER classes, whick is the bridge between the skin and the MODEL, it controls the skin, and passes user events to MODEL.

- class-based logging. A good practice to create an addLog function at the bottom of every class, which passes the log text to its parent object. It's good, because we can switch logging on/off independently in every class/class hierarchy witch a simple comment.

Let's start. We have to rewrite our application a bit. Create a new Project named FootballGame. Then File - New - Actionscript Class. Package name: "logic", Class name: "InteractivePointLogic", enter.
We have a new folder ( package ) in Navigator named logic, and there is our InteractivePointLogic.as. Let's convert BallClip class from the previous tutorial to pure logic.

package logic
{
	//
	//
	//
	import flash.display.Sprite;
	import flash.media.Sound;
	import flash.events.*;
	//
	//
	//
	public class InteractivePointLogic
	{
		//
		//
		//
		private var father:Object;
		private var gravity:Number = 0.5;
		private var skinSP:Sprite;
		private var ballSND:Sound;
		//
		public var xpos:Number;
		public var ypos:Number;
		public var xspeed:Number;
		public var yspeed:Number;

Define father, gravity, a variable containing our skin, sound, and the usual position and speed variables. ( we use xpos instead of x, because we should easily mix it with a DisplayObject's x coordinate ).

		//
		//
		//
		public function InteractivePointLogic ( myRoot:MovieClip )
		{
			//
			father = myRoot;
			addLog( "new InteractivePointLogic" );
			//
		}

		//
		//
		//
		public function setSkin ( mySP:Sprite ):void
		{
			//
			skinSP = mySP;
			skinSP.addEventListener( MouseEvent.MOUSE_DOWN , mouseDownHandler );
			skinSP.addEventListener( MouseEvent.MOUSE_UP , mouseUpHandler );
			//
			addLog( "InteractivePointLogic.setSkin " + mySP );
			//
		}

Constructor is evident, we get our skin( reference ) by setSkin, and set mouseEvents.

		//
		//
		//
		public function updateSkin ( ):void
		{
			//
			skinSP.x = xpos;
			skinSP.y = ypos;
			skinSP.rotation += xspeed;
			//
			//addLog( "InteractivePointLogic.updateSkin" );
			//
		}

		//
		//
		//
		public function setSound ( mySND:Sound ):void
		{
			//
			ballSND = mySND;
			//
			addLog( "InteractivePointLogic.setSound " + mySND );
			//
		}

updateSkin sets skin coordinates to our abstract xpos and ypos, and rotates it to make movement lifelike.

		//
		//
		//
		public function step ( timeEvent:TimerEvent ):void
		{
			//
			yspeed += gravity;
			//
			if ( xpos + xspeed > 390 )

			{

				//
				ballSND.play( );
				xspeed *= -1;
				//
			}
			//
			if ( xpos + xspeed < 10 )

			{

				//
				ballSND.play( );
				xspeed *= -1;
				//
			}
			//
			if ( ypos + yspeed > 190 )

			{

				//
				ballSND.play( );
				yspeed -= gravity;
				yspeed *= -1;
				//
			}
			//
			if ( ypos + yspeed < 10 )

			{

				//
				ballSND.play( );
				yspeed *= -1;
				//
			}
			//
			xpos += xspeed;
			ypos += yspeed;
			//
			updateSkin( );
			//
			//addLog( "InteractivePointLogic.step" );
			//
		}

function step expanded a lot, we play our pop sound with every frame collosion. Only the two handler functions and addLog left.

		//
		//
		//
		public function mouseDownHandler ( eventOBJ:MouseEvent ):void
		{
			//
			father.dragBall( );
			//
		}

		//
		//
		//
		public function mouseUpHandler ( eventOBJ:MouseEvent ):void

		{
			//
			father.releaseBall( );
			//
		}

		//
		//
		//
		private function addLog ( logText:String ):void
		{
			//
			father.addLog( logText );
			//
		}

		//
		//
		//
	}
	//
	//
	//
}
//
//
//end

Controller logic comes. We need a footbal bitmap and a pop sound, i found these with google.

ball
pop

We load the bitmap with the help of Loader Display class, and the sound by the classic way Sound class. The only change from AS2, that they need an URLrequest object instead of the pure URL. We use flash.utils.trace to trace addLog messages.

//begin
//
//
package
{

	//
	//
	//
	import flash.display.Loader;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.display.Sprite;
	import flash.media.Sound;
	import flash.net.URLRequest;
	import flash.events.*
	import flash.utils.*;
	//
	import logic.InteractivePointLogic;
	//
	//
	//
	public class FootballGame extends MovieClip
	{
		//
		//
		private var moveTimer:Timer;
		//
		private var hasSkin:Boolean;
		private var hasSound:Boolean;
		private var ballSkinLO:Loader;
		private var ballSkinSP:Sprite;
		private var ballPopSND:Sound;
		private var ballPoint:InteractivePointLogic;
		private var myBackSP:Sprite;
		//
		private var xspeed:Number;
		private var yspeed:Number;
		private var oldx:Number;
		private var oldy:Number;
		//
		//
		//
		public function FootballGame ( )

		{

			//
			stage.frameRate = 25;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP;
			//
			myBackSP = new Sprite( );
			myBackSP.graphics.beginFill( 0x900000 , 1 );
			myBackSP.graphics.lineStyle( 2 , 0xffffff , 1 );
			myBackSP.graphics.moveTo( 0 , 0 );
			myBackSP.graphics.lineTo( 400 , 0 );
			myBackSP.graphics.lineTo( 400 , 200 );
			myBackSP.graphics.lineTo( 0 , 200 );
			myBackSP.graphics.lineTo( 0 , 0 );
			addChild( myBackSP );
			//
			loadSkin( );
			loadSound( );
			//
			addLog( "new FootballGame" );
			//
		}

We don't use a separate Stage instance, because according to the definition, every DisplayObject has a stage static property, which refers to the applet's Stage. In the constructor we start to load skin and sound.

This block does skin and sound loading, and error handling.

		//
		//
		//
		public function loadSkin ( ):void
		{
			//
			ballSkinSP = new Sprite( );
			addChild( ballSkinSP );
			//
			var urlRequest:URLRequest = new URLRequest( "soccerball.gif" );
			ballSkinLO = new Loader( );
			ballSkinLO.contentLoaderInfo.addEventListener( Event.COMPLETE 
,skinLoaded );
			ballSkinLO.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR , 
ioErrorHandler );
			ballSkinLO.load( urlRequest );
			ballSkinSP.addChild( ballSkinLO );
			//
			addLog( "FootballGame.loadSkin" );
			//
		}

		//
		//
		//
		public function loadSound ( ):void
		{
			//
			var urlRequest:URLRequest = new URLRequest( "pop.mp3" );
			ballPopSND = new Sound( );
			ballPopSND.addEventListener( Event.COMPLETE , soundLoaded );
			ballPopSND.addEventListener( IOErrorEvent.IO_ERROR , 
ioErrorHandler );
			ballPopSND.load( urlRequest );
			//
			addLog( "FootballGame.loadSound" );
			//
		}

		//
		//
		//
		public function ioErrorHandler ( eventOBJ:Event ):void
		{
			//
			addLog( "ioError: " + eventOBJ );
			//
		}

		//
		//
		//
		public function skinLoaded ( eventOBJ:Event ):void

		{
			//
			ballSkinLO.x = -20;
			ballSkinLO.y = -20;
			ballSkinLO.width = 40;
			ballSkinLO.height = 40;
			hasSkin = true;
			initLogic( );
			//
			addLog( "FootballGame.skinLoaded" );
			//
		}

		//
		//
		//
		public function soundLoaded ( eventOBJ:Event ):void
		{
			//
			hasSound = true;
			initLogic( );
			//
			addLog( "FootballGame.soundLoaded" );
			//
		}

Interesting things: Loader is actually a Sprite, but a special one, which can load images on itself, with the same attributes as a sprite. However, i put Loader in another Sprite, because i wanted the ball to rotate around its center, and in Loader the image's left upper corner is 0,0.

		//
		//
		//
		public function initLogic ( ):void
		{
			//
			if ( hasSkin && hasSound )

			{
				//
				ballPoint = new InteractivePointLogic( this );
				ballPoint.xpos = 20;
				ballPoint.ypos = 20;
				ballPoint.xspeed = Math.random( )*5;
				ballPoint.yspeed = Math.random( )*5;
				ballPoint.setSkin( ballSkinSP );
				ballPoint.setSound( ballPopSND );
				//
				moveTimer = new Timer( 25 );
				moveTimer.addEventListener( TimerEvent.TIMER , ballPoint.step );
				moveTimer.start( );
				//
			}

			//
			addLog( "FootbalGame.initLogic " + hasSkin + " " + hasSound );
			//
		}
		//
		//
		//
		public function dragBall ( ):void

		{

			//
			addEventListener( MouseEvent.MOUSE_MOVE , moveBall );
			moveTimer.stop( );
			//
			addLog( "FootbalGame.dragBall" );
			//
		}

		//
		//
		//
		public function releaseBall ( ):void
		{

			//
			removeEventListener( MouseEvent.MOUSE_MOVE , moveBall );
			ballPoint.xspeed = xspeed;
			ballPoint.yspeed = yspeed;
			moveTimer.start( );
			//
			addLog( "FootbalGame.releaseBall" );
			//
		}

		//
		//
		//
		public function moveBall ( eventOBJ:MouseEvent ):void

		{
			//
			ballPoint.xpos = mouseX;
			ballPoint.ypos = mouseY;
			ballPoint.updateSkin( );
			//
			xspeed = mouseX - oldx;
			yspeed = mouseY - oldy;
			//
			oldx = mouseX;
			oldy = mouseY;
			//
			addLog( "FootbalGame.moveBall" + mouseX + " " + mouseY );
			//
		}

		//
		//
		//
		public function addLog( logText:String ):void
		{
			//
			trace( logText );
			//
		}

		//
		//
		//
	}

	//
	//
	//
}
//
//
//end

So, this is it.

Source: here

Showcase: here


 
 
Name: Milan Toth (MilGra)
Location: Koka, Hungary
Age: 24
Flash experience: 4 years
Job: flash developer/web designer
Website: http://www.tetrapod.ini.hu/
 
 
| Homepage | News | Games | Articles | Multiplayer Central | Reviews | Spotlight | Forums | Info | Links | Contact us | Advertise | Credits |

| www.smartfoxserver.com | www.gotoandplay.biz | www.openspace-engine.com |

gotoAndPlay() v 3.0.0 -- (c)2003-2008 gotoAndPlay() Team -- P.IVA 03121770048