Trying to essentially push details through classes - actionscript-3

I am working on a game that creates three circles" red, green, and blue who have 3,2,1 health respectively. They get removed from the stage after their health reaches 0 and it is decremented by 1 per click. I am using a Main.mxml file then I have a Target.as file, as well as RedTarget.as, GreenTarget.as, and BlueTarget.as. My question is that I would like to set everything up in my Target.as file, then push the details such as color, health, and if they are dead or not through those functions. I am having trouble doing that though because I am not sure what I would need in the Target.as and then what I would need to code in each of the colored target files.
Here is my Target.as file:
package com.multiClicker {
//import the needed classes
import flash.display.Shape;
import flash.events.MouseEvent;
import spark.components.Image;
public class Target extends Image {
public function Target() {
//add event listeners
this.addEventListener(MouseEvent.CLICK, onClick);
}
//sets the hp of the target
public function hp():Number {
return hp;
}
//get function that returns false if alpha is <= 0
public function dead():Boolean {
if(alpha <= 0){
return false;
}
return true;
}
//subtracts one from targets HP when clicked
public function onClick(e:MouseEvent = null):void {
//subtracts one from hp each click
hp --;
if(hp <=0) {
this.addEventListener(onEnterFrame);
}
}
//subtracts .1 from the classes alpha
public function onEnterFrame():void{
this.alpha =- .1;
}
//draws the target
public function drawTarget(color):void {
var circle:Shape = new Shape();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(0,0,30);
}
}
}
and then my RedTarget.as file, which is the same as blue and green, except for that they are labeled as such in the variables:
package com.multiClicker {
import flash.events.MouseEvent;
public class RedTarget extends Target{
private var redHP:Number = 3;
private var redDead:Boolean = false;
private var redColor:String = "red";
public function RedTarget()
{
redHP = hp;
redDead = dead;
redColor = color;
//include the super function
super();
}
//subtracts one from targets HP when clicked
override public function onClick(e:MouseEvent=null):void {
super.onClick(e);
//push all to super
}
}
}
Any help on the issue would be great. I have been trying to figure it out throughout the day but have not figured it out.

Are you just asking how to pass variables in when you create the Target object?
public class Target extends Image {
public function Target(hp:Number, dead:Boolean, color:String) {
this.hp = hp;
this.dead = dead;
this.color = color;
}
}
Then you instantiate each target like this:
var redTarget:Target = new Target(3, false, "red");
var greenTarget:Target = new Target(2, false, "green");
etc...

Related

Actionscript making intro of a game

I'm making a game in full classes. so the timeline is empty. But I want to use another scene for the game intro, after the intro, it will proceed to the main menu of the game which I have created. Anyone got an idea? I haven't found any since a week ago... I don't really know about how to operate scenes from code in classes. Please help. Thanks!
Here is the main code :
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class Main extends Sprite
{
public var field:Array;
//CALL EVERY CLASS
public var _money:Money = new Money();
public var _gold:Gold;
public var _hero:Hero;
public var _enemy:Enemy;
private var _pause:MovieClip = new Pause();
private var pauseLayer:MovieClip = new PauseLayer();
private var ts:TitleScreen;
public function Main():void
{
ts = new TitleScreen();
addChild(ts);
}
//GAME FUNCTION
public function onStage():void
{
_hero = new Hero(this);
_enemy = new Enemy(this);
_gold = new Gold(this);
setupField();
_gold.goldSet(stage);
_money.addText(stage);
_hero.displayHero(stage);
_enemy.displayEnemy(stage);
setPause();
_pause.addEventListener(MouseEvent.CLICK, pauseGame);
}
private function setPause():void
{
addChild(_pause);
_pause.x = 620;
_pause.y = 50;
_pause.buttonMode = true;
}
private function pauseGame (e:MouseEvent):void
{
stage.frameRate = 0;
addChild(pauseLayer);
pauseLayer.alpha = 0.5;
pauseLayer.parent.setChildIndex(pauseLayer,numChildren-1);
}
//SET UP FIELD ARRAY
private function setupField():void
{
var fieldSprite:Sprite=new Sprite();
addChild(fieldSprite);
fieldSprite.graphics.lineStyle(4);
field=new Array();
for (var a:int=0; a<6; a++)
{
field[a]=new Array();
for (var b:int=0; b<10; b++)
{
field[a][b]=0;
}
}
//DRAW FIELD
for (var i:int=0; i<5; i++)
{
for (var j:int=0; j<9; j++)
{
fieldSprite.graphics.drawRect(75+65*j,50+75*i,65,75);
}
}
}
}
}
Titlescreen class :
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.Sprite;
public class TitleScreen extends Sprite
{
private var playBtn:MovieClip = new Resume();
public function TitleScreen()
{
playBtn.x = 50;
playBtn.y = 50;
playBtn.addEventListener(MouseEvent.CLICK, Play);
}
private function Play(e:MouseEvent):void
{
trace("a");
}
}
}
The most simple way would be using wrapper Sprites to hold each set of objects you probably want to be available as whole, say main menu, upgrades, storyline, etc etc. Then you just shift them in and out of display list to display corresponding "scene" with your Main class responsible of transition flow. But to do this you need to shift your game core functionality out of Main class into say Game class. That's how I have done the same thing in my game:
public class Main extends MovieClip {
private var so:SharedObject;
private var ui:UserInterface;
private var ts:TitleScreen;
private function init(e:Event = null):void
{
ui = new UserInterface();
ts = new TitleScreen();
ts.newButtonClicked = newGame;
ts.loadButtonClicked = loadGame;
ui.gotoMapBehavior = wentToMap;
addChild(ts);
}
Here, UserInterface is a class that has gaming logic inside, and TitleScreen is a main menu class. The functions are callbacks in Main:
private function newGame():void {
removeChild(ts); // hide title
if (!contains(ui)) addChild(ui);
SoundManager.playMusic(SoundManager.MUSIC_LEVELSELECT);
}
private function loadGame():void {
newGame();
ui.loadBattle(); // this should make UI load the battle from shared object (either supplied or received by itself)
}
private function wentToMap():void {
// we have just executed "go to map" from UI
removeChild(ui);
addChild(ts);
checkSO();
SoundManager.playMusic(SoundManager.MUSIC_INTRO);
}
The actual gaming logic does not interact with Main at all, except for shared object which is common for the entire project, but the link is received normally via SharedObject.getLocal(someName). The code is ugly, but could do for starters.
Save your game as SWF and make another project with timeline-animated intro. When the intro ends, make your project to load your game. Loader class can load other swf files. So, you don't need to edit your game classes.

Actionscript 3, adding an audio slider to my game

so I've really been struggling trying to add an audio slider to my game the last couple days and I've about had it, so, let me preface this by saying I have tried EXTREMELY hard and I would love to fully understand the solution, but at this point I really just want the solution, so the more specific you can be the better.
I've thought of a number of approaches, but my actionscript skills have been too faulty to pull any of them off. Let me explain my setup a bit. I have a fully functional class that is an audio slider. It plays music, slides, does everything perfect. Now, I'm sticking it in my document class. I thought it was easiest to call this function right at the very beginning (as my title screen shows up), EVEN THOUGH I don't want music to be playing right now at the title screen. So I thought I would call it, then just simply not play the music yet. So now I have it called from my document class. Now, I want to be able to click on the options button and then addChild the audio slider. I have actually accomplished this and it works. Finally....the hard part. I want to click the play game button and then have the music start playing WHILE BEING LINKED to the options slider which has the possibility of already being moved. Really...just a standard audio slider.
I'm really stuck on linking the options screen audio slider to the music actually playing in the game. I thought I would call the Volume() function (my audio slider), and then once my playscreen starts up, call it again and then just run a method of the Volume() class from within my playscreen class. This seems to lead to problems though...and this is where I lose it. By calling the Volume() class again, am I totally reinstating my audio? Like does this mean that I'm erasing everything I have done with my audio slider in the options panel? It seems to be...because it just starts playing at the default value.
So here's some detailed code of what I'm doing. I was thinking of using navigation events, but like I said, I'm not the greatest flash programmer yet and when I tried using them before I ran into trouble. Here are my main concerns in the code.
1) Calling new_Volume in my playScreen class (called SimpleMenuMain). Does this wipe out everything I've done in my document class when I called Volume()?
2) Towards the end of the Volume() class, I made a stopMusic function. Whenever I call it from my document class, it only works if I have not yet pressed play game, further leading me to believe I'm erasing whatever I do in the options panel before pressing play game.
3) Should I be using navigation events (custom events)? If so, how exactly do I do it? I understand how to use them in general (I've already used 5 in this game), but all of my navigation events go to my document class, so I'm guessing there's some subtlety with them I'm not quite understanding. I have a custom events class..I'll post that as well.
Thank you for all the help =) this has been killing me. I will wittle down these classes to the relavent info.
Document Class
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.ProgressEvent;
public class SMGDocClass extends MovieClip
{
public var playScreen:SimpleMenuMain;
public var titleScreen:TitleScreen;
public var gameOver:GameOver;
public var loadingProgress:LoadingProgress;
public var optionScreen:OptionScreen;
public var new_Volume:Volume;
public function SMGDocClass()
{
loadingProgress = new LoadingProgress();
loadingProgress.x = 0;
loadingProgress.y = 0;
addChild( loadingProgress );
loaderInfo.addEventListener( Event.COMPLETE, onCompletelyDownloaded,false,0,true );
loaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgressMade,false,0,true );
}
public function showTitleScreen():void
{
titleScreen = new TitleScreen();
titleScreen.addEventListener(NavigationEvent.START,onRequestStart,false,0,true);
titleScreen.addEventListener(NavigationEvent.OPTIONS,onRequestOptions,false,0,true);
titleScreen.x = 0;
titleScreen.y = 0;
addChild(titleScreen);
removeChild(loadingProgress);
new_Volume = new Volume();
new_Volume.stopMusic();
stage.focus = playScreen;
stage.stageFocusRect = false;
}
public function onStickman1Death(stickman1Event:Stickman1Event):void
{
var finalScore:Number = playScreen.getFinalScore();
var finalClockTime:Number = playScreen.getFinalClockTime();
gameOver = new GameOver();
gameOver.addEventListener(NavigationEvent.RESTART,onRequestRestart,false,0,true);
gameOver.addEventListener(NavigationEvent.MAINMENU,onRequestMainMenu,false,0,true);
gameOver.x = 5;
gameOver.y = 6;
gameOver.setFinalScore( finalScore );
gameOver.setFinalClockTime( finalClockTime );
addChild(gameOver);
new_Volume.stopMusic();
removeChild(playScreen);
playScreen = null;
}
public function onRequestStart( navigationEvent:NavigationEvent ):void
{
playScreen = new SimpleMenuMain();
playScreen.addEventListener( Stickman1Event.DEAD, onStickman1Death,false,0,true );
playScreen.x = 0;
playScreen.y = 0;
addChild( playScreen );
dispatchEvent(new Stickman1Event(Stickman1Event.DEAD));
removeChild(titleScreen);
titleScreen = null;
stage.focus = playScreen;
stage.stageFocusRect = false;
}
public function restartGame():void
{
playScreen = new SimpleMenuMain();
playScreen.addEventListener(Stickman1Event.DEAD, onStickman1Death,false,0,true);
playScreen.x = 0;
playScreen.y = 0;
addChild(playScreen);
removeChild(gameOver);
gameOver = null;
}
public function onRequestMainMenu( navigationEvent:NavigationEvent):void
{
titleScreen = new TitleScreen();
titleScreen.addEventListener(NavigationEvent.START,onRequestStart,false,0,true);
titleScreen.addEventListener(NavigationEvent.OPTIONS,onRequestOptions,false,0,true);
titleScreen.x = 0;
titleScreen.y = 0;
while(numChildren > 0)
{
removeChildAt(0);
}
addChild(titleScreen);
stage.focus = playScreen;
stage.stageFocusRect = false;
}
public function onCompletelyDownloaded( event:Event ):void
{
gotoAndStop(3);
showTitleScreen();
}
public function onProgressMade( progressEvent:ProgressEvent ):void
{
loadingProgress.setValue( Math.floor( 100 * loaderInfo.bytesLoaded / loaderInfo.bytesTotal ) );
}
public function onRequestOptions(navigationEvent:NavigationEvent):void
{
optionScreen = new OptionScreen();
optionScreen.addEventListener(NavigationEvent.MAINMENU,onRequestMainMenu,false,0,true);
optionScreen.x = 0;
optionScreen.y = 0;
addChild(optionScreen);
removeChild(titleScreen);
}
}
}
Play Screen Class
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Mouse;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.media.SoundChannel;
public class SimpleMenuMain extends MovieClip {
public var gameTimer:Timer;
public var stickman1:Stickman1;
public var new_Volume:Volume;
public function SimpleMenuMain() {
currentLevelData = new LevelData( 1 );
setBackgroundImage();
new_Volume = new Volume();
gameTimer = new Timer(25);
gameTimer.addEventListener(TimerEvent.TIMER, onTick, false, 0, true);
gameTimer.start();
addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
}
public function onAddToStage(event:Event):void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPress,false,0,true);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyRelease,false,0,true);
}
public function onTick(timerEvent:TimerEvent):void
{
var stickman1HasBeenHit:Boolean = false;
var i:int = army1.length - 1;
var enemy1:Enemy1;
while ( i > -1 )
{
enemy1 = army1[i];
if (enemySpeed == 1)
{
enemy1.moveABit(3,-1.5);
}
if (enemySpeed == 2)
{
enemy1.moveABit(3.6,-1.8);
}
if ( PixelPerfectCollisionDetection.isColliding( stickman1, enemy1, this, true ) )
{
getFinalScore();
gameTimer.stop();
bgmSoundChannel.stop();
stickman1HasBeenHit = true;
}
if ( enemy1.y > 400 )
{
removeChild( enemy1 );
army1.splice( i, 1 );
}
i = i - 1;
}
var i:int = army2.length - 1;
var enemy2:Enemy2;
while ( i > -1 )
{
enemy2 = army2[i];
if (enemySpeed2 == 1)
{
enemy2.moveABit(6,-3);
}
if (PixelPerfectCollisionDetection.isColliding(stickman1, enemy2, this, true ) )
{
gameTimer.stop();
bgmSoundChannel.stop();
stickman1HasBeenHit = true;
}
if ( enemy2.y > 400 )
{
removeChild( enemy2 );
army2.splice( i, 1 );
}
i = i - 1;
}
if (stickman1HasBeenHit)
{
dispatchEvent(new Stickman1Event(Stickman1Event.DEAD));
}
}
}
Volume Class
package {
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.net.URLRequest;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.geom.Rectangle;
public class Volume extends Sprite {
public var snd:Sound = new Sound();
public var channel:SoundChannel = new SoundChannel();
//URLRequest=new URLRequest("solitude.wav");
//Make sure you pass URLRequest an audio file on your computer.
public var req:BackgroundMusic = new BackgroundMusic();
public var boundary:Rectangle;
public var sprite:Sprite;
public var slider:Sprite;
public var xPos:Number;
public var yPos:Number;
public var vol:Number;
/*
Our request is loaded into the sound object and plays through
our channel. Volume is initially set at 50% and passed as a
transformation to our our channels soundTransform property
(a fancy way of saying volume). The init() function is called.
*/
public function Volume() {
this.addEventListener(Event.ADDED_TO_STAGE, onStage,false,0,true);
startMusic();
}
/*
The init function creates and draws a rectangle and circle
to the stage and centers them based on the height and
width of the stage. In addition, a rectangle object is
created to 'contain' the sliding circle, like an imaginary box.
We pass -100 as the x value because it is added relative
to our sprite. If we set its x value at 0, or the sprites default x
value,the boundary would stop and start at the slider sprite. Change
-100 to 0 in the rectangle object to get a better idea of its use.
*/
public function onStage(e:Event):void
{
//We remove it immediately so that it doesn't get called multiple times
//As the instance is added to the display list tree
this.removeEventListener(Event.ADDED_TO_STAGE, onStage);
xPos = 320;
yPos = 132;
/* Now that we have a reference to the stage, let's go ahead and create our slider */
init();
}
public function init():void {
sprite = new Sprite();
channel.stop();
sprite.graphics.beginFill(0x999999);
sprite.graphics.drawRect(xPos,yPos,100,5);
sprite.graphics.endFill();
addChild(sprite);
sprite.x-=sprite.width/2;
slider = new Sprite();
slider.graphics.beginFill(0xFF0000);
slider.graphics.drawCircle(xPos+50,yPos, 15);
slider.graphics.endFill();
addChild(slider);
slider.addEventListener(MouseEvent.MOUSE_DOWN, dragSlider);
stage.addEventListener(MouseEvent.MOUSE_UP, stopSlider);
boundary=new Rectangle(-100,0,100,0);
}
/*
dragSlider runs when the use holds the mouse button down. A
startDrag method is used on our sprite where we specify boundary
as our dragging limits. A new event handler designed
to change the mouse volume is subsequenlty called per frame, where
the slider.x property determines volume.
*/
public function dragSlider(event:MouseEvent):void {
slider.startDrag(false,boundary);
slider.removeEventListener(MouseEvent.CLICK, dragSlider);
slider.addEventListener(Event.ENTER_FRAME, changeVolume);
}
/*
Stops dragging and removes the event listener to save on space. Again,
volume will be based on the sliders current x position, which is
constantly being recalculated per frame because we used an
ENTER_FRAME event.
*/
public function stopSlider(event:MouseEvent):void {
slider.stopDrag();
slider.removeEventListener(MouseEvent.MOUSE_UP, stopSlider);
}
/*
This function is constantly recalculating the vol variable
based on the sliders x position, relative to the length of
our rectangle. Creates a decimal range from 0 to 1, where 1
represents 100% volume and 0 represents mute. Anything exceeding
100% causes distortion.
*/
public function changeVolume(event:Event):void {
vol=1+Math.round(slider.x)/100;
channel.soundTransform=new SoundTransform(vol);
}
public function onBackgroundMusicFinished(event:Event):void
{
channel = req.play();
channel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
vol=1;
channel.soundTransform=new SoundTransform(vol);
}
public function startMusic():void
{
channel=req.play();
channel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished,false,0,true );
vol=1;
channel.soundTransform=new SoundTransform(vol);
}
public function playMusic():void
{
channel = req.play();
}
public function stopMusic():void
{
channel.stop();
}
}
}
Navigation Event Class
package
{
import flash.events.Event;
public class NavigationEvent extends Event
{
public static const RESTART:String = "restart";
public static const START:String = "start";
public static const MAINMENU:String = "mainmenu";
public static const OPTIONS:String = "options";
public static const STOPMUSIC:String = "stopmusic"
public function NavigationEvent( type:String, bubbles:Boolean = false, cancelable:Boolean = false )
{
super( type, bubbles, cancelable );
}
public override function clone():Event
{
return new NavigationEvent( type, bubbles, cancelable );
}
public override function toString():String
{
return formatToString( "NavigationEvent", "type", "bubbles", "cancelable", "eventPhase" );
}
}
}
Options Screen Class
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.ui.Mouse;
import flash.net.SharedObject;
import flash.events.Event;
public class OptionScreen extends MovieClip {
public var mainMenuButton:SimpleButton;
private var new_Volume:Volume;
public var myEvent:Event;
public function OptionScreen() {
Mouse.show();
new_Volume = new Volume();
addChild(new_Volume);
mainMenuButtonOptions.addEventListener(MouseEvent.CLICK, onClickMainMenu,false,0,true);
}
public function onClickMainMenu(mouseEvent:MouseEvent):void
{
dispatchEvent( new NavigationEvent(NavigationEvent.MAINMENU));
}
}
}
Finally....Title Screen Class
package
{
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class TitleScreen extends MovieClip
{
public var startButton:SimpleButton;
public function TitleScreen()
{
Mouse.show();
startButton.addEventListener( MouseEvent.CLICK, onClickStart,false,0,true );
titleOptionsButton.addEventListener( MouseEvent.CLICK, onClickOptions,false,0,true );
}
public function onClickStart( event:MouseEvent ):void
{
dispatchEvent( new NavigationEvent( NavigationEvent.START ) );
}
public function onClickOptions( event:MouseEvent ):void
{
dispatchEvent( new NavigationEvent( NavigationEvent.OPTIONS ) );
}
}
}
You can change the volume on individual SoundChannels, or globally on the SoundMixer class. Your current implementation is the former, and defined every time you instantiate your class.
See Adobe's Controlling sound volume and panning.
You can also set global volume and pan values for all sounds at once
using the soundTransform property of the SoundMixer class, as the
following example shows:
SoundMixer.soundTransform = new SoundTransform(1, -1);
You could also store your volume and reference it as a global/static variable.
public static var soundLevel:Number = 100;
public function changeVolume(event:Event):void {
soundLevel = 1+Math.round(slider.x)/100;
channel.soundTransform=new SoundTransform(soundVolume);
}
This way, any slider object changes the same variable. Of course, then you're left with needing to update N number of soundObjects to the new soundLevel, which is why using the SoundMixer is a better solution.
No. The new instance of Volume class doesn't overwrite the SoundChannel previously created. However, because Volume is a DisplayObject, if its only reference was on the stage, and starting your game takes to you a different frame, the old Volume object would be removed from the DisplayList and could be garbage collected.
Definitely sounds like you're moving between frames, in which case the older Volume object would be removed from DisplayList and GC'ed. This comes up a lot, but I'll reiterate: don't use stage frames. There are better (less headache inducing) ways of programming what you need.
Your choice of Nav events is discretional. You could just as easily write a nav class which handles all input events as they come from the system, and appropriately call your methods. Personally, I don't like Flash style events. There's often other data I want to pass to my methods apart from the usual variable suspects, thereby leading to clutter induced by custom events. You could also clear that up with global state tracking, and simply reference your current state from your generic methods to determine their response to any given nav event.

How to call a function from a Class AS3

I'm studying to be a Game Designer, and right now I'm having some issues with my flash game.
the game has a Counter Class, with a Score Class that extends Counter. and it is added to the stage in my PlayScreenA Class.
The Timer starts with a number and decreases every 24frames. but in my Hero Class I can pick up some coins and that coins are going to increase the Time on my Score.
The question is: How I can say in my Hero Class to execute the addToValue function inside the Counter Class?
Pieces of Code:
Creating my score in the PlayScreenA Class:
private var myTime:Score = new Score();
private function create_time (){
myTime.x = 800;
myTime.y = 50;
addChild(myTime);
}
Counter Class:
package
{
import flash.display.MovieClip;
public class Counter extends MovieClip
{
public var currentValue:Number;
public function Counter()
{
reset();
}
public function addToValue( amountToAdd:Number ):void
{
currentValue = currentValue + amountToAdd;
updateDisplay();
}
public function subToValue( amountToSub:Number ):void
{
currentValue = currentValue - amountToSub;
updateDisplay();
}
public function reset():void
{
currentValue = 20;
updateDisplay();
}
public function updateDisplay():void
{
}
}
}
Score Class:
package
{
import flash.text.TextField;
import flash.events.Event;
public class Score extends Counter
{
protected var _timeCounter:int;
public function Score()
{
super();
addEventListener(Event.ENTER_FRAME, onUpdate);
}
override public function updateDisplay():void
{
super.updateDisplay();
scoreDisplay.text = currentValue.toString();
}
protected function onUpdate(e:Event):void
{
_timeCounter++;
trace(currentValue);
if (_timeCounter == 24)
{
this.subToValue( 1 );
_timeCounter = 0;
}
}
}
}
Piece of my Hero Class where I need to Call the function:
for(var i:int; i<collisionList.length;i++)
{
var $collision:platform_tile = collisionList[i];
if($hasCollided = hitbox.hitTestObject($collision.hitBox) && $collision.alpha<0.8 && $collision.alpha>0.6)
{
$collision.alpha=0;
$collision.visible = false;
//Here is where I want to call my subToValue function!
break;
}
since addToValue and subToValue are instance methods, you should provide a reference (an instance variable) to the counter object in your hero object, then call its addToValue or subToValue methods.
var theCounter:Counter;
you should either initiate this in your hero object, or assign a pre-existing counter object through getter/setters. then you can call:
theCounter.addToValue();
I assume you are trying to access the object of Score class created initially in the PlayerScreenA class...
If that is the case then you either derive a relationship between the two classes to pass this object or you could keep a static class keeping track of the function at a global level...
public class AppRefrences
{
public static var addToValueFunc:Function;
}
In Player A Class,
private var myTime:Score = new Score();
private function create_time (){
myTime.x = 800;
myTime.y = 50;
addChild(myTime);
// This is where you set the function
Apprefrences.addToValueFunc = myTime.addToValue;
}
In Hero Class,
for(var i:int; i<collisionList.length;i++)
{
var $collision:platform_tile = collisionList[i];
if($hasCollided = hitbox.hitTestObject($collision.hitBox) && $collision.alpha<0.8 && $collision.alpha>0.6)
{
$collision.alpha=0;
$collision.visible = false;
// This is where you call the function
if(AppRefrences.addToValueFunc != null)
AppRefrences.addToValueFunc(0);
break;
}
Try using getter & setters to control the update of the static variable. I didn't include it for the sake of clarity.

Initialize Assets after Preload

Whenever I export the .swf file of my Flash game, I am receiving "TypeError: Error #1009: Cannot access a property or method of a null object reference.", along with a Runtime Shared Library Preloading Warning for my preloader. I have my timeline organized so that the first and third frames are both empty along with a stop(); command in the Actions layer. The second frame contains a single MovieClip that contains all of my exported assets, which are going to be initialized in the third frame of the timeline. None of my assets, except for the preloader, are exported in the first frame. What changes should I make to my Document Class for it to initialize the assets in the third frame?
Document Class:
package com.gameEngine.documentClass
{
import flash.events.*;
import flash.display.*;
import flash.geom.Point;
import com.gameEngine.assetHolders.*;
import com.gameEngine.assetHolders.Levels.*;
public class Document extends MovieClip
{
private static var _document:Document;
private var preloader:Preloader;
public var mcMain:Player;
public var restartButton:RestartButton;
public var spawnArea:SpawnArea;
public var level_1:Level_1;
public var level_2:Level_2;
public var level_3:Level_3;
public function Document()
{
addEventListener(Event.ADDED_TO_STAGE, init);
_document = this;
preloader = new Preloader(390, this.loaderInfo);
this.addChild(preloader);
preloader.addEventListener("loadComplete", loadAssets);
preloader.addEventListener("preloaderFinished", showLogo);
mcMain = new Player(this);
restartButton = new RestartButton(this);
spawnArea = new SpawnArea();
level_1 = new Level_1(this);
level_2 = new Level_2(this);
level_3 = new Level_3(this);
this.addChild(restartButton);
this.addChild(spawnArea);
this.preloader.x = 400;
this.preloader.y = 250;
restartButton.x = 822.95;
restartButton.y = 19;
spawnArea.x = 400;
spawnArea.y = 250;
trace ("Document Class Initialized");
// constructor code
}
public static function getInstance():Document
{
return _document;
}
private function loadAssets(event:Event):void
{
this.play();
}
private function showLogo(event:Event):void
{
this.removeChild(preloader);
}
public function init(event:Event)
{
if (stage.contains(spawnArea))
{
addChild(mcMain);
}
mcMain.x = spawnArea.x;
mcMain.y = spawnArea.y;
}
}
}
Preloader Class:
package com.gameEngine.assetHolders
{
import com.gameEngine.documentClass.*;
import flash.display.*;
import flash.events.*;
public class Preloader extends MovieClip
{
private var fullWidth:Number;
public var loaderInfo:LoaderInfo;
public function Preloader(fullWidth:Number = 0, loaderInfo:LoaderInfo = null)
{
this.fullWidth = fullWidth;
this.loaderInfo = loaderInfo;
addEventListener(Event.ENTER_FRAME, checkLoad);
}
private function checkLoad (event:Event):void
{
if (loaderInfo.bytesLoaded == loaderInfo.bytesTotal && loaderInfo.bytesTotal != 0)
{
dispatchEvent(new Event("loadComplete"));
phaseOut();
}
updateLoader(loaderInfo.bytesLoaded / loaderInfo.bytesTotal);
}
private function updateLoader(num:Number):void
{
progressBar.width = num * fullWidth;
}
private function phaseOut():void
{
removeEventListener(Event.ENTER_FRAME, checkLoad);
progressBar.gotoAndPlay(2);
if (progressBar.currentFrame == progressBar.totalFrames)
{
phaseComplete();
}
}
private function phaseComplete() : void
{
dispatchEvent(new Event("preloaderFinished"));
}
}
}
You have a lot of race conditions going on here. Many of these events could occur at relatively random times in relation to one another . . . you have to think asynchronously. That is, there can be no assumption that any object exists. E.g., in Document.init(), you check is if the spawnArea exists, but it is almost guaranteed not to at that point, and you never check for it again.
Without making any specific changes, I can recommend a generic solution. For any object (objB) you want loaded after another object (objA) is loaded, have objB created in the objA's ADDED_TO_STAGE handler. A simple example would be:
var objA:Whatever;
var objB:WhateverElse;
[...]
objA = new Whatever();
objA.addEventListener(Event.ADDED_TO_STAGE, objAAddedHnd);
[...]
public function objAAddedHnd(event:Event)
{
// remove the event, if no longer needed:
objA.removeEventListener(Event.ADDED_TO_STAGE, objAAddedHnd);
objB = new WhateverElse();
objB.addEventListener(Event.ADDED_TO_STAGE, objBAddedHnd);
}
[...]
public function objBAddedHnd(event:Event)
{
// remove the event, if no longer needed:
objB.removeEventListener(Event.ADDED_TO_STAGE, objBAddedHnd);
// and so on . . .
}
At this point, it shows that you would need to plan the timeline of object creation.

ActionScript - Global Custom Events?

up until now, the way i've been needing to handle my own custom events is by adding an event listener to the object that was dispatching the custom event. while this method of event handling works just fine, i've come to the point where i would like my custom events to be globally accessible, where the listening object does not need to be the same object that is dispatching the event.
in this example, my main Controller class is instantiating and adding to the display list 2 sprite classes: Square and Triangle. the 4th and final class is a custom event called ColorChangeEvent.
i'm attempting to dispatch a new ColorChangeEvent from the Square class, which uses a timer to dispatch a new random color once every second, while Triangle will listen for the dispatched event and change its fill color to the color that was dispatched by Square.
Controller.as:
package
{
import flash.display.Sprite;
public class Controller extends Sprite
{
public function Controller()
{
var sq:Square = new Square();
sq.x = sq.y = 100;
var tr:Triangle = new Triangle();
tr.x = tr.y = 250;
addChild(sq);
addChild(tr);
}
}
}
Square.as:
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Square extends Sprite
{
public function Square()
{
graphics.beginFill(0x999999);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
var myTimer:Timer = new Timer(1000);
myTimer.addEventListener(TimerEvent.TIMER, dispatchNewColor);
myTimer.start();
}
private function dispatchNewColor(evt:TimerEvent):void
{
var randomColor:Number = Math.random() * 0xFFFFFF;
trace("Square Class Dispatched: " + randomColor);
dispatchEvent(new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor));
}
}
}
Triangle.as:
package
{
import flash.display.Sprite;
import flash.geom.ColorTransform;
public class Triangle extends Sprite
{
public function Triangle()
{
graphics.beginFill(0x999999);
graphics.moveTo(0, 0);
graphics.lineTo(100, 50);
graphics.lineTo(-50, 150);
graphics.endFill();
addEventListener(ColorChangeEvent.CHANGE, changeColor);
}
private function changeColor(evt:ColorChangeEvent):void
{
var ct:ColorTransform = new ColorTransform;
ct.color = evt.color;
transform.colorTransform = ct;
trace("Triangle Class Received: " + evt.color);
}
}
}
ColorChangeEvent.as:
package
{
import flash.events.Event;
public class ColorChangeEvent extends Event
{
public static const CHANGE:String = "change";
public var color:Number;
public function ColorChangeEvent(type:String, color:Number)
{
super(type);
this.color = color;
}
override public function clone():Event
{
return new ColorChangeEvent(type, color);
}
}
}
needless to say, this isn't working.
of course, i could add the event listener to the Square instance in the Controller class, who's event handler could pass that value to Triangle via a public function to change the color, but this is exactly the kind of limitation i'm trying to avoid.
it's not always easy to access and pass a value to a class from where the custom event is dispatched, which is why i'm looking for an actual global solution to handling custom events.
I have been using this class for some time now. To use it you would do this in square:
data.EventManager.instance.publish("someName", randomColor);
and then in your Triangle:
data.EventManager.instance.subscribe("someName", handleColorChange);
private function handleColorChange(color:Number):void {
// implementation here
}
You can even pass the ColorChangeEvent instead of just the color.
data.EventManager.instance.publish(ColorChangeEvent.CHANGE, new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor);
And then
data.EventManager.instance.subscribe(ColorChangeEvent.CHANGE, handleColorChange);
private function handleColorChange(colorChangeEvent:ColorChangeEvent):void {
// implement here
}
I removed a lot of code that is specific to my projects, so I am not 100% it is usable exactly as-is. But, you should be able to modify it to get it working correctly. If not, let me know and I can try to work it out with you.
This class handles additional things that I will not go into, though you are free to explore. Be aware, however, that anything that subscribes for event notification has a strong reference by the EventManager. That means that if you want to destroy something for garbage collection, you need to call EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange) before the Triangle instances can be collected.
package data {
import flash.utils.*;
public class EventManager extends Object {
private var _subscribers:Dictionary;
private var _calls:Dictionary;
private var _feeds:Dictionary;
private var _requests:Dictionary;
private var _notify:Dictionary;
private var _services:Dictionary;
private static var __instance:EventManager;
public function EventManager() {
if (__instance) {
trace("EventManager is a Singleton class which should only be accessed via getInstance()");
}
_feeds = new Dictionary(true);
_subscribers = new Dictionary(true);
_requests = new Dictionary(true);
_services = new Dictionary(true);
_notify = new Dictionary(true);
}
public function getFeedData($name:String) {
if (_feeds[$name]) {
return _feeds[$name];
}
return undefined;
}
public function unpublish($name:String) {
var _post:* = _feeds[$name];
delete _feeds[$name];
return _post;
}
public function cancel($name:String, $subscriberFunc:Function, ...args): void {
var _cnt:Number;
var _subscriberArray:Array;
if (_subscribers[$name]) {
for (_cnt = 0; _cnt < _subscribers[$name].length; _cnt++) {
if (_subscribers[$name][_cnt] == $subscriberFunc) {
_subscribers[$name].splice(_cnt, 1);
}
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name];
_cnt = _subscriberArray.length;
while (_cnt > 0) {
if (_subscriberArray[_cnt] == $subscriberFunc) {
_subscriberArray.splice(_cnt, 1);
}
_cnt--;
}
}
}
public function subscribe($name:String, $subscriber:Function, ...args): void {
var _funcArray:Array;
var _func:Function;
if (_feeds[$name]) {
$subscriber(_feeds[$name]);
}
if (! _subscribers[$name]) {
_subscribers[$name] = new Array();
}
_subscribers[$name].push($subscriber);
if (_notify[$name]) {
_funcArray = _notify[$name];
for each (_func in _funcArray) {
_func();
}
delete _notify[$name];
}
}
public function request($name:String, $feedFunction:Function): void {
var _requestArray:Array;
var _request:Function;
if (! _feeds[$name]) {
if (! _requests[$name]) {
_requests[$name] = new Array();
}
_requests[$name].push($feedFunction);
} else {
$feedFunction(_feeds[$name]);
}
if (_notify[$name]) {
_requestArray = _notify[$name];
for each (_request in _requestArray) {
_request();
}
delete _notify[$name];
}
}
public function publish($name:String, $data:*, $args:Object = null): void {
var _subscriberArray:Array;
var _func:Function;
var cnt:Number = 0;
_feeds[$name] = $data;
if (_subscribers[$name] != undefined) {
_subscriberArray = _subscribers[$name].slice();
_cnt = 0;
while (_cnt < _subscriberArray.length) {
_func = _subscriberArray[_cnt] as Function;
if ($args) {
_func($data, $args);
}else {
_func($data);
}
_cnt++;
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name].slice();
delete _requests[$name];
_cnt = 0;
while (_cnt < _subscriberArray.length) {
if (_subscriberArray[_cnt] != null) {
_subscriberArray[_cnt]($data);
}
_cnt++;
}
}
}
public function notify($name:String, $subscriber:Function): void {
if (_requests[$name] || _subscribers[$name]) {
$subscriber();
}else {
if (! _notify[$name]) {
_notify[$name] = new Array();
}
_notify[$name].push($subscriber);
}
}
public static function getInstance(): EventManager {
if (! __instance) {
__instance = new EventManager();
}
return __instance;
}
public static function get instance(): EventManager {
return getInstance();
}
}
}
I got this to work by creating a singleton: EventDispatchSingleton that extends EventDispatcher. It's basically an empty singleton that provides the dispatchEvent and add/removeEventListener methods (these are automatically provided by extending EventDispatcher).
Anywhere I want to dispatch an event I import EventDispatchSingleton and then call EventDispatchSingleton.instance.dispatchEvent(<someEvent>);.
Then, wherever I want to listen to that event, I just import EventDispatchSingleton and call EventDispatchSingleton.instance.addEventListener(eventName, callback);
You should look into event bubbling, specificly I think you will find the Capturing phase of the event propagation useful. Take a read of Event propagation from Adobe LiveDocs. It's in the Flex docs, but it is about AS3 Events.
Also Senocular has a good post on Flash Event Bubbling.