package
{
import flash.geom.Point;
import mx.core.*;
public class Enemy extends AnimatedGameObject
{
static public var pool:ResourcePool = new ResourcePool(NewEnemy);
protected var logic:Function = null;
protected var speed:Number = 0;
static public function NewEnemy():Enemy
{
return new Enemy();
}
public function Enemy()
{
super();
}
public function startupBasicEnemy(graphics:GraphicsResource, position:Point, speed:Number):void
{
super.startupAnimatedGameObject(graphics, position, ZOrders.PlayerZOrder);
logic = basicEnemyLogic;
this.speed = speed;
this.collisionName = CollisionIdentifiers.ENEMY;
}
override public function shutdown():void
{
super.shutdown();
logic = null;
}
override public function enterFrame(dt:Number):void
{
super.enterFrame(dt);
if (logic != null)
logic(dt);
}
protected function basicEnemyLogic(dt:Number):void
{
if (position.y > Application.application.height + graphics.bitmap.height )
this.shutdown();
position.y += speed * dt;
}
override public function collision(other:GameObject):void
{
var animatedGameObject:AnimatedGameObject = AnimatedGameObject.pool.ItemFromPool as AnimatedGameObject;
animatedGameObject.startupAnimatedGameObject(
ResourceManager.BigExplosionGraphics,
new Point(
position.x + graphics.bitmap.width / graphics.frames / 2 - ResourceManager.BigExplosionGraphics.bitmap.width / ResourceManager.BigExplosionGraphics.frames / 2,
position.y + graphics.bitmap.height / 2 - ResourceManager.BigExplosionGraphics.bitmap.height / 2),
ZOrders.PlayerZOrder,
true);
this.shutdown();
ResourceManager.ExplosionFX.play();
}
}
}
With just one call to the play function we can play a sound effect. I told you Flex made playing sound easy. The Player class makes similar calls to the play function when creating a new weapon (during the enterFrame function) and also when it is destroyed (during the collision function). Download the source code at the end of the article to view those changes.
The process for playing background music is similar, but there are a few extra steps we need to take because we need to be able to manually stop the music when we exit the level (i.e. when we leave the Game state). Lets take a look at the changes to the Level class now.
package
{
import flash.events.*;
import flash.geom.*;
import flash.media.*;
import flash.net.*;
import flash.utils.*;
import mx.collections.*;
import mx.core.*;
public class Level
{
protected static var instance:Level = null;
protected static const TimeBetweenLevelElements:Number = 2;
protected static const TimeBetweenEnemies:Number = 3;
protected static const TimeBetweenClouds:Number = 2.5;
protected static const TimeToLevelEnd:Number = 2;
protected var timeToNextLevelElement:Number = 0;
protected var levelElementGraphics:ArrayCollection = new ArrayCollection();
protected var timeToNextEnemy:Number = 0;
protected var enemyElementGraphics:ArrayCollection = new ArrayCollection();
protected var timeToNextCloud:Number = 0;
protected var timeToLevelEnd:Number = 0;
protected var backgroundMusic:SoundChannel = null;
public var levelEnd:Boolean = false;
static public function get Instance():Level
{
if ( instance == null )
instance = new Level();
return instance;
}
public function Level(caller:Function = null )
{
if ( Level.instance != null )
throw new Error( "Only one Singleton instance should be instantiated" );
levelElementGraphics.addItem( ResourceManager.SmallIslandGraphics);
levelElementGraphics.addItem( ResourceManager.BigIslandGraphics);
levelElementGraphics.addItem( ResourceManager.VolcanoIslandGraphics);
enemyElementGraphics.addItem( ResourceManager.SmallBluePlaneGraphics);
enemyElementGraphics.addItem( ResourceManager.SmallGreenPlaneGraphics);
enemyElementGraphics.addItem( ResourceManager.SmallWhitePlaneGraphics);
}
public function startup():void
{
timeToNextLevelElement = 0;
new Player().startupPlayer();
timeToLevelEnd = TimeToLevelEnd;
levelEnd = false;
backgroundMusic = ResourceManager.Track1FX.play(0, int.MAX_VALUE);
}
public function shutdown():void
{
backgroundMusic.stop();
backgroundMusic = null;
}
public function enterFrame(dt:Number):void
{
// add a background element
timeToNextLevelElement -= dt;
if (timeToNextLevelElement <= 0)
{
timeToNextLevelElement = TimeBetweenLevelElements;
var graphics:GraphicsResource = levelElementGraphics.getItemAt(MathUtils.randomInteger(0, levelElementGraphics.length)) as GraphicsResource;
var backgroundLevelElement:BackgroundLevelElement = BackgroundLevelElement.pool.ItemFromPool as BackgroundLevelElement;
backgroundLevelElement.startupBackgroundLevelElement(
graphics,
new Point(Math.random() * Application.application.width, -graphics.bitmap.height),
ZOrders.BackgoundZOrder,
50);
}
// add an emeny
timeToNextEnemy -= dt;
if (timeToNextEnemy <= 0)
{
timeToNextEnemy = TimeBetweenEnemies;
var enemygraphics:GraphicsResource = enemyElementGraphics.getItemAt(MathUtils.randomInteger(0, enemyElementGraphics.length)) as GraphicsResource;
var enemy:Enemy = Enemy.pool.ItemFromPool as Enemy;
enemy.startupBasicEnemy(
enemygraphics,
new Point(Math.random() * Application.application.width, -enemygraphics.bitmap.height),
55);
}
// add cloud
timeToNextCloud -= dt;
if (timeToNextCloud <= dt)
{
timeToNextCloud = TimeBetweenClouds;
var cloudBackgroundLevelElement:BackgroundLevelElement = BackgroundLevelElement.pool.ItemFromPool as BackgroundLevelElement;
cloudBackgroundLevelElement. startupBackgroundLevelElement(
ResourceManager.CloudGraphics,
new Point(Math.random() * Application.application.width, -ResourceManager.CloudGraphics.bitmap.height),
ZOrders.CloudsBelowZOrder,
75);
}
if (levelEnd)
{
timeToLevelEnd -= dt;
var scale:Number = timeToLevelEnd / TimeToLevelEnd;
if (scale < 0) scale = 0;
var transform:SoundTransform = backgroundMusic.soundTransform;
transform.volume = scale;
backgroundMusic.soundTransform = transform;
}
if (timeToLevelEnd <= 0)
Application.application.currentState = "MainMenu";
}
}
}
In order to manipulate a sound when it is playing we need to keep a reference to the SoundChannel that is returned with the SoundAsset play function. To this end we have added a backgroundMusic property, which is assigned a value in the startup function. In the shutdown function we call stop to stop the music from playing. In the enterFrame function we have added some code that allow us to fade the music out once levelEnd has been set to true (i.e. the level has ended because the Player has died). This is done by assigning the transform variable to the backgroundMusic soundTransform property, modifying the volume property on the transform variable, and then setting backgroundMusic soundTransform property back to our edited transform variable.
While displaying graphics required jumping through some hoops, Flex makes playing sounds a trivial task. With only a dozen lines of code we have embedded the sound effects and then played them during the game.
With the sound effects implemented we have all the basic elements of a game. Fighting endless waves of randomly positioned enemies will get pretty boring though. In part 9 of the series look at implementing a way to define a level structure i.e. defining where and when enemies, background elements and any other game element are created.
Go back to Flash Game Development with Flex and ActionScript