AS3: Score based on timer - actionscript-3

I'm making a game in AS3 and I've been trying to make a score based on the time since the game started, the score would show when the game is over and would basically be the seconds since the game started multiply by 1000. But I'm struggling to see how to do such thing since I've made the timer in a separate class and I'm trying to add the score to the main document class.
Here's what I've tried:
in the main class:
score.affichageScore.text = "votre score: " + chrono.seconds * 1000;
in this, is the timer class where I used a Date class:
package cem {
import flash.display.MovieClip;
import flash.events.*;
public class Chronometre extends MovieClip {
var begin: Date;
public var seconds: uint = 0;
public function Chronometre() {
// constructor code
}
//************************************************Start the chrono*********************************************//
public function start() {
begin= new Date();
this.addEventListener(Event.ENTER_FRAME, _actualize);
}
//************************************************Stop the chrono*********************************************//
public function stop() {
this.removeEventListener(Event.ENTER_FRAME, _actualize);
}
//************************************************Actualize the chrono*********************************************//
private function _actualize(e: Event) {
var msSpent: uint = new Date().getTime() - begin.getTime();
seconds = Math.floor(msSpent/ 1000);
var milliseconds: uint = msSpent- (seconds * 1000);
affichage.text = seconds + ":" + milliseconds;
}
}
}
The obvious problem is how to get the ''seconds'' variable value from the timer class to the ''score'' variable in the main class?

Please don't create a new date on each frame - this is the worst option performance wise. As null have mentioned there is a timer class that could count the time but it can be even easier:
getTimer();
This returns the number of milliseconds since the swf was started. So you could do this straight in your main game class:
// when the game starts
gameStartTime = getTimer();
// when the game ends
gameEndTime = getTimer();
// calculate score with one point for each millisecond
// (might be even better so that your scores won't always end in 000)
myScore = gameEndTime - gameStartTime;
// 1000 points for each second:
seconds = Math.floor((gameEndTime - gameStartTime) / 1000);
myScore = seconds * 1000;

Related

Problems with adding and subtracting time from/to Timers

Now I am also using a timer in frame 8, which is my Gamescreen frame to try and create an energy bar, so decreasing by 1 every second, and everytime the character collides with an object then increment the value of count by 1 (which in my min is 1sec, right?), however the timer runs out prematurely, when the label is showing 3secs left after collecting 3 items the timer automatically ends, HELP ME! :)
var count:Number = 5; (temporary value for testing)
var theTimer:Timer = new Timer(1000, count);
theTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);
theTimer.start();
function whenTimerComplete(e:TimerEvent):void
{
theTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, whenTimerComplete); //Remove listener
gotoAndStop("frameFive"); // Advance to score screen.
}
theTimer.addEventListener(TimerEvent.TIMER, theCountdown);
function theCountdown(e:TimerEvent):void
{
count--;
timerLabel.text = count.toString()
}
//Start the timer and show in the label.
timerLabel.text=count.toString();
theTimer.start();
All help and a solution is VERY much appreciated.
Here's an example countdown timer:
Launch Flash example
FLA source code
Countdown Timer AS3 source code
CS6 ZIP of source code
CS5 ZIP of source code
Create a countdown timer class at the root of your FLA:
CountdownTimer.as
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
public class CountdownTimer extends Timer {
public var time:Number = 0;
public function CountdownTimer(time:Number = Number.NEGATIVE_INFINITY, delay:Number = 1000) {
super(delay, repeatCount);
if (!isNaN(time))
this.time = time;
repeatCount = Math.ceil(time / delay);
addEventListener(TimerEvent.TIMER, timerHandler);
}
protected function timerHandler(event:TimerEvent):void {
time -= delay;
if (time == 0)
dispatchEvent(new TimerEvent(TimerEvent.TIMER_COMPLETE));
}
public function dispose():void {
removeEventListener(TimerEvent.TIMER, timerHandler);
}
}
}
On the timeline of your FLA, create a timer with the total number of milliseconds to countdown:
var timer:CountdownTimer = new CountdownTimer(60000);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
timer.start();
In the example above, the timer will countdown for 1-minute (60-seconds). Each second the timerHandler will be called. When it reaches 0, the timerCompleteHandler will be called.
function timerHandler(event:TimerEvent):void {
timerText.text = (timer.time / 1000).toString();
}
function timerCompleteHandler(event:TimerEvent):void {
timerText.text = "COMPLETE";
}
To add time to the timer, add milliseconds to time. If you want the timer to dispatch timer complete event when it reaches 0, update the repeatCount:
timer.time += 1000;
timer.repeatCount += 1;
Likewise to remove time from the timer, subtract milliseconds from time; and again, if you want the timer to dispatch timer complete event when it reaches 0, update the repeatCount:
timer.time -= 1000;
timer.repeatCount -= 1;

Adding additional time to main timer from movieclip?

Hi so yeah in the main timeline I have the timer
var count:Number = 300;//Count down from 300
var myTimer:Timer = new Timer(1000,count);
myTimer.addEventListener(TimerEvent.TIMER, sayHello);
function sayHello(e:TimerEvent):void
{
trace("Current Count: " + myTimer.currentCount);
}
And when you go into the movieclip reimoi_mcand click the useplush button I want to be able to add additional seconds onto the timer. The following is the code in the reimoi_mc clip but yeah I really have no idea how to make this work, please help ;0; (I have to use MovieClip(root) to access the running timer from the main timeline within the movieclip)
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.utils.getTimer;
stop();
useplush.addEventListener(MouseEvent.CLICK, addtime);
function addtime(e:MouseEvent):void
{
MovieClip(root).count += 2;
MovieClip(root).myTimer.repeatCount += MovieClip(root).count; //add time to the timer
trace("new time " + myTimer.currentCount);
}
I think what you are trying to do is add 2 seconds to the timer in the click handler, and then show how much time is left? If so, just a couple tweaks will do:
function sayHello(e:TimerEvent):void {
trace("Time Left: " + myTimer.repeatCount - myTimer.currentCount); //time left is the repeat count - the current count
}
function addtime(e:MouseEvent):void {
MovieClip(root).myTimer.repeatCount += 2 //add 2 more ticks to the timer (currentCount will always remain the same unless the timer is reset)
trace("new time remaining: " + MovieClip(root).myTimer.repeatCount - MovieClip(root).myTimer.currentCount);
}
BONUS CODE!
If you wanted to make it agnostic of the timer delay (let's say you want it to update quicker than 1 second for instance), you could do this:
var startingTime:Number = 20; //the initial time in seconds
var myTimer:Timer = new Timer(200); //your timer and how often to have it tick (let's say 5 times a second)
myTimer.repeatCount = startingTime * Math.ceil(1000 / myTimer.delay); //set the initial repeat count
myTimer.addEventListener(TimerEvent.TIMER, sayHello);
myTimer.start();
function sayHello(e:Event):void {
trace("Time Left: " + ((((myTimer.repeatCount - myTimer.currentCount) * myTimer.delay) / 1000)) + "seconds");
}
And in your other object:
stage.addEventListener(MouseEvent.CLICK, function(e:Event){
myTimer.repeatCount += Math.ceil(2000 / myTimer.delay); //add 2000 milliseconds to the timer
});
You'd better use an external counter to count the time, instead of stuffing it into a Timer object. You would then need timers to measure delays, and listeners to count them.
var myTimer:Timer=new Timer(1000); // no second parameter
public var secondsLeft:int=300; // former "count"
myTimer.addEventListener(TimerEvent.TIMER, sayHello);
function sayHello(e:TimerEvent):void {
secondsLeft--;
trace("Seconds left:", secondsLeft);
if (secondsLeft<=0) {
myTimer.stop();
myTimer.reset();
// whatever else to trigger when time runs out
}
}
And then you just add to secondsLeft and update the scoreboard.

Is this a good implementation of the gameloop

I have implemented a gameloop in Flash/Actionscript/Starling and I want to throw it at you to see if this is a valid implementation.
I wanted to have a variable time step approach.
private var _deltaTime:Number = 0;
private var _lastTime:Number = 0;
private var _speed = 1000 / 40;
private function onEnterFrame() {
var now = new Date().getTime();
var delta = now - _lastTime;
_deltaTime += delta - _speed;
_lastTime = now;
//skip if frame rate to fast
if (_deltaTime <= -_speed) {
_deltaTime += _speed;
return;
}
update();
}
private function update() {
updateGameState();
if (_deltaTime >= _speed) {
_deltaTime -= _speed;
update();
}
}
What I got sofar is that I have a constant speed (more or less).
My question is is there a better approach so that the movements will appear even
smoother.
What is really surprising to me is that even thou the FPS is pretty much constant (60FPS)
the movement is sometimes bumpy yet smoother than with the naive gameloop.
Youre on the right track - assuming that onEnterFrame is triggered in some way by Event.ENTER_FRAME - instead of skipping update, call it on every frame but pass in the time elapsed:
private function onEnterFrame() {
var now = new Date().getTime();
var delta = now - _lastTime;
_lastTime = now;
updateGameState(delta/1000);//divide by 1000 to give time in seconds
}
In updateGameState, you can utilise 'delta' to calculate movement etc, eg:
function updateGameState(timeElapsed:Number):void {
myAlien.x += myAlienSpeedPerSecond*timeElapsed;
}
This way you get smooth movement even when frame rate varies.
from the Starling introduction pages, it shows that time elapsed is built into the EnterFrameEvent class.
// the corresponding event listener
private function onEnterFrame(event:EnterFrameEvent):void
{
trace("Time passed since last frame: " + event.passedTime);
enemy.moveBy(event.passedTime * enemy.velocity);
}
http://wiki.starling-framework.org/manual/animation#enterframeevent

Flash Game Score not working AS3, please help?

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);
}
}

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!');
}
}
}