Moving stuff around, nothing to see here
git-svn-id: https://aklabs.dyndns.org/svn/aklabs/trunk/games/wilysays@50 eb184899-6090-47d4-a65b-558f62f6ea1c
This commit is contained in:
34
net/aklabs/demo/simonsays/LoadingObject.as
Executable file
34
net/aklabs/demo/simonsays/LoadingObject.as
Executable file
@@ -0,0 +1,34 @@
|
||||
package net.aklabs.demo.simonsays {
|
||||
|
||||
/*
|
||||
* Class LoadingObject
|
||||
*
|
||||
* This class is used to represent a content asset while it is going through the process of being loaded
|
||||
* by the Preloader class.
|
||||
*/
|
||||
public class LoadingObject {
|
||||
public static var STATE_READY:Number = 0; // Object has been loaded and is ready
|
||||
public static var STATE_LOADING:Number = 1; // Object is currently loading, not ready yet
|
||||
public static var STATE_NOTFOUND:Number = 2; // Object wasn't found in the cache
|
||||
public var handle:String; // Text handle for this object
|
||||
public var state:Number; // State value
|
||||
public var bytesRead:Number; // the amount of bytes currently read in to this object over the net
|
||||
public var bytesTotal:Number; // the total byte size of this object
|
||||
|
||||
/*
|
||||
* LoadingObject()
|
||||
*
|
||||
* Default constructor
|
||||
*
|
||||
* arguments : none
|
||||
*
|
||||
* Returns : LoadingObject
|
||||
*/
|
||||
public function LoadingObject() {
|
||||
this.handle = "";
|
||||
this.state = LoadingObject.STATE_NOTFOUND;
|
||||
this.bytesRead = 0;
|
||||
this.bytesTotal = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
176
net/aklabs/demo/simonsays/Mastermind.as
Executable file
176
net/aklabs/demo/simonsays/Mastermind.as
Executable file
@@ -0,0 +1,176 @@
|
||||
package net.aklabs.demo.simonsays
|
||||
{
|
||||
|
||||
import flash.utils.Timer;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.display.Sprite;
|
||||
import net.aklabs.demo.simonsays.Preloader;
|
||||
import net.aklabs.demo.simonsays.SimonButton;
|
||||
import net.aklabs.demo.simonsays.MastermindEvent;
|
||||
|
||||
/*
|
||||
* Class: Mastermind
|
||||
*
|
||||
* This class defines our "Simon Says", "Wily Lok", "Mastermind", whatever you want to call it.
|
||||
* (I called it 3 or 4 different things during the course of development.)
|
||||
*
|
||||
*/
|
||||
public class Mastermind extends Sprite
|
||||
{
|
||||
protected var lightOutTimer:Timer; // timer that fires when it's time to turn off the lights
|
||||
protected var lightButtons:Array; // array of custom SimonButtons that exists in Pattern.COLOR_XXX order
|
||||
public var isLit:Boolean; // is the device currently lit?
|
||||
|
||||
public function Mastermind()
|
||||
{
|
||||
var preloader = Preloader.getInstance();
|
||||
var lightPositions = new Array();
|
||||
// this array holds pairs of (x,y) coordinates at which to place the dark/light colored
|
||||
// Simon Says buttons, since they're meant to cover the existing buttons on the original graphic.
|
||||
// These are hard-coded; in a better implementation, they would come from an XML or would be
|
||||
// individual frames of an SWF which could be fired individually, etc. But this works.
|
||||
// array idx 0: Blue, 1: Green, 2: Red, 3: Yellow
|
||||
|
||||
lightPositions.push( new Array(183, 187)); // blue
|
||||
lightPositions.push( new Array(18, 17)); // green
|
||||
lightPositions.push( new Array(185, 17)); // red
|
||||
lightPositions.push( new Array(18, 186)); // yellow
|
||||
|
||||
// this array holds the button objects for the visible simon says buttons ...
|
||||
this.lightButtons = new Array();
|
||||
// just a temporary array for which images to fetch for creating the down/up button images
|
||||
var fetchArray = new Array( new Array("gfx_btn_darkblue", "gfx_btn_lightblue"),
|
||||
new Array("gfx_btn_darkgreen", "gfx_btn_lightgreen"),
|
||||
new Array("gfx_btn_darkred", "gfx_btn_lightred"),
|
||||
new Array("gfx_btn_darkyellow", "gfx_btn_lightyellow") );
|
||||
// Simon Says body
|
||||
var whole = preloader.getObject("gfx_mastermind");
|
||||
this.addChild(whole);
|
||||
|
||||
for ( var i = 0; i < fetchArray.length ; i++ ) {
|
||||
var btn:SimonButton = new SimonButton(preloader.getObject(fetchArray[i][1]), preloader.getObject(fetchArray[i][0]));
|
||||
btn.x = lightPositions[i][0];
|
||||
btn.y = lightPositions[i][1];
|
||||
this.lightButtons.push(btn);
|
||||
this.addChild(btn);
|
||||
btn.addEventListener(MouseEvent.CLICK, this.onMouseClick); // for some reason, MouseEvent.CLICK never actually does anything?
|
||||
//btn.addEventListener(MouseEvent.MOUSE_UP, this.onMouseClick);
|
||||
}
|
||||
this.lightOutTimer = new Timer(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* flashAll(length)
|
||||
*
|
||||
* This function lights all the lights on the Mastermind for the given length of time
|
||||
*
|
||||
* arguments:
|
||||
* @length:Number, the time in milliseconds for which the Mastermind should stay lit
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function flashAll(length:Number)
|
||||
{
|
||||
this.lightOutTimer.delay = length;
|
||||
this.lightOutTimer.addEventListener(TimerEvent.TIMER, this.onTimer);
|
||||
this.lightOutTimer.reset();
|
||||
this.lightOutTimer.start();
|
||||
for (var i = 0 ; i < 4 ; i++) {
|
||||
// fake mouse event to light it up
|
||||
this.lightButtons[i].onMouseDown(null);
|
||||
}
|
||||
this.isLit = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* lightButton(btn, activeTime)
|
||||
*
|
||||
* This function lights up a given button on the Mastermind. Mostly used by the Pattern when it's replaying itself.
|
||||
*
|
||||
* arguments:
|
||||
* @btn:Number, the Pattern.COLOR_XXX button that should light
|
||||
* @activeTime:Number, the amount of milliseconds for which the button should stay lit
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function lightButton(btn:Number, activeTime:Number = 0 )
|
||||
{
|
||||
if ( btn < 4 ) {
|
||||
this.lightButtons[btn].onMouseDown(null);
|
||||
this.isLit = true;
|
||||
}
|
||||
if ( activeTime != 0 ) {
|
||||
this.lightOutTimer.delay = activeTime;
|
||||
this.lightOutTimer.addEventListener(TimerEvent.TIMER, this.onTimer);
|
||||
this.lightOutTimer.reset();
|
||||
this.lightOutTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* blackout()
|
||||
*
|
||||
* This function makes sure that all lights on the Mastermind are extinguished
|
||||
*
|
||||
* arguments : none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function blackout()
|
||||
{
|
||||
if ( this.lightButtons.length <= 0 ) {
|
||||
return;
|
||||
}
|
||||
for ( var i = 0 ; i < this.lightButtons.length ; i++ ){
|
||||
this.lightButtons[i].onMouseUp(null);
|
||||
}
|
||||
this.isLit = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* onTimer(evt)
|
||||
*
|
||||
* This function fires whenever the lightOutTimer fires, telling the lights to shut off
|
||||
*
|
||||
* arguments :
|
||||
* @evt:Event, the event that's firing this function
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function onTimer(evt:TimerEvent)
|
||||
{
|
||||
if ( evt.target != this.lightOutTimer )
|
||||
return;
|
||||
this.lightOutTimer.removeEventListener(TimerEvent.TIMER, this.onTimer);
|
||||
this.lightOutTimer.stop();
|
||||
this.lightOutTimer.reset();
|
||||
this.blackout();
|
||||
}
|
||||
|
||||
/*
|
||||
* onMouseClick()
|
||||
*
|
||||
* This function is fired whenever the user clicks one of the Mastermind's buttons
|
||||
*
|
||||
* arguments:
|
||||
* @evt:Event, the event firing this function
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function onMouseClick(evt:MouseEvent)
|
||||
{
|
||||
// we don't do any processing here, as the SimonButton has already checked for
|
||||
// per-pixel accuracy w/ the click on our abnormally shaped buttons. We just propagate
|
||||
// out a new MastermindEvent for the game to catch.
|
||||
for ( var i:Number = 0; i < this.lightButtons.length ; i++ ) {
|
||||
if ( evt.target == this.lightButtons[i] ) {
|
||||
var newEvt:MastermindEvent = new MastermindEvent(MastermindEvent.BTN_CLICKED);
|
||||
newEvt.colorClicked = i;
|
||||
this.dispatchEvent(newEvt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
net/aklabs/demo/simonsays/MastermindEvent.as
Executable file
22
net/aklabs/demo/simonsays/MastermindEvent.as
Executable file
@@ -0,0 +1,22 @@
|
||||
package net.aklabs.demo.simonsays
|
||||
{
|
||||
import flash.events.Event;
|
||||
|
||||
/*
|
||||
* Class : MastermindEvent
|
||||
*
|
||||
* This class basically just defines a custom event that will let the mastermind send up
|
||||
* a clicked event w/ a color.
|
||||
*/
|
||||
public class MastermindEvent extends Event
|
||||
{
|
||||
public static var BTN_CLICKED:String = "MASTERMIND_BUTTON_CLICKED";
|
||||
public var colorClicked:Number;
|
||||
|
||||
public function MastermindEvent(evtType:String)
|
||||
{
|
||||
super(evtType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
393
net/aklabs/demo/simonsays/Pattern.as
Executable file
393
net/aklabs/demo/simonsays/Pattern.as
Executable file
@@ -0,0 +1,393 @@
|
||||
package net.aklabs.demo.simonsays
|
||||
{
|
||||
import flash.utils.Timer;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Bitmap;
|
||||
import net.aklabs.demo.simonsays.Mastermind;
|
||||
import net.aklabs.demo.simonsays.Powerup;
|
||||
import net.aklabs.demo.simonsays.PowerupEvent;
|
||||
import net.aklabs.demo.simonsays.Preloader;
|
||||
|
||||
/*
|
||||
* Class Pattern
|
||||
*
|
||||
* This class defines a "pattern", which is where most of the game challenge exists.
|
||||
* It just defines the pattern currently being traced out on the Simon Says/Mastermind/etc
|
||||
*
|
||||
* In addition to doing processing, this class also does some graphical representation,
|
||||
* in the way of a series of red/green lights to show how far along the player is inside the
|
||||
* pattern. The image is 16 pixels wide, and (16*maxSize) pixels tall.
|
||||
*
|
||||
*/
|
||||
public class Pattern extends Sprite
|
||||
{
|
||||
public static var COLOR_BLUE:Number = 0;
|
||||
public static var COLOR_GREEN:Number = 1;
|
||||
public static var COLOR_RED:Number = 2;
|
||||
public static var COLOR_YELLOW:Number = 3;
|
||||
|
||||
protected var patternTimer:Timer; // timer that fires to check pattern logic independently of game timer
|
||||
protected var curIndex:Number; // amount of the pattern currently finished
|
||||
protected var pattern:Array; // the array of colors that make up the actual pattern
|
||||
protected var simon:Mastermind; // A link back up to the parent Mastermind (put here because I didn't want to assume that this.parent would always be correct)
|
||||
protected var delay:Number; // The number of milliseconds that should pass before the logic timer fires
|
||||
protected var playCount:Number; // The number of times this pattern has been played through (via Forgiveness). Not currently used for anything.
|
||||
public var clearTime:Number; // the amount of time the player has (in milliseconds) to finish the pattern
|
||||
public var state:Number; // state of the pattern at current
|
||||
public static var STATE_RUNNING = 0; // STATE : pattern is currently "running" - e.g., waiting for input from the player and checking logic
|
||||
public static var STATE_DEMO = 1; // STATE : pattern is currently "demoing", e.g., flashing the lights up to this.curIndex of the pattern
|
||||
public static var STATE_FAILED = 2; // STATE : pattern is stopped and the player screwed up
|
||||
public static var STATE_CORRECT = 3; // STATE : pattern is stopped and the player got the last iteration correct
|
||||
public static var STATE_STOPPED = 4; // STATE : pattern is just stopped w/ no further info
|
||||
public static var STATE_COMPLETE = 5; // STATE : pattern is stopped because the player has finished all iterations of this pattern
|
||||
public var score:Number; // Score currently built up in this pattern
|
||||
protected var maxSize:Number; // Maximum length of the pattern
|
||||
public var patternPowerups:Array; // array of powerups assigned to any given button on this pattern
|
||||
protected var scoreMultiplier:Number; // Set by powerup, the multiplier for current score (default x1)
|
||||
protected var clearDecrement:Number; // Set by powerup, defines how quickly the pattern's timer runs
|
||||
protected var progressLights:Array; // An array of bitmaps equal in length to the pattern; all the lights up to this.curIndex will be green, the rest are red
|
||||
protected var level:Number; // The level of pattern which this is (mainly used for calculating pattern length, could probly be scrapped)
|
||||
protected var difficulty:Number; // The difficulty of the pattern (used in calculating timer speed)
|
||||
|
||||
/*
|
||||
* Pattern()
|
||||
*
|
||||
* Default constructor
|
||||
*
|
||||
* arguments:
|
||||
* @levelNumber:Number, the level number for which this pattern is being made
|
||||
* @simon:Mastermind, the Mastermind object to which this pattern is to be applied (default null)
|
||||
* @difficulty:Number, the difficulty level for this pattern (default 1)
|
||||
*
|
||||
* Returns: Pattern
|
||||
*/
|
||||
public function Pattern(levelNumber:Number, simon:Mastermind = null, difficulty:Number = 1)
|
||||
{
|
||||
this.state = 0;
|
||||
this.simon = simon;
|
||||
this.level = levelNumber;
|
||||
this.difficulty = difficulty;
|
||||
this.curIndex = -1;
|
||||
this.maxSize = 2+levelNumber; // smallest pattern will never be less than 3 lights total
|
||||
this.pattern = new Array();
|
||||
this.patternPowerups = new Array();
|
||||
this.progressLights = new Array();
|
||||
this.patternTimer = null;
|
||||
this.delay = 1000;
|
||||
this.playCount = 0;
|
||||
this.clearTime = 0;
|
||||
this.score = 0;
|
||||
this.scoreMultiplier = 1;
|
||||
this.clearDecrement = 0;
|
||||
this.patternTimer = new Timer(0);
|
||||
|
||||
this.addEventListener(PowerupEvent.USED_POWERUP, this.onUsedPowerup);
|
||||
|
||||
var preloader:Preloader = Preloader.getInstance();
|
||||
var newLight:Bitmap;
|
||||
// populate all the red lights for this pattern that will turn green as the player goes on
|
||||
for ( var i:Number = 0; i < this.maxSize ; i++ ) {
|
||||
newLight = preloader.getBitmap("gfx_progress_red");
|
||||
newLight.x = 0;
|
||||
newLight.y = i*16;
|
||||
if ( i > 15 ) {
|
||||
newLight.x += 20;
|
||||
newLight.y = (i-15)*16;
|
||||
}
|
||||
this.progressLights.push(newLight);
|
||||
this.addChild(newLight);
|
||||
}
|
||||
this.complexify();
|
||||
}
|
||||
|
||||
/*
|
||||
* patternLength()
|
||||
*
|
||||
* Just a getter for the length of the pattern
|
||||
*
|
||||
* arguments : none
|
||||
*
|
||||
* Returns : Number
|
||||
*/
|
||||
public function patternLength():Number
|
||||
{
|
||||
return this.pattern.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* forceState()
|
||||
*
|
||||
* Forces a given state onto the pattern
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function forceState(state:Number)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/*
|
||||
* complexify()
|
||||
*
|
||||
* This function adds another element to the pattern, so that it becomes a longer pattern, up until the maximum length of the pattern
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function complexify()
|
||||
{
|
||||
// we're complete if we're beyond the maximum size
|
||||
if ( this.pattern.length >= this.maxSize ) {
|
||||
this.stop();
|
||||
this.state = Pattern.STATE_COMPLETE;
|
||||
return null;
|
||||
}
|
||||
// reset the score multiplier and such 'cause complexify only gets called at the end of a round
|
||||
this.scoreMultiplier = 1;
|
||||
this.state = Pattern.STATE_STOPPED;
|
||||
this.stop(); // -- wtf why did I call stop on myself? ...
|
||||
var newcolor = (Math.round(int(Math.random()*4)));
|
||||
this.pattern.push(newcolor);
|
||||
// create a new powerup ~20% of the time that complexify is ran
|
||||
if ( Math.random() < 0.20 ) {
|
||||
var powerup = new Powerup();
|
||||
powerup.pType = (Math.round(int(Math.random()*Powerup.PTYPE_MAXVALUE)));
|
||||
powerup.imgHandle = Powerup.POWERUP_IMAGES[powerup.pType];
|
||||
powerup.sndHandle = Powerup.POWERUP_SOUNDS[powerup.pType];
|
||||
this.patternPowerups.push(powerup);
|
||||
} else {
|
||||
this.patternPowerups.push(null);
|
||||
}
|
||||
this.clearTime = 2000 * ( this.pattern.length );
|
||||
}
|
||||
|
||||
/*
|
||||
* play(lightSimon)
|
||||
*
|
||||
* This function tells the pattern to start playback in one of two modes; demo, or running. Demo mode
|
||||
* just has the pattern playing itself back via the lights on the Mastermind. The running mode doesn't
|
||||
* do any playback, it just checks logic.
|
||||
*
|
||||
* arguments:
|
||||
* @lightSimon:Boolean, set this to True to run in Demo mode (default false)
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function play(lightSimon:Boolean = false)
|
||||
{
|
||||
if ( this.patternTimer ) {
|
||||
this.patternTimer.reset()
|
||||
} else {
|
||||
this.patternTimer = new Timer( this.delay );
|
||||
}
|
||||
if ( lightSimon ){
|
||||
this.state = Pattern.STATE_DEMO;
|
||||
this.patternTimer.delay = 1000;
|
||||
this.patternTimer.addEventListener(TimerEvent.TIMER, this.onDemoTimer);
|
||||
} else {
|
||||
this.state = Pattern.STATE_RUNNING;
|
||||
this.patternTimer.delay = 25;
|
||||
this.clearDecrement = this.patternTimer.delay + (this.level*(this.difficulty));
|
||||
this.patternTimer.addEventListener(TimerEvent.TIMER, this.onRunningTimer);
|
||||
}
|
||||
this.patternTimer.start();
|
||||
this.playCount += 1;
|
||||
this.curIndex = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* stop()
|
||||
*
|
||||
* Stop all logic/running status on the pattern
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
if ( this.patternTimer ) {
|
||||
this.patternTimer.removeEventListener(TimerEvent.TIMER, this.onDemoTimer);
|
||||
this.patternTimer.removeEventListener(TimerEvent.TIMER, this.onRunningTimer);
|
||||
}
|
||||
this.curIndex = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* getIndex()
|
||||
*
|
||||
* Gets the current value is curIndex
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
|
||||
public function getIndex()
|
||||
{
|
||||
return this.curIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* getActive()
|
||||
*
|
||||
* OBSOLETE - gets the currecntly active color. This isn't as useful since the input checking method changed around v0.12.
|
||||
*
|
||||
* arguments: none
|
||||
* Returns : Number, -1 on failure, >= 0 on success
|
||||
*/
|
||||
public function getActive()
|
||||
{
|
||||
if ( (this.curIndex < this.pattern.length) && (this.curIndex >= 0) ) {
|
||||
return this.pattern[this.curIndex];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* resetLights()
|
||||
*
|
||||
* This function makes sure the ratio of red:green lights in the progress lights is correct
|
||||
* according to the value of curIndex
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function resetLights()
|
||||
{
|
||||
var preloader:Preloader = Preloader.getInstance();
|
||||
var newLight:Bitmap;
|
||||
for ( var i:Number = 0; i <= this.curIndex ; i++ ) {
|
||||
// remove any existing red lights and replace them with green lights
|
||||
// if they're at an index < curIndex
|
||||
this.removeChild(this.progressLights[i]);
|
||||
newLight = preloader.getBitmap("gfx_progress_green");
|
||||
newLight.x = this.progressLights[i].x;
|
||||
newLight.y = this.progressLights[i].y;
|
||||
this.progressLights[i] = newLight;
|
||||
this.addChild(this.progressLights[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* colorActive(color)
|
||||
*
|
||||
* Checks to see if the given color is the one currently active on the pattern.
|
||||
* Also updates the current index, modifies state, etc, depending on the result.
|
||||
*
|
||||
* arguments:
|
||||
* @color:Number, the Pattern.COLOR_XXX color you want checked
|
||||
*
|
||||
* Returns: Boolean (Always returns false on a stopped pattern)
|
||||
*/
|
||||
public function colorActive(color:Number):Boolean
|
||||
{
|
||||
if ( this.curIndex == -1 ) {
|
||||
return false;
|
||||
}
|
||||
if ( (this.curIndex < this.pattern.length) && (this.pattern[this.curIndex] == color) ) {
|
||||
// dispatch a PowerupEvent if there is a powerup in this spot at the pattern
|
||||
if ( this.patternPowerups[this.curIndex] != null ) {
|
||||
this.dispatchEvent(new PowerupEvent(PowerupEvent.GOT_POWERUP, this.patternPowerups[this.curIndex]));
|
||||
this.patternPowerups[this.curIndex] = null;
|
||||
}
|
||||
this.resetLights();
|
||||
this.curIndex += 1;
|
||||
this.score += 5;
|
||||
if ( this.curIndex >= this.pattern.length ) {
|
||||
this.curIndex = -1;
|
||||
this.state = Pattern.STATE_CORRECT;
|
||||
this.stop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
this.state = Pattern.STATE_FAILED;
|
||||
this.stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* onRunningTimer(evt)
|
||||
*
|
||||
* Fires along w/ the runningTimer to check pattern logic
|
||||
*
|
||||
* arguments:
|
||||
* @evt:Event, event firing this function
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
|
||||
public function onRunningTimer(evt:TimerEvent)
|
||||
{
|
||||
if ( (!evt) || (evt.target != this.patternTimer) )
|
||||
return;
|
||||
this.clearTime -= this.clearDecrement;
|
||||
if ( this.clearTime < 0 ) {
|
||||
this.clearTime = 0;
|
||||
this.state = Pattern.STATE_FAILED;
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* onDemoTimer(evt)
|
||||
*
|
||||
* Runs every time the Demo timer fires, lighting the buttons in sequence at the right times
|
||||
*
|
||||
* arguments:
|
||||
* @evt:Event, the event firing this function
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
|
||||
public function onDemoTimer(evt:TimerEvent)
|
||||
{
|
||||
if ( (!evt) || (evt.target != this.patternTimer) || (!this.simon) )
|
||||
return;
|
||||
if ( this.curIndex >= this.pattern.length ) {
|
||||
this.state = Pattern.STATE_STOPPED;
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
this.simon.lightButton(this.pattern[curIndex], this.patternTimer.delay/2);
|
||||
this.curIndex += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* onUsedPowerup(evt)
|
||||
*
|
||||
* This function fires whenever a PowerupEvent filters down from the Mastermind, which originally
|
||||
* filtered up from the Player. It processes and applies the effects of any powerups used by the player.
|
||||
*
|
||||
* arguments:
|
||||
* @evt:PowerupEvent, the event firing this function
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function onUsedPowerup(evt:PowerupEvent)
|
||||
{
|
||||
var pwup:Powerup = evt.pwup;
|
||||
if ( pwup.pType == Powerup.PTYPE_FORGIVENESS ) {
|
||||
// we don't actually have to *do* anything with a forgiveness ...
|
||||
return;
|
||||
} else if ( pwup.pType == Powerup.PTYPE_SLOWDOWN ) {
|
||||
this.clearDecrement = 1;
|
||||
} else if ( pwup.pType == Powerup.PTYPE_SKIP ) {
|
||||
this.state = Pattern.STATE_CORRECT;
|
||||
this.stop();
|
||||
this.resetLights();
|
||||
} else if ( pwup.pType == Powerup.PTYPE_DOUBLE ) {
|
||||
this.scoreMultiplier = 2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
228
net/aklabs/demo/simonsays/Player.as
Executable file
228
net/aklabs/demo/simonsays/Player.as
Executable file
@@ -0,0 +1,228 @@
|
||||
package net.aklabs.demo.simonsays
|
||||
{
|
||||
import net.aklabs.demo.simonsays.PowerupEvent;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import net.aklabs.demo.simonsays.Preloader;
|
||||
import flash.display.Bitmap;
|
||||
|
||||
/*
|
||||
* Class Player
|
||||
*
|
||||
* This class represents the player in the game.
|
||||
*
|
||||
* The class has two displayable objects in it: the Player object itself,
|
||||
* and Player.lifeDisplay. The Player object displays the inventory (64 pixels high, up to (64*5) pixels wide)
|
||||
* The Player.lifeDisplay object displays the remaining number of lives (64 pixels high, up to 64*3 pixels wide)
|
||||
*
|
||||
*/
|
||||
public class Player extends Sprite {
|
||||
public var score:Number; // the player's current score
|
||||
public var lives:Number; // the number of lives the player currently has
|
||||
public var maxPattern:Number; // the largest pattern the player has completed
|
||||
public var inventory:Array; // the player's inventory
|
||||
public var lifeDisplay:Sprite; /* the parent sprite to which all the player life sprites are attached (number of remaining lives) ..
|
||||
we have this parenting the rest of the images, so the Game class can just add this single child object, rather than tracking
|
||||
and removing all the images in the individual lifeImages array */
|
||||
protected var lifeImages:Array; // an array of images holding all the images showing up in the player's life array
|
||||
protected var headExplosion;
|
||||
|
||||
/*
|
||||
* Player()
|
||||
*
|
||||
* Default constructor
|
||||
*
|
||||
* arguments : none
|
||||
*
|
||||
* Returns : none
|
||||
*/
|
||||
public function Player()
|
||||
{
|
||||
this.score = 0;
|
||||
this.lives = 3;
|
||||
this.maxPattern = 0;
|
||||
this.inventory = new Array();
|
||||
this.lifeDisplay = new Sprite();
|
||||
this.lifeImages = new Array();
|
||||
}
|
||||
|
||||
/*
|
||||
* addPowerup(pwup)
|
||||
*
|
||||
* Adds a new powerup to the player's inventory
|
||||
*
|
||||
* arguments:
|
||||
* @pwup:Powerup, the powerup to be added
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function addPowerup(pwup:Powerup)
|
||||
{
|
||||
if ( this.inventory.length >= 5 ) {
|
||||
return;
|
||||
}
|
||||
this.inventory.push(pwup);
|
||||
this.resetPowerupPositions();
|
||||
this.addChild(pwup);
|
||||
pwup.addEventListener(MouseEvent.MOUSE_UP, this.onPowerupClicked);
|
||||
}
|
||||
|
||||
/*
|
||||
* resetPowerupPositions()
|
||||
*
|
||||
* This function goes through the player's inventory and makes sure the positions line up (mostly) with the background graphic for their slot
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
protected function resetPowerupPositions()
|
||||
{
|
||||
for ( var i = 0; i < this.inventory.length ; i++ ) {
|
||||
var pwup:Powerup = this.inventory[i];
|
||||
pwup.x = 2+(70*i);
|
||||
pwup.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* die()
|
||||
*
|
||||
* This function is called whenever the player should die - lose a life
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function die()
|
||||
{
|
||||
// lose a life, and do it in style
|
||||
var preloader:Preloader = Preloader.getInstance();
|
||||
this.headExplosion = preloader.getMovieClip("movie_explosion");
|
||||
this.headExplosion.addEventListener(Event.ENTER_FRAME, this.stopExplosion);
|
||||
this.headExplosion.x = (this.lives * 64)-32;
|
||||
this.headExplosion.y = 32;
|
||||
this.lifeDisplay.addChild(this.headExplosion);
|
||||
this.headExplosion.play();
|
||||
preloader.playSound("sfx_explosion");
|
||||
this.lives -= 1;
|
||||
this.resetLifePositions();
|
||||
}
|
||||
|
||||
/*
|
||||
* stopExplosion(evt)
|
||||
*
|
||||
* This stops the head explosion animation from looping (much like Game.onNonLoopEnterFrame)
|
||||
*
|
||||
* arguments:
|
||||
* @evt:Event, the event firing this function
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function stopExplosion(evt:Event)
|
||||
{
|
||||
if ( evt.target.currentFrame == evt.target.totalFrames ) {
|
||||
this.headExplosion.stop();
|
||||
this.lifeDisplay.removeChild(this.headExplosion);
|
||||
this.headExplosion.removeEventListener(Event.ENTER_FRAME, this.stopExplosion);
|
||||
this.headExplosion = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* resetLifePositions()
|
||||
*
|
||||
* This function arranges the images representing the number of remaining lives the player has
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* returns : none
|
||||
*/
|
||||
public function resetLifePositions()
|
||||
{
|
||||
var i:Number = 0;
|
||||
var preloader:Preloader = Preloader.getInstance();
|
||||
if ( this.lifeImages.length < this.lives ) {
|
||||
for ( i = this.lifeImages.length; i < this.lives; i++ ) {
|
||||
var img:Bitmap = preloader.getBitmap("gfx_pwup_freelife");
|
||||
img.x = 64*i;
|
||||
img.y = 0;
|
||||
this.lifeImages.push(img);
|
||||
this.lifeDisplay.addChild(img);
|
||||
}
|
||||
} else {
|
||||
for ( var i = 0; i < this.lifeImages.length ; i++ ) {
|
||||
if ( i >= this.lives ) {
|
||||
this.lifeDisplay.removeChild(this.lifeImages[i]);
|
||||
this.lifeImages.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( var i = 0; i < this.lifeImages.length ; i++ ) {
|
||||
this.lifeImages[i].x = 64*i;
|
||||
this.lifeImages[i].y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* usePowerupAt(index)
|
||||
*
|
||||
* See if there is a powerup at index 'index' in the inventory, use it, fire off any sounds associated with it,
|
||||
* and dispatch a new PowerupEvent for it
|
||||
*
|
||||
* arguments:
|
||||
* @index:Number, the index in inventory from which the powerup should be drawn
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function usePowerupAt(index:Number)
|
||||
{
|
||||
if ( index < this.inventory.length ) {
|
||||
this.removeChild(this.inventory[index]);
|
||||
var preloader:Preloader = Preloader.getInstance();
|
||||
preloader.playSound(this.inventory[index].sndHandle);
|
||||
this.resetPowerupPositions();
|
||||
this.dispatchEvent(new PowerupEvent(PowerupEvent.USED_POWERUP, this.inventory[index]));
|
||||
this.inventory[index].removeEventListener(MouseEvent.MOUSE_UP, this.onPowerupClicked);
|
||||
this.inventory.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* onPowerupClicked(evt)
|
||||
*
|
||||
* This function is fired whenever the player clicks the mouse on a powerup owned by the player
|
||||
*
|
||||
* arguments:
|
||||
* @evt:MouseEvent, the event firing this function
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function onPowerupClicked(evt:MouseEvent)
|
||||
{
|
||||
for ( var i:Number = 0 ; i < this.inventory.length ; i++ ) {
|
||||
if ( this.inventory[i] == evt.target ) {
|
||||
this.usePowerupAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* clearInventory()
|
||||
*
|
||||
* Fairly obvious, this function just clears out the inventory
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function clearInventory()
|
||||
{
|
||||
for ( var i:Number = 0; i < this.inventory.length ; i++ ) {
|
||||
this.removeChild(this.inventory[i]);
|
||||
this.inventory.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
net/aklabs/demo/simonsays/Powerup.as
Executable file
29
net/aklabs/demo/simonsays/Powerup.as
Executable file
@@ -0,0 +1,29 @@
|
||||
package net.aklabs.demo.simonsays {
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import net.aklabs.demo.simonsays.PowerupEvent;
|
||||
|
||||
/*
|
||||
* Class Powerup
|
||||
*
|
||||
* This class just represents a powerup in the game.
|
||||
* This is more a data structure than a class, but I don't think
|
||||
* AS 3.0 has just bare structures. Silly ECMA language...
|
||||
*/
|
||||
public class Powerup extends Sprite
|
||||
{
|
||||
public static var PTYPE_SLOWDOWN:Number = 0; /* SLOWDOWN - Slows the pattern timer to a much lower rate */
|
||||
public static var PTYPE_FORGIVENESS:Number = 1; /* FORGIVENESS - If you have FORGIVENESSS in your inventory and you miss a pattern, it doesn't stop you */
|
||||
public static var PTYPE_SKIP:Number = 2; /* SKIP - Lets you "skip" a given pattern iteration, and you still get all the score for it. */
|
||||
public static var PTYPE_DOUBLE:Number = 3; /* DOUBLE - Score double points for the pattern on which you use this powerup. */
|
||||
public static var PTYPE_MAXVALUE:Number = 4;
|
||||
// POWERUP_IMAGES - these are the image handles (stored in an array where idx => PTYPE_XXX) for each of the powerup types
|
||||
public static var POWERUP_IMAGES = new Array("gfx_pwup_slowdown", "gfx_pwup_forgiveness", "gfx_pwup_exclamation", "gfx_pwup_pointdoubler");
|
||||
// POWERUP_SOUNDS - these are the sound handles (stored in an array where idx => PTYPE_XXX) for each of the powerup types
|
||||
public static var POWERUP_SOUNDS = new Array("sfx_slowdown", "sfx_forgiveness", "sfx_exclamation", "sfx_pointdoubler");
|
||||
public var imgHandle:String; // the handle for the image of this specific powerup
|
||||
public var sndHandle:String; // the handle for the sound of this specific powerup
|
||||
public var pType:Number; // the PTYPE_XXX of this powerup
|
||||
}
|
||||
}
|
||||
32
net/aklabs/demo/simonsays/PowerupEvent.as
Executable file
32
net/aklabs/demo/simonsays/PowerupEvent.as
Executable file
@@ -0,0 +1,32 @@
|
||||
package net.aklabs.demo.simonsays {
|
||||
import flash.events.Event;
|
||||
import net.aklabs.demo.simonsays.Powerup;
|
||||
|
||||
/*
|
||||
* Class PowerupEvent
|
||||
*
|
||||
* An event specifically made for actions taken regarding powerups
|
||||
*/
|
||||
public class PowerupEvent extends Event {
|
||||
public static var GOT_POWERUP:String = "SIMONSAYS_GOT_POWERUP"; // Type for events when a powerup was received
|
||||
public static var USED_POWERUP:String = "SIMONSAYS_USED_POWERUP"; // Type for events when a powerup was used
|
||||
public var pwup:Powerup; // the powerup (rather than the target) of this event
|
||||
|
||||
/*
|
||||
* PowerupEvent()
|
||||
*
|
||||
* Default Constructor
|
||||
*
|
||||
* arguments:
|
||||
* @evtType:String, the type of this event (GOT_POWERUP or USED_POWERUP)
|
||||
* @tgt:Powerup, the Powerup object that's being affected by this event
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function PowerupEvent(evtType:String, tgt:Powerup = null)
|
||||
{
|
||||
super(evtType);
|
||||
this.pwup = tgt;
|
||||
}
|
||||
}
|
||||
}
|
||||
529
net/aklabs/demo/simonsays/Preloader.as
Executable file
529
net/aklabs/demo/simonsays/Preloader.as
Executable file
@@ -0,0 +1,529 @@
|
||||
package net.aklabs.demo.simonsays {
|
||||
|
||||
import net.aklabs.demo.simonsays.LoadingObject;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.net.URLRequest;
|
||||
import flash.display.Loader;
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.Sprite;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFormat;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
import flash.media.Sound;
|
||||
import flash.display.MovieClip;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.events.SecurityErrorEvent;
|
||||
import flash.events.ProgressEvent;
|
||||
import flash.events.Event;
|
||||
|
||||
/*
|
||||
* Class Preloader
|
||||
*
|
||||
* This class is what loads and manages the cache of media assets for the game
|
||||
* This class is a singleton, which was annoyingly difficulty to implement in
|
||||
* Actionscript 3 because it doesn't support private constructors.
|
||||
*
|
||||
* Be careful subclassing this, because of the way the singleton mechanism was implemented,
|
||||
* it may break.
|
||||
*
|
||||
* This class can be added as a child asset, and it will display a pair of progress
|
||||
* bars as it loads all the assets. The top bar is the progress on the current file,
|
||||
* the bottom bar is the progress on the total set of assets. You don't have to display the
|
||||
* preloader, but if you do, make sure to load via the assets array, rather than calling loadImage()
|
||||
* and such manually, as the progress bars will act funky.
|
||||
*
|
||||
* When the preloader has loaded all of the assets, it will dispatch a COMPLETE event that should be handled
|
||||
* by whatever higher game class, as a signal that all assets are ready and cached.
|
||||
*/
|
||||
|
||||
public class Preloader extends Sprite {
|
||||
protected var objects:Dictionary; // this contains all loaded objects, keyed by their handle
|
||||
protected var loading_by_instance:Dictionary; // this contains the [handle, bytes read, bytes total] of all objects that are currently loading, keyed by their instance
|
||||
protected var loading_by_handle:Dictionary; // this contains the [instance, bytes read, bytes total] of all objects that are currently loading, keyed by their handle
|
||||
protected static var instance:Preloader = null; // the singleton instance
|
||||
protected var curAsset:Number; // the index of the asset (in the assets array) currently being loaded
|
||||
|
||||
protected var assets:Array; // the array of all the assets to be loaded
|
||||
/* format of the 'assets' array:
|
||||
[ ASSET_ARRAY, ASSET_ARRAY ...]
|
||||
|
||||
each ASSET_ARRAY is...
|
||||
|
||||
["images"|"sounds"|"movies", "TEXT HANDLE", "URI", "CLASS NAME"]
|
||||
|
||||
... The "images"|"sounds"|"movies" serves an obvious purpose; it says what kind of asset we're loading,
|
||||
as the mechanism for loading images/sounds/movies are different.
|
||||
|
||||
The TEXT HANDLE is a text handle that can be used when referencing this asset in the preloader
|
||||
|
||||
The URI is just that, the URI where this object can be found. Usual security restrictions apply.
|
||||
|
||||
The CLASS NAME is only important for exported SWF movies, and must equal whatever the class name is
|
||||
that you set for that SWF when telling Flash to export it for Actionscript. If this is wrong, or you
|
||||
don't export your SWFs for actionscript, you won't be able to instantiate new MovieClip/Sprites of them.
|
||||
*/
|
||||
|
||||
protected var loadingLabel:TextField; // just a text label that says "Please wait; loading"
|
||||
protected var progressSpinner:Array = new Array("-", "\\", "|", "/"); // an array of characters that creates a spinner for the loading label
|
||||
protected var progSpin:Number = 0; // the current index in the progressSpinner array
|
||||
protected var classDefs:Dictionary; // classDefs holds the class definitions for each of the given objects (if supplied), keyed by text handle
|
||||
protected var classNames:Dictionary; // classNames holds the name of the classes for each of the given objects (if supplied), keyed by text handle
|
||||
|
||||
/*
|
||||
* getInstance()
|
||||
*
|
||||
* Returns the instance of the singleton
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* Returns: Preloader
|
||||
*/
|
||||
public static function getInstance():Preloader
|
||||
{
|
||||
if ( Preloader.instance == null )
|
||||
Preloader.instance = new Preloader();
|
||||
return Preloader.instance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preloader(assets)
|
||||
*
|
||||
* Default constructor for Preloader
|
||||
*
|
||||
* arguments:
|
||||
* @assets:Array, the asset array to be loaded (default null)
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
public function Preloader(assets:Array = null)
|
||||
{
|
||||
if ( Preloader.instance != null )
|
||||
throw("Don't use (new Preloader()) directly, use Preloader.getInstance() to prevent duplication of this singleton class.");
|
||||
this.objects = new Dictionary();
|
||||
this.loading_by_instance = new Dictionary();
|
||||
this.loading_by_handle = new Dictionary();
|
||||
Preloader.instance = this;
|
||||
this.curAsset = 0;
|
||||
if ( assets != null)
|
||||
this.assets = assets;
|
||||
var labelFormat = new TextFormat();
|
||||
labelFormat.font = "Courier New";
|
||||
labelFormat.bold = false;
|
||||
labelFormat.color = 0xFFFFFF;
|
||||
labelFormat.size = 12;;
|
||||
this.loadingLabel = new TextField();
|
||||
this.loadingLabel.background = false;
|
||||
this.loadingLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
this.loadingLabel.defaultTextFormat = labelFormat;
|
||||
this.loadingLabel.text = "Please wait; loading |"
|
||||
this.loadingLabel.x = 0;
|
||||
this.loadingLabel.y = 0;
|
||||
this.addChild(loadingLabel);
|
||||
this.classDefs = new Dictionary();
|
||||
this.classNames = new Dictionary();
|
||||
}
|
||||
|
||||
/*
|
||||
* setAssets(assets)
|
||||
*
|
||||
* Set the asset array for the preloader
|
||||
*
|
||||
* arguments:
|
||||
* @assets:Array, the array of assets
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function setAssets(assets:Array)
|
||||
{
|
||||
this.assets = assets;
|
||||
}
|
||||
|
||||
/*
|
||||
* loadAssets()
|
||||
*
|
||||
* Start loading all the assets
|
||||
*
|
||||
* arguments: none
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function loadAssets()
|
||||
{
|
||||
this.onLoadComplete(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* getObject(handle)
|
||||
*
|
||||
* Get a generic Object referenced by the given handle
|
||||
*
|
||||
* argument:
|
||||
* @handle:String, the text handle of the object you want
|
||||
*
|
||||
* returns: object you want, or null
|
||||
*/
|
||||
public function getObject(handle:String)
|
||||
{
|
||||
if ( this.objects[handle] )
|
||||
return this.objects[handle];
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* getBitmap(handle:String)
|
||||
*
|
||||
* This function returns a CLONE of a Bitmap object in the preloader. Use this when
|
||||
* you want a bitmap that you can use in more than one place, e.g., more like a sprite.
|
||||
* All instances will reference the same bitmap data, however, so any modification to
|
||||
* the core bitmap data will show up in all instances.
|
||||
*
|
||||
* arguments:
|
||||
* @handle:String, the text handle reference for the bitmap you want
|
||||
*
|
||||
* returns Bitmap on success, null on failure
|
||||
*/
|
||||
|
||||
public function getBitmap(handle:String)
|
||||
{
|
||||
var obj = this.getObject(handle);
|
||||
if ( (obj) && (obj is Bitmap) ) {
|
||||
var bm = new Bitmap(obj.bitmapData);
|
||||
return bm;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* getBitmap(handle:String)
|
||||
*
|
||||
* This function returns a CLONE of a MovieClip object in the preloader. Use this when
|
||||
* you want a MovieClip that you can use in more than one place, e.g., more like a sprite.
|
||||
* All instances will reference the same frame data, however, so any modification to
|
||||
* the core frame data will show up in all instances.
|
||||
*
|
||||
* arguments:
|
||||
* @handle:String, the text handle reference for the bitmap you want
|
||||
*
|
||||
* returns MovieClip on success, null on failure
|
||||
*/
|
||||
public function getMovieClip(handle:String):MovieClip
|
||||
{
|
||||
var obj = this.getObject(handle);
|
||||
try {
|
||||
var clip:Class = this.classDefs[handle];
|
||||
if ( clip ) {
|
||||
return new clip();
|
||||
}
|
||||
} catch (error:Error) {
|
||||
trace(error);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* startObject(obj, handle)
|
||||
*
|
||||
* Start loading the given object with the given handle. Sets up event handling for notifications on the event while it loads.
|
||||
*
|
||||
* arguments:
|
||||
* @obj:Loader|Sound, either a Loader or a Sound object, referencing the object which has already had its URI set and begun loading
|
||||
* @handle:String, the text string by which this object should be referenced
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function startObject(obj, handle:String)
|
||||
{
|
||||
var toadd = obj;
|
||||
if ( obj is Loader ) {
|
||||
toadd = obj.contentLoaderInfo;
|
||||
}
|
||||
toadd.addEventListener(Event.COMPLETE, this.onLoadComplete);
|
||||
toadd.addEventListener(ProgressEvent.PROGRESS, this.onProgressUpdate);
|
||||
toadd.addEventListener(IOErrorEvent.IO_ERROR, this.onIOError);
|
||||
toadd.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityError);
|
||||
this.loading_by_instance[toadd] = new Array(handle, 0, 0);
|
||||
this.loading_by_handle[handle] = new Array(obj, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* stopObject(obj)
|
||||
*
|
||||
* Stops loading on a given object, unhooks all the event listeners, etc
|
||||
*
|
||||
* arguments:
|
||||
* @obj:Loader|Sound, the object on which loading should stop
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function stopObject(obj)
|
||||
{
|
||||
var obj_info = this.loading_by_instance[obj];
|
||||
obj.removeEventListener(Event.COMPLETE, this.onLoadComplete);
|
||||
obj.removeEventListener(ProgressEvent.PROGRESS, this.onProgressUpdate);
|
||||
obj.removeEventListener(IOErrorEvent.IO_ERROR, this.onIOError);
|
||||
obj.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityError);
|
||||
delete this.loading_by_handle[this.loading_by_instance[obj][0]];
|
||||
delete this.loading_by_instance[obj];
|
||||
}
|
||||
|
||||
/*
|
||||
* getObjectStatus(handle)
|
||||
*
|
||||
* Returns a LoadingObject object that describes the current loading status of the object you're inquiring about
|
||||
*
|
||||
* arguments:
|
||||
* @handle:String, the handle of the object you want to know about
|
||||
*
|
||||
* returns : LoadingObject
|
||||
*/
|
||||
public function getObjectStatus(handle:String):LoadingObject
|
||||
{
|
||||
var objStats = new LoadingObject();
|
||||
objStats.handle = handle;
|
||||
if ( this.objects[handle] ) {
|
||||
objStats.state = LoadingObject.STATE_READY;
|
||||
} else if ( this.loading_by_handle[handle] ) {
|
||||
objStats.state = LoadingObject.STATE_LOADING;
|
||||
objStats.bytesRead = this.loading_by_handle[handle][1];
|
||||
objStats.bytesTotal = this.loading_by_handle[handle][2];
|
||||
}
|
||||
return objStats;
|
||||
}
|
||||
|
||||
/*
|
||||
* loadImage(uri, handle)
|
||||
*
|
||||
* Start loading the image at the given URI with the given handle
|
||||
*
|
||||
* arguments:
|
||||
* @uri:String, the URI where the file lives
|
||||
* @handle:String, the handle for the object
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function loadImage(uri:String, handle:String)
|
||||
{
|
||||
var request:URLRequest = new URLRequest(uri);
|
||||
var img = new Loader();
|
||||
img.load(request);
|
||||
this.startObject(img, handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* loadMovie(uri, handle, className)
|
||||
*
|
||||
* Loads an external SWF object from URI and stores it as 'handle' and stores the class definition from it where the class name is className
|
||||
*
|
||||
* arguments:
|
||||
* @uri:String, the URI where the file lives
|
||||
* @handle:String, the handle for this object
|
||||
* @className:String, the name of the SWF class when exported for Actionscript
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function loadMovie(uri:String, handle:String, className:String)
|
||||
{
|
||||
var request:URLRequest = new URLRequest(uri);
|
||||
var movie = new Loader();
|
||||
movie.load(request);
|
||||
this.startObject(movie, handle);
|
||||
this.classNames[handle] = className;
|
||||
trace(this.classNames[handle]);
|
||||
}
|
||||
|
||||
/*
|
||||
* loadSound(uri, handle)
|
||||
*
|
||||
* Loads the given sound
|
||||
*
|
||||
* arguments:
|
||||
* @uri:String, the URI from which to load the sound
|
||||
* @handle:String, the handle to store the sound as
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
public function loadSound(uri:String, handle:String)
|
||||
{
|
||||
var request:URLRequest = new URLRequest(uri);
|
||||
var snd = new Sound();
|
||||
snd.load(request);
|
||||
this.startObject(snd, handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* playSound(handle)
|
||||
*
|
||||
* Locates the sound associated with the given handle, and plays it
|
||||
*
|
||||
* arguments:
|
||||
* @handle:String, the text handle for the sound you want
|
||||
*
|
||||
* returns: Boolean (true on success, false on error)
|
||||
*/
|
||||
public function playSound(handle:String):Boolean
|
||||
{
|
||||
var snd = this.getObject(handle);
|
||||
if ( !snd )
|
||||
return false;
|
||||
snd.play(); // we don't care about the channel it returns
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* onIOError(evt)
|
||||
*
|
||||
* This function fires whenever there's an IO Error that prevents the object from finishing loading
|
||||
*
|
||||
* arguments:
|
||||
* @evt:IOErrorEvent, the event firing this function
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function onIOError(evt:IOErrorEvent)
|
||||
{
|
||||
var obj = evt.target;
|
||||
var obj_info = this.loading_by_instance[obj];
|
||||
var handle = obj_info[0];
|
||||
var read = obj_info[1];
|
||||
var total = obj_info[2];
|
||||
this.stopObject(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* onSecurityError(evt)
|
||||
*
|
||||
* This function fires whenever there's a security error that prevents the object from finishing loading
|
||||
*
|
||||
* arguments:
|
||||
* @evt:SecurityErrorEvent, the event firing this function
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function onSecurityError(evt:SecurityErrorEvent)
|
||||
{
|
||||
var obj = evt.target;
|
||||
var obj_info = this.loading_by_instance[obj];
|
||||
var handle = obj_info[0];
|
||||
var read = obj_info[1];
|
||||
var total = obj_info[2];
|
||||
this.stopObject(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* onProgressUpdate(evt)
|
||||
*
|
||||
* This function fires whenever there's a progress update on the object currently loading
|
||||
*
|
||||
* arguments:
|
||||
* @evt:ProgressEvent, the event firing this function
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function onProgressUpdate(evt:ProgressEvent)
|
||||
{
|
||||
var obj = evt.target;
|
||||
var handle = this.loading_by_instance[obj][0];
|
||||
this.loading_by_instance[obj][1] = this.loading_by_handle[handle][1] = evt.bytesLoaded;
|
||||
this.loading_by_instance[obj][2] = this.loading_by_handle[handle][2] = evt.bytesTotal;
|
||||
this.drawProgressMeters(evt);
|
||||
this.progSpin += 1;
|
||||
if ( this.progSpin >= this.progressSpinner.length ) {
|
||||
this.progSpin = 0;
|
||||
}
|
||||
this.loadingLabel.text = "Please wait; loading ... " + this.progressSpinner[this.progSpin];
|
||||
}
|
||||
|
||||
/*
|
||||
* onLoadComplete(evt)
|
||||
*
|
||||
* This function fires whenever a file finishes loading. You can call this, after setting the assets array, with a null event.
|
||||
* In such a case, the loading process will simply be started.
|
||||
*
|
||||
* arguments:
|
||||
* @evt:Event, the event firing this function (default null)
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function onLoadComplete(evt:Event = null)
|
||||
{
|
||||
if ( evt != null ) {
|
||||
var obj = evt.target;
|
||||
var handle = this.loading_by_instance[obj][0];
|
||||
if ( obj is LoaderInfo ) {
|
||||
this.objects[handle] = obj.content;
|
||||
trace(this.classNames[handle]);
|
||||
if ( (this.classNames[handle]) && (this.classNames[handle] != "") )
|
||||
this.classDefs[handle] = obj.applicationDomain.getDefinition(this.classNames[handle]);
|
||||
else
|
||||
this.classDefs[handle] = null;
|
||||
} else
|
||||
this.objects[handle] = obj
|
||||
this.stopObject(obj);
|
||||
this.curAsset += 1;
|
||||
}
|
||||
if ( this.curAsset < this.assets.length ) {
|
||||
var asset = this.assets[this.curAsset];
|
||||
var asset_stat = this.getObjectStatus(asset[1]);
|
||||
if ( asset_stat.state == LoadingObject.STATE_NOTFOUND ) {
|
||||
if ( asset[0] == "sounds" ){
|
||||
this.loadSound(asset[2], asset[1]);
|
||||
} else if ( asset[0] == "images" ) {
|
||||
this.loadImage(asset[2], asset[1]);
|
||||
} else if ( asset[0] == "movies" ) {
|
||||
this.loadMovie(asset[2], asset[1], asset[3]);
|
||||
}
|
||||
}
|
||||
} else if ( this.curAsset >= this.assets.length ) {
|
||||
var evt = new Event(Event.COMPLETE);
|
||||
this.dispatchEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* drawProgressMeters(evt)
|
||||
*
|
||||
* This function redraws the visible progress meters; it is generally called from inside of onProgressUpdate.
|
||||
* It isn't fired by a timer, but it does need to have the event passed in to it so it can access the bytes read, etc.
|
||||
*
|
||||
* arguments:
|
||||
* @evt:ProgressEvent, the event firing this function (default null)
|
||||
*
|
||||
* returns: none
|
||||
*/
|
||||
protected function drawProgressMeters(evt:ProgressEvent)
|
||||
{
|
||||
this.graphics.clear();
|
||||
// draw the file progress meter
|
||||
// white box
|
||||
this.graphics.lineStyle(1,0xFFFFFF);
|
||||
this.graphics.beginFill(0xFFFFFF);
|
||||
this.graphics.drawRoundRect(60, 30, 200, 15, 5);
|
||||
this.graphics.endFill();
|
||||
// blue bar
|
||||
this.graphics.lineStyle(1,0x6E6BF4);
|
||||
this.graphics.beginFill(0x6E6BF4);
|
||||
this.graphics.drawRoundRect(60, 30, 200*(evt.bytesLoaded/evt.bytesTotal), 15, 5);
|
||||
this.graphics.endFill();
|
||||
// red box
|
||||
this.graphics.lineStyle(3, 0xAC2626);
|
||||
this.graphics.drawRoundRect(60, 30, 200, 15, 5);
|
||||
// draw the total progress meter
|
||||
// white box
|
||||
this.graphics.lineStyle(1,0xFFFFFF);
|
||||
this.graphics.beginFill(0xFFFFFF);
|
||||
this.graphics.drawRoundRect(60, 60, 200, 15, 5);
|
||||
this.graphics.endFill();
|
||||
// blue bar
|
||||
this.graphics.lineStyle(1,0x6E6BF4);
|
||||
this.graphics.beginFill(0x6E6BF4);
|
||||
this.graphics.drawRoundRect(60, 60, 200*(this.curAsset/this.assets.length), 15, 5);
|
||||
this.graphics.endFill();
|
||||
// red box
|
||||
this.graphics.lineStyle(3, 0xAC2626);
|
||||
this.graphics.drawRoundRect(60, 60, 200, 15, 5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
123
net/aklabs/demo/simonsays/SimonButton.as
Executable file
123
net/aklabs/demo/simonsays/SimonButton.as
Executable file
@@ -0,0 +1,123 @@
|
||||
package net.aklabs.demo.simonsays {
|
||||
|
||||
import flash.events.MouseEvent;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.Sprite;
|
||||
|
||||
/*
|
||||
* class SimonButton
|
||||
*
|
||||
* This is just a custom button class that is pixel-accurate, because the Mastermin/Simon Says
|
||||
* buttons are an extremely odd shape, so I needed something that could detect mouse hits in/
|
||||
* outside of the alpha color areas.
|
||||
*
|
||||
* Most of this class is really self explanatory, so I'm not going to bother documenting all of it. Only the parts that don't make immediate sense.
|
||||
*/
|
||||
public class SimonButton extends Sprite
|
||||
{
|
||||
protected var imgDown:Bitmap; // bitmap for when the button is pressed
|
||||
protected var imgUp:Bitmap; // bitmap for when the button is released
|
||||
protected var curImg:Bitmap; // the bitmap currently being displayed on the button
|
||||
protected var magicColor:Number; // the magic color (e.g. "magic pink"), if any (otherwise alpha is used for hit detection)
|
||||
|
||||
public function SimonButton(imgDown:Bitmap = null, imgUp:Bitmap = null, magicColor = 0x00000000)
|
||||
{
|
||||
super();
|
||||
this.imgDown = imgDown;
|
||||
this.imgUp = imgUp;
|
||||
this.curImg = null;
|
||||
this.magicColor = magicColor;
|
||||
this.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseDown);
|
||||
this.addEventListener(MouseEvent.MOUSE_UP, this.onMouseUp);
|
||||
this.addEventListener(MouseEvent.CLICK, this.onMouseClick);
|
||||
}
|
||||
|
||||
public function setMagicColor(color:Number)
|
||||
{
|
||||
this.magicColor = color;
|
||||
}
|
||||
|
||||
public function setBtnDown(obj:Bitmap)
|
||||
{
|
||||
if ( obj ) {
|
||||
this.imgDown = obj;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBtnUp(obj:Bitmap)
|
||||
{
|
||||
if ( obj ) {
|
||||
this.imgUp = obj;
|
||||
}
|
||||
}
|
||||
|
||||
public function onMouseDown(obj:MouseEvent)
|
||||
{
|
||||
if ( (obj) && (! this.hitTestPoint(obj.localX, obj.localY)) ) {
|
||||
obj.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
if ( this.curImg ) {
|
||||
this.removeChild(this.curImg);
|
||||
}
|
||||
if ( this.imgDown ) {
|
||||
this.addChild(this.imgDown);
|
||||
this.curImg = this.imgDown;
|
||||
}
|
||||
}
|
||||
|
||||
public function onMouseUp(obj:MouseEvent)
|
||||
{
|
||||
if ( (obj) && (!this.hitTestPoint(obj.localX, obj.localY)) ) {
|
||||
obj.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
if ( this.curImg ) {
|
||||
this.removeChild(this.curImg);
|
||||
}
|
||||
if ( this.imgUp ) {
|
||||
this.addChild(this.imgUp);
|
||||
this.curImg = this.imgUp;
|
||||
}
|
||||
}
|
||||
|
||||
public function onMouseClick(obj:MouseEvent)
|
||||
{
|
||||
if ( ! this.hitTestPoint(obj.localX, obj.localY) ) {
|
||||
obj.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* hitTestPoint(x, y, shapeFlag)
|
||||
*
|
||||
* An overriden version of hitTestPoint that is pixel-accurate. If the value at (x, y) is either A: of the value
|
||||
* in the "magic color", or B: containing an alpha value of zero, then the hit is POSITIVE. Otherwise it is false.
|
||||
*
|
||||
* arguments:
|
||||
* @x:Number, the X location of the hit relative to the origin of the object
|
||||
* @y:Number, the Y location of the hit relative to the origin of the object
|
||||
* @shapeFlag:Boolean, not used, just here for compatibility
|
||||
*
|
||||
* returns: Boolean (true if the hit is positive, false if it's negative)
|
||||
*/
|
||||
public override function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean
|
||||
{
|
||||
var color:uint;
|
||||
var rgb:uint;
|
||||
var a:uint;
|
||||
|
||||
if ( this.curImg && this.curImg.bitmapData ) {
|
||||
color = this.curImg.bitmapData.getPixel32(x, y);
|
||||
a = ((color >> 24) & 0xFF);
|
||||
rgb = (color & 0xFFFFFF00);
|
||||
//trace("Alpha : " + a + " RGB " + rgb + " magic color " + this.magicColor);
|
||||
if ( this.magicColor == rgb || a == 0 ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
net/aklabs/demo/simonsays/SimonSays.as
Executable file
81
net/aklabs/demo/simonsays/SimonSays.as
Executable file
@@ -0,0 +1,81 @@
|
||||
package net.aklabs.demo.simonsays
|
||||
{
|
||||
|
||||
import flash.utils.Timer;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import net.aklabs.demo.simonsays.Preloader;
|
||||
|
||||
public class Mastermind
|
||||
{
|
||||
protected var lightOutTimer:Timer;
|
||||
protected var lightBitmaps:Array;
|
||||
|
||||
public function Mastermind(preloader:Preloader, screenX:Number = 0, screenY:Number = 0)
|
||||
{
|
||||
// pass in a preloader so the class knows where to get its resources
|
||||
var lightPositions = new Array();
|
||||
// this array holds pairs of (x,y) coordinates at which to place the dark/light colored
|
||||
// Simon Says buttons, since they're meant to cover the existing buttons on the original graphic.
|
||||
// These are hard-coded; in a better implementation, they would come from an XML or would be
|
||||
// individual frames of an SWF which could be fired individually, etc. But this works.
|
||||
// array idx 0: Blue, 1: Green, 2: Red, 3: Yellow
|
||||
lightPositions.push( new Array(screenX + 216, screenY + 220)); // blue
|
||||
lightPositions.push( new Array(screenX + 22, screenY + 20)); // green
|
||||
lightPositions.push( new Array(screenX + 218, screenY + 20)); // red
|
||||
lightPositions.push( new Array(screenX + 22, screenY + 218)); // yellow
|
||||
// this array holds the light/dark bitmaps for the simon says buttons ... each idx is an array which holds (dark, light) bitmap objects
|
||||
// the indexes (0-3) correspond to the above for colors
|
||||
this.lightBitmaps = new Array();
|
||||
var fetchArray = new Array( new Array("gfx_btn_darkblue", "gfx_btn_lightblue"),
|
||||
new Array("gfx_btn_darkgreen", "gfx_btn_lightgreen"),
|
||||
new Array("gfx_btn_darkred", "gfx_btn_lightred"),
|
||||
new Array("gfx_btn_darkyellow", "gfx_btn_lightyellow") );
|
||||
for ( var i = 0; i < fetchArray.length ; i++ ) {
|
||||
light = preloader.getObject(fetchArray[i][0]);
|
||||
dark = preloader.getObject(fetchArray[i][1]);
|
||||
light.x = lightPositions[i][0];
|
||||
light.y = lightPositions[i][1];
|
||||
dark.x = lightPositions[i][0];
|
||||
dark.y = lightPositions[i][1];
|
||||
// we don't check the return values here because the preloader shouldn't even fire
|
||||
// the application up if resources are missing
|
||||
this.lightBitmaps.push(new Array(light, dark));
|
||||
// the dark buttons are always there, the lighted ones are just temporarily overlain on them for effect
|
||||
addChild(dark);
|
||||
}
|
||||
whole = preloader.getObject("gfx_background");
|
||||
whole.x = screenX;
|
||||
whole.y = screenY;
|
||||
addChild(whole);
|
||||
|
||||
this.lightOutTimer = Timer(1000);
|
||||
this.lightOutTimer.addEventListener(TimerEvent.TIMER, this.onTimer);
|
||||
this.lightOutTimer.start();
|
||||
}
|
||||
|
||||
public function flashAll(length:Number)
|
||||
{
|
||||
this.lightOutTimer.reset();
|
||||
this.lightOutTimer.delay(length);
|
||||
this.lightOutTimer.start();
|
||||
}
|
||||
|
||||
public function lightButton(btn:Number, activeTime:Number)
|
||||
{
|
||||
if ( btn < 4 ) {
|
||||
this.lightOutTimer.reset();
|
||||
this.lightOutTimer.delay(activeTime);
|
||||
addChild(this.lightBitmaps[btn][0]);
|
||||
this.lightOutTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
public function onTimer(evt:TimerEvent);
|
||||
{
|
||||
for ( i = 0 ; i < this.lightBitmaps.length ; i++ ){
|
||||
removeChild(this.lightBitmaps[i][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user