Flash Game Score not working AS3, please help? - actionscript-3

So Im creating a game and all I wanted to add was a counter that increments constantly until a player loses the game.
I created my score class and it looks like this:
package
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.text.TextField;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Score extends MovieClip
{
public var second:Number = 0;
public var timer:Timer = new Timer(10);
private var stageRef:Stage;
public function Score(stageRef:Stage)
{
x = 537.95;
y = 31.35;
this.stageRef = stageRef;
timer.addEventListener(TimerEvent.TIMER, clock);
timer.start();
}
function clock(evt:TimerEvent):void
{
second += 1;
scoreDisplay.text = String("Score: " +second);
}
}
}
and this is my engine class that adds it to the stage:
package {
//list of our imports these are classes we need in order to
//run our application.
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class Engine extends MovieClip{
private var enemyList:Array = new Array();
private var ourBoat:Boat;
private var score:Score;
public function Engine() : void{
//create an object of our ship from the Ship class
ourBoat = new Boat(stage);
score = new Score(stage);
//add it to the display list
stage.addChild(ourBoat);
stage.addChild(score);
So that creates a timer on the stage and continuously increments, but when I compile, I get no errors and my timmer for some reason doesn't work, it just displays random numbers, please help! If there is a better way of doing this please enlighten me.

I'm assuming scoreDisplay is a named Object on stage. You may find it useful to add trace()s to the script in each function that is called. That way you can see which ones are being called correctly. For example trace("Engine Instantiated."); and trace("Timer Event Received"); will tell if your class is being instantiated correctly. If it is and the trigger is not working you know your issue is between these two points. Then work your way toward the middle of the code execution until you find the problem.
You could also add an event listener to the stage for enter frame events and use that to trigger your count function. This event is always broadcast, so using should use less resources than adding a timer.

Are you sure scoreDisplay is large enough? Your number would increase by 100 every second, which if your textfield is only 2 characters long you will see random numbers.

First, you do not need to pass the stage class to MovieClip childs, once they're added to stage, you can access the stage with the this.stage property.
Second, the Timer class delay parameter is described as following in the documentation:
delay:Number — The delay between timer events, in milliseconds. A
delay lower than 20 milliseconds is not recommended. Timer frequency
is limited to 60 frames per second, meaning a delay lower than 16.6
milliseconds causes runtime problems.
Therefore, if you are really tracking seconds, your timer should be :
public var timer:Timer = new Timer(1000);
EDIT:
Here's how I would implement the score you described on the comment:
public class Score extends MovieClip
{
public var second:Number = 0;
var pointsPerSecond : Number = 10;
private var stageRef:Stage;
public function Score(stageRef:Stage)
{
x = 537.95;
y = 31.35;
this.stageRef = stageRef;
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
function clock(evt:Event):void
{
second += pointsPerSecond/stage.frameRate; // Note that if the game is running slow (flash cant keep the frameRate you asked for), the score will also grow slowly
scoreDisplay.text = String("Score: " +second);
}
}

Related

AS3 error 2025 removechild

I made a game with AS3 where you must click on falling bombs before they explode and destroy a wall. Now, I'm trying to remove the bombs that fell just when the wall got destroyed, so I did a removeChild(blob) in my game over function, since these bombs are added to the stage with an addChild(blob), and I keep getting this error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller. ...line 80
...And by the way, I've already tried things like these:
this.parent.removeChild(this);
or
blob.parent.removeChild(blob);
or
stage.removeChild(blob);
but I still get the same error.
Here's my code:
package cem {
import flash.geom.*;
import flash.display.*;
import flash.events.*;
import flash.display.MovieClip;
import flash.utils.Timer;
public class Jeu extends MovieClip {
//Variables publiques
var decor: MovieClip = new Decor();
var chrono: cem.Chronometre;
var nextObject: Timer = new Timer(800, 0);
var _menu: MovieClip = new Menu();
var _btnJouer: MovieClip = new BoutonJouer();
var blob: cem.Blob;
var score: Score;
public function Jeu() {
// constructor code
//***********************************************Mettre menu***********************************************//
addChild(_menu);
addChild(_btnJouer);
_btnJouer.x = 500;
_btnJouer.y = 500;
_btnJouer.addEventListener(MouseEvent.CLICK, jouer);
}
//*****************************************************Jouer**************************************************//
function jouer(e: MouseEvent) {
removeChild(_menu);
addChild(decor);
decor.gotoAndStop(1);
chrono = new cem.Chronometre();
addChild(chrono);
chrono.demarrer();
score = new Score();
score.x = 600;
nextObject.addEventListener(TimerEvent.TIMER, creerBlobs);
nextObject.start();
}
//**************************************************Créer Bombes***********************************************//
function creerBlobs(e: TimerEvent) {
blob = new cem.Blob();
blob.x = Math.floor(Math.random() * (stage.stageWidth - blob.width));
addChild(blob);
blob.gotoAndStop(1);
blob.addEventListener("explosion", perdreVies);
}
//************************************************Perdre des vies*********************************************//
public function perdreVies(e: Event) {
decor.moinsVie();
decor.addEventListener("gameisover", _gameOver);
}
//************************************************Partie terminée*********************************************//
public function _gameOver(e: Event) {
blob.removeEventListener("explosion", perdreVies);
removeChild(blob);
chrono.arret();
addChild(_menu);
addChild(_btnJouer);
nextObject.stop();
nextObject.removeEventListener(TimerEvent.TIMER, creerBlobs);
nextObject.removeEventListener(TimerEvent.TIMER, creerBlobs);
addChild(score);
score.affichageScore.text = "votre score: " + chrono.secondes * 1000;
}
}
}
The var name blob can only reference one specific Blob object at a time.
Each time you create a new Blob you are reassigning the name blob to the last created one, losing the reference to the previous one.
That error says, at the time you call removeChild the specific Blob assigned to the name "blob" is not a child, it is not on the display list.
So its referencing the wrong Blob or its already removed from the display list.
To avoid errors u can also say something like if (blob.parent) remove child blob

Unable to stop spawning an enemy

Okay so here's the dealio.
The code below is what I use to spawn a single enemy periodically in my horror game. He spawns at the window every 10 seconds, then every 6 seconds later, he enters the room and you're essentially dead already, because 5 seconds after that you get a lovely jumpscare. The moment the enemy shifts from the window to the bedroom is when I want the window enemy to stop spawning.
EnemyShipTimer is the timer that spawns the enemy.
enemyTimer is the timer that counts how long the enemy has been at
the window, and then in the room.
In the main file, I've attempted to get rid of the enemy a number of ways, to no effect.
So function gtfo is my latest attempt at removing the enemy, by trying to stop the spawning from the class file itself. It still hasn't worked. Maybe I need to somehow remove the class file from my game, but I have no idea how. Please help! ;A;
PS, countClick counts how many clicks you've done to make the enemy go away, although when I make him go away, room enemy still spawns :c
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.Sprite;
import flash.utils.Timer;
import flash.utils.getTimer;
import flash.events.TimerEvent;
import flash.text.TextField;
public class EnemyShip extends MovieClip
{
private var clickCount:int = 0;
private var enemyShipTimer:Timer;
private var enemyTimer:Timer;
public function EnemyShip()
{
this.x = 900;
this.y = 214;
addEventListener(MouseEvent.CLICK, addClick);
addEventListener(MouseEvent.CLICK, countclick);
addEventListener(TimerEvent.TIMER, gtfo);
}
function gtfo(e:TimerEvent):void{
if (enemyTimer.currentCount==5)
enemyShipTimer.stop();
stage.removeChild(this);
}
function addClick(event:MouseEvent):void
{
clickCount = clickCount + 1;
trace("Clickage : " + clickCount);
}
function countclick(event:MouseEvent):void
{
if (clickCount ==4)
{
stage.removeChild(this);
}
}
}
}
The following is the relevant main timeline code that may be clashing with the code (I have updated the package class as per #Karma 's helpful instructions c: though the enemy still spawns; I think what the problem is now is that the timer functions clash with timer functions I've put in my main timeline, and I attempted to sort of move them into the package class but I don't know how to add the necessary movieclips so that I won't get access of undefined property errors so I separated the two once more
enemy is the window spawning enemy.
mosnta is the room spawning enemy.
sod is the screen of death (game over screen) which does not play at all.
var enemyShipTimer:Timer;
function sendEnemy(e:Event)
{
var enemy = new EnemyShip();
stage.addChild(enemy);
var enemytimer = new Timer (1000, count);
enemytimer.start();
enemyShipTimer = new Timer(10000);
enemyShipTimer.addEventListener("timer", sendEnemy);
enemyShipTimer.start();
enemytimer.addEventListener(TimerEvent.TIMER, countdowndesu);
function countdowndesu(e:Event):void{
if (enemytimer.currentCount>5){
trace("ur ded");
enemytimer.removeEventListener(TimerEvent.TIMER, countdowndesu);
mosnta.visible=true;
enemy.visible=false;
if (enemytimer.currentCount==8){
sod.visible=true;
sod.gotoAndPlay(2);
}
}
}
}
Not really understanding the dynamics of how your game works, but here's an altered version of your code with working Timers. Maybe this will help you figure out how to fix your issues
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class EnemyShip extends MovieClip
{
private var clickCount:int = 0;
private var enemyShipTimer:Timer;
private var enemyTimer:Timer;
public function EnemyShip()
{
this.x = 900;
this.y = 214;
//only need one click handler
addEventListener(MouseEvent.CLICK, addClick);
//Instantiate Timers
enemyShipTimer = new Timer(10000); //10 seconds
enemyTimer = new Timer(6000); //6 seconds
//add TimerEvent listeners onto Timer Objects
enemyShipTimer.addEventListener(TimerEvent.TIMER, gtfo);
enemyTimer.addEventListener(TimerEvent.TIMER, enemyTimerHandler);
//Start the timers
enemyShipTimer.start();
enemyTimer.start();
}
//This gets called every 10 seconds
private function gtfo(e:TimerEvent):void
{
trace("enemy spawns at window");
if (enemyTimer.currentCount == 5) {
enemyShipTimer.stop();
stage.removeChild(this);
}
}
//This gets called every 6 seconds
private function enemyTimerHandler(e:TimerEvent):void
{
trace("enemy moves to room");
}
private function addClick(event:MouseEvent):void
{
clickCount ++;
trace("Clickage : " + clickCount);
if (clickCount == 4)
{
stage.removeChild(this);
}
}
}
}

variable in class not returning updated value

I'm relatively new to actionscript 3, and this one has me stumped. Here's my class;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Clicker extends MovieClip {
public var clicks:uint;
public var string:String;
public function Clicker() {
// constructor code
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
addEventListener(Event.ADDED_TO_STAGE, alignCentre);
string = "clicks: ";
clicks = 5; // I can change it here
}
public function clicked(e:MouseEvent):void{
clicks++;
trace(clicks); // it outputs updated value here
}
public function alignCentre(e:Event):void{
x = stage.stageWidth / 2 - width/2;
y = stage.stageHeight / 2 - height/2;
}
public function addedToStageHandler(e:Event):void{
this.stage.addEventListener(MouseEvent.CLICK, clicked);
}
public function get_clicks():uint{
trace(clicks); // gives me whatever I initialise it to in the constructor
return clicks;
}
}
}
I want to return the value of clicks from my Clicker class, but the value remains whatever I set it to in the constructor within get_clicks(), and I'm not sure why.
The variable has class scope, so why would it return the default value (in this case, 5) of clicks from get_clicks()? my clicked() method traces the correctly updated value. Is it a scope issue? I'm very confused.
This is my first frame where I create the object;
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.text.TextField;
var clicks:TextField = new TextField();
var circle:Clicker = new Clicker();
clicks.text = circle.get_clicks().toString();
trace(circle.get_clicks());
addChild(circle);
addChild(clicks);
As you'd expect from the problem I'm having, trace spits out 5 over and over, and Clicks doesn't change from 5.
Edit:
There was a mistake, but fixing it has caused clicks not to update at all. I had a library version of the movieclip on my first frame rather than adding the object to the frame with addChild. Now that I've added circle, clicks does not update as my clicked() method isn't being triggered when I click my object.
Resolved:
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.text.TextField;
var clicks:TextField = new TextField();
var circle:Clicker = new Clicker();
var myTimer:Timer = new Timer(100,0);
myTimer.addEventListener(TimerEvent.TIMER, timerListener);
function timerListener (e:TimerEvent):void{
trace("Timer is Triggered");
trace(circle.get_clicks());
clicks.text = circle.get_clicks().toString();
addChild(circle);
addChild(clicks);
}
myTimer.start();
Rather than use the timeline and frames, I wrapped the code I wanted to repeat in a timer listener. Works exactly as intended.

Gettling starling to work with box2d and debugdraw with as3

This topic has been raised before, but not one of the examples I've found online seem to work for me! I am trying to get starling to work with box2d, and also for the box2d debugdraw.
I have tried a bunch of different methods, and my code is now a bit of a mess due to commenting out to try different mixes of the "solution". Does anyone know how to do all this properly? I would be greatly in dept if someone could explain it.
Here is the last attempt I tried:
In my Startup class:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
//import flash.events.Event;
import starling.core.Starling;
//import starling.display.Sprite;
import flash.events.Event;
[SWF(width="640", height="480", frameRate="60", backgroundColor="#000000")]
public class Startup extends Sprite {
public static var mStarling:Starling;
public static var debugSprite:Sprite;
public function Startup() {
//addChild ( new Stats() );
super();
//stage.align = StageAlign.TOP_LEFT;
//stage.scaleMode = StageScaleMode.NO_SCALE;
// create our Starling instance
mStarling = new Starling(Game, stage);
// set anti-aliasing (higher the better quality but slower performance)
mStarling.antiAliasing = 1;
mStarling.showStats = true;
// start it!
mStarling.start();
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
}
private function onContextCreated(e:Event):void{
////debug mode
// debugSprite=new Sprite();
// //addChild(debugSprite);
// Starling.current.nativeOverlay.addChild(debugSprite);
//var debugSprite:Sprite=new Sprite();
addChild(debugSprite);
(mStarling.stage.getChildAt(0) as Game).DebugDraw(debugSprite)
}
I call the debugdraw like this:
debugDraw(Startup.debugSprite);
Here is a heavily commented out debugdraw:
private function debugDraw(debugSprite:flash.display.Sprite):void {
/*var worldDebugDraw:b2DebugDraw=new b2DebugDraw();
//var debugSprite:flash.display.Sprite = new flash.display.Sprite();
var debugSprite:Sprite = new Sprite();
addChild(debugSprite);
//mStarling.current.nativeOverlay.addChild(debugSprite);
//worldDebugDraw.SetSprite(debugSprite);
//debugDraw.SetSprite(Starling.current.nativeOverlay); //DOESN'T SEEM TO WORK
worldDebugDraw.SetDrawScale(worldScale);
worldDebugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
//worldDebugDraw.SetFillAlpha(0.0);
//worldDebugDraw.SetAlpha(0.0);
//visible
worldDebugDraw.SetFillAlpha(0.8); //for testing
worldDebugDraw.SetAlpha(1); //for testing
world.SetDebugDraw(worldDebugDraw);*/
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(debugSprite);
world.SetDebugDraw(worldDebugDraw);
}
DebudDraw works with ONE classic Flash Sprite (you keep creating new ones for some reason). Only one b2DebugDraw should be created and set with that ONE Sprite.
Starling pretends to own the stage and all displaylist but it doesn't. Use simply your StartUp instance or even directly the stage itself without passing through Starling it will avoid some confusion.
The right way to do all this:
public var debugSprite:Sprite;//no static var
Starting what?
//don't start it!
mStarling.start();
You star something that cannot be started. At this point you are trying to create a valid Context3D so be patient. Remove that line.
Now in onContextCreated:
mStarling.start();//now you can start
debugSprite = new Sprite();//create your sprite
addChild(debugSprite);
var game:Game = mStarling.stage.getChildAt(0) as Game;//Game? somebody is following a tutorial ...
if(game)
{
game.setDebug(debugSprite);//this is a new public method to create in Game
}
In Game in method setDebug (with one parameter Sprite):
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(myspriteparameter);
world.SetDebugDraw(worldDebugDraw);
That's it, don't create new Sprite, don't create new debugdraw, you are good to go that's all you need.

Multiple dynamic text score display. Modifying each text one after another and incrementing the score by a certain number

I have a result screen that shows bonus points and such. I want each text field to increment one after another and also have it increment by a certain amount each frame.
Result Screen pops up.
First is the player score
check the player score, is it more than the score we want to display
if the player score is greater than the player display score by 100
increase the player display score by 100
if the player score is greater than the player display score by 10
increase the player display score by 10
else increase the player display score by 1
when finished move to the next score...and so on.
I have thought of using timers to move from one score to the next, but not being in an Event.ENTER_FRAME it only does one if then moves to the next one. Also the if statement for incrementing the score looks ridiculous and I'm thinking there has to be a better way to do it. I was thinking of making it a separate function but then I wouldn't know what to return, or how to return it so it looks like its increasing and not just showing the total number instantly.
If you have any questions please leave a comment. I'll try to expand on it a little more.
You could make a new ScoreText class that inherits from TextField, and use that for each of your score text fields. On that class you could make a setTargetScore method that takes a score number, and handles the incrementation of the display number. Then it could dispatch an event when it is finished. You could listen for then events, and call the setTargetScore method on each ScoreText as you need to.
Another way, that is possibly better/easier, is to use TweenLite to tween your score number, and use its events to update the score textfield, and when its complete, move to the next one.
EDIT*
Here is an example of using Tweenlite to tween a score variable:
How to Tween A Variable with Flash and TweenLite
EDIT2*
Here is an example of my first method:
First here is the ScoreText class:
package {
import flash.events.Event;
import flash.text.TextField;
public class ScoreText extends TextField {
public static const EVENT_SCORE_COMPLETE:String = 'scoreCompleteEvent';
private var targetScore:Number = 0;
private var currentScore:Number = 0;
private const speed:Number = 0.11;
public function ScoreText(initialScore:Number = 0) {
currentScore = initialScore;
updateScore();
}
public function setTargetScore(targetScore:Number):void {
this.targetScore = targetScore;
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(e:Event):void {
currentScore += (targetScore - currentScore) * speed;
if (currentScore >= targetScore -1) {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
dispatchEvent(new Event(EVENT_SCORE_COMPLETE));
}
updateScore();
}
private function updateScore():void {
this.text = Math.round(currentScore).toString();
}
}
}
And here is the Main class:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
public class Main extends Sprite
{
private var st1:ScoreText;
private var st2:ScoreText;
private var st3:ScoreText;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
st1 = new ScoreText(0);
st1.y = 10;
st1.addEventListener(ScoreText.EVENT_SCORE_COMPLETE, score1Complete);
addChild(st1);
st2 = new ScoreText(0);
st2.y = 60;
st2.addEventListener(ScoreText.EVENT_SCORE_COMPLETE, score2Complete);
addChild(st2);
st3 = new ScoreText(0);
st3.y = 110;
st3.addEventListener(ScoreText.EVENT_SCORE_COMPLETE, score3Complete);
addChild(st3);
st1.setTargetScore(1234);
}
private function score1Complete(e:Event):void
{
trace('score 1 finishes, start the next one!');
st2.setTargetScore(234553);
}
private function score2Complete(e:Event):void
{
trace('score 2 finishes, start the next one!');
st3.setTargetScore(745);
}
private function score3Complete(e:Event):void
{
trace('score 3 finishes, start the next one!');
}
}
}