Actionscript 3 timer is unidentified, how do I fix this? - actionscript-3

I'm building a memory Flash game, in which there's a timer that gives you a certain amount of time to finish the deck of cards. The code for this timer is shown below:
public function memory():void
{
levelDuration = 10;
gameTime = levelDuration;
var gameTimer:Timer = new Timer(1000,levelDuration);
gameTimer.addEventListener(TimerEvent.TIMER, updateTime);
gameTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timeExpired);
gameTimer.start();
}
function updateTime(e:TimerEvent):void // what happens when the time runs out
{
// your class variable tracking each second,
gameTime--;
//update your user interface as needed
timeText.text = "Tijd : " + String(gameTime); //gameTime is defined before the public function memory
}
function timeExpired(e:TimerEvent):void
{
var gameTimer:Timer = e.target as Timer;
gameTimer.removeEventListener(TimerEvent.TIMER, updateTime);
gameTimer.removeEventListener(TimerEvent.TIMER, timeExpired);
finalScore = score;
musicchannel.stop();
gameTimer.stop();
MovieClip(root).gotoAndStop("gameover");
}
Now, this works fine. The timer counts down, and when it expires, it brings you to the gameover screen. However, when you finish the game BEFORE the time expires, the timer doesn't stop. It will bring you back to the gameover screen when it decides it has run out, even when you've started a new game.
I've tried to fix this by putting gameTimer.stop() in other functions that bring you to the gameover screen, but then there was another problem. This occurred while trying to stop the timer in other functions, like this one (stop button while playing):
function stopplaying(event:MouseEvent){
gameTimer.stop();
finalScore = score;
musicchannel.stop();
MovieClip(root).gotoAndStop("introduction");
}
This will give me a compile error 1120: access of undefined property gameTimer.
I understand that the gameTimer usually can only be influenced within a function if that function listens to a TimerEvent, but I don't see any options to do this in any other way.
I've tried to make gameTimer a public variable, but it won't allow me to do that within the main memory function.
Also, when I try to define it a public variable out of a funcion, but within the class, the timer will still count down. But when it expires, it just gives a random high number in return and doesn't go to the gameover screen.
I hope the explanation of my problem wasn't too vague and that you are able to help me with this. This is a schoolproject and it's due pretty soon! Also, I can't figure this out on my own with internet alone :( Several tries have only made things worse, I'm afraid to screw this up now that I've come this far.

You were doing it probably right-ish by declaring it as a public variable.. but where did you declare it?
In AS (all versions) you have function scope. That means if you declare your variable inside a function, that variable "exists" (is accessible) only inside of that function. Check where you are declaring your variable:
public function memory():void
{
levelDuration = 10;
gameTime = levelDuration;
var gameTimer:Timer = new Timer(1000,levelDuration); // <-
gameTimer.addEventListener(TimerEvent.TIMER, updateTime);
gameTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timeExpired);
gameTimer.start();
}
That means your variable "gameTimer" is local to the function memory(). You won't be able to use your variable anywhere outside of this function because it exists only inside of memory(). To solve this issue, you have move it outside of the function:
private var gameTimer:Timer;
public function memory():void
{
levelDuration = 10;
gameTime = levelDuration;
gameTimer = new Timer(1000,levelDuration);
gameTimer.addEventListener(TimerEvent.TIMER, updateTime);
gameTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timeExpired);
gameTimer.start();
}
That will solve all your issues.

Related

AS3 running an event for a set duration after button (or anything) event

For the purposes of the question, Imagine I have an object onstage. When I click on another button, I want the colour to change for 1 second, then revert back again when finished.
Here's what my demo code looks like:
Button.addEventListener(MouseEvent.CLICK, Colour_Change);
function Colour_Change(evt: MouseEvent): void {
var my_color: ColorTransform = new ColorTransform();
my_color.color = 0xFF0000;
Coloured_Object.transform.colorTransform = my_color;
}
What I am wanting is some sort of timer function to be incorporated in the above function. I haven't got any idea how to do it, hence why there's no implementation.
You should use the flash.utils.Timer class.Adobe ActionScript 3.0 Reference for the Timer class
The following should be enough to get you headed in the right direction:
import flash.utils.Timer;
var myTimer:Timer = new Timer(1000, 1); // 1 second
var running:Boolean = false;
Button.addEventListener(MouseEvent.CLICK, Colour_Change);
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
function Colour_Change(evt: MouseEvent): void {
var my_color: ColorTransform = new ColorTransform();
my_color.color = 0xFF0000;
Coloured_Object.transform.colorTransform = my_color;
if(!running) {
myTimer.start();
running = true;
}
}
function runOnce(event:TimerEvent):void {
// code to revert the button's color back goes here
myTimer.reset();
running = false;
}
Let me know if you need more help or if this example has errors via this answer's comments section.
To further explain the Timer class as used above:
when creating a new timer
myTimer=new Timer(1000,1)
the first number in the brackets is the number of milliseconds you want the timer to run for (e.g. 1000 = 1 second)
The second number is how many times you want the timer to repeat (or 0 for infinite repetition).
Every time the timer reaches the time you entered (1000), this is will trigger any event listeners for the event Timer_Event.TIMER, so for example if u wanted to make it change color on and off, you could have multiple repetitions on the timer and change the function.
Other useful things timers can do:
You can add an event listener for
Timer_Event.TIMER_COMPLETE
(goes off when all repetitions are complete)
myTimer.currentCount
will return the number of repetitions the timer has done so far.
To do that you can use, as other answers said, a Timer object or the setTimeout() function, like this :
// the current color of our target object
var default_color:ColorTransform;
// the delay in milliseconds
var delay:int = 1000;
btn.addEventListener(MouseEvent.CLICK, Colour_Change);
function Colour_Change(evt: MouseEvent): void {
// save the current color of our target object
default_color = target.transform.colorTransform;
var new_color:ColorTransform = new ColorTransform();
new_color.color = 0xFF0000;
target.transform.colorTransform = new_color;
var timer:Timer = new Timer(delay, 1);
timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
// after the delay, we use the default color of our target
target.transform.colorTransform = default_color;
})
timer.start();
// using setTimeout(), you have to disable this if using the Timer
var timeout:int = setTimeout(
function(){
clearTimeout(timeout);
// after the delay, we use the default color of our target
target.transform.colorTransform = default_color;
},
delay
);
}
Hope that can help.

How to get the width of a MovieClip for a different frame instantly?

Is there a way to get the width of a MovieClip (that does have a name) on a different frame? I have tried to using .width and .getBounds(null).width, however, both of them will give me only the width of the current frame. I have tried to do gotoAndStop(frameiwant), but the information doesn't seem to be correct until at least the next frame
I would like to get the width of the frame instantly so I don't have to wait until the next frame for the width.
The only way I could think of doing this was to have an initial phase in your project which will:
Run through all of the frames in your timeline. Create an object which will hold information about the children in that frame. It can be called Frame.
Iterate over all the children that are added to the stage in that frame and add a definition object that describes that child. The description can be as basic or vast as you need. We can call this class an ObjectDefintion.
The downside of this process is that you need to wait for the FRAME_CONSTRUCTED event like #Larusso pointed out in his answer. This means that the frame actually has to finish rendering before you are able to get information about its children, which of course means you have to go through and render every single frame in your timeline during this phase. All you can really do to mitigate this problem is set the frameRate to something high and then set it back when you're done assessing all the frames.
I have set this up and it works well - I'll paste each class and try explain what they do.
So for your document class (or whichever MovieClip holds the frames you want to look at), I have this:
public class Main extends MovieClip
{
private var _userFrameRate:int;
private var _frames:Vector.<Frame> = new <Frame>[];
public function Main()
{
_userFrameRate = stage.frameRate;
stage.frameRate = 120;
addEventListener(Event.FRAME_CONSTRUCTED, _assess);
}
public function getFrame(index:int):Frame
{
return _frames[index - 1];
}
private function _assess(e:Event):void
{
var frame:Frame = new Frame(this);
_frames.push(frame);
if(currentFrame === totalFrames)
{
removeEventListener(Event.FRAME_CONSTRUCTED, _assess);
gotoAndStop(1);
stage.frameRate = _userFrameRate;
ready();
}
else play();
}
public function ready():void
{
// Start here.
// There is a MovieClip on frame 10 with the instance name 'test'.
// We can get the width of it like this.
trace( getFrame(10).define("test").property("width") );
}
}
This basically initializes the phase in which we will run over each frame in the MovieClip and assess its children. The ready() method is used as the entry point for your code post-assessment.
Next we have the Frame class, which serves to hold information about children related to a frame:
public class Frame
{
private var _main:Main;
private var _content:Object = {};
public function Frame(main:Main)
{
_main = main;
update();
}
public function update():void
{
_content = {};
for(var i:int = 0; i < _main.numChildren; i++)
{
var target:DisplayObject = _main.getChildAt(i);
// This will be explained below.
var definition:ObjectDefinition = new ObjectDefinition(target, "x", "y", "width", "height");
_content[target.name] = definition;
}
}
public function define(name:String):ObjectDefinition
{
return _content[name];
}
}
It's pretty straightforward - you give it a reference to Main so that it can check children that are existent within it each frame.
The ObjectDefinition class is also pretty straightforward, acting purely as a repository for data that you want to keep track of on each child of the frame:
public class ObjectDefinition
{
private var _definition:Object = {};
public function ObjectDefinition(target:DisplayObject, ...properties)
{
for each(var i:String in properties)
{
_definition[i] = target[i];
}
}
public function property(property:String):*
{
return _definition[property];
}
}
You'll notice that the constructor accepts the target DisplayObject that will be defined, as well as any amount of properties you want to keep track of as strings (see above within Frame for implementation).
Once complete, you can chain the methods Main.getFrame(), Frame.define() and ObjectDefinition.property() to get properties of children that will exist throughout the timeline. For example, if you have a MovieClip with the instance name square on frame 15 and you want to get its width and height, you can do this within .ready() like so:
var square:ObjectDefinition = getFrame(15).define("square");
trace(square.property("width"), square.property("height"));
Of course this process is not ideal - but unfortunately it is the only way I can see that what you want to achieve is possible.
You have to listen to a specific event before you can ask for the information.
clip.addEventListener(Event.FRAME_CONSTRUCTED, frameReadyHandler);
clip.gotoAndStop(frame);
function frameReadyHandler(event:Event):void
{
clip.removeEventListener(Event.FRAME_CONSTRUCTED, frameReadyHandler);
var width = clip.width;
}
The Frame constructed event is the first of several events that gets dispatched. It gets dispatches right before the frame script gets executed. You could also wait for the on enter frame event.
You could add an event listener for 1 millisecond and test if the previousWidth you had stored is different. If it is, there you go. If not, its probably listening to the same frame.
A 1 millisecond timer is not such a big deal, stop it if you don't need it, resume it if you do, else, keep it running constantly. When it changes, dispatch an event or whatever needs to happen.
If you know the maximum size of the MovieClip, you may try this:
// Create movie clip
var movie :MovieClip = new MovieClipWith3Frames();
// Move to second frame
movie.gotoAndStop(2);
// Create bitmap witch magenta background
var bd :BitmapData = new BitmapData(200, 200, false, 0xFF00FF);
// Draw second frame
bd.draw(movie);
// Found the bounds of shape
var movieBounds:Rectangle = bd.getColorBoundsRect(0xFFFFFF, 0xFF00FF, false);
trace(movieBounds); // (x=42, y=15, w=32, h=33)

Need help using a timer in Action Script 3

Alright, so I am fairly new to AS3 and I have a level in my game where you have to stay alive for 45 seconds. If I use a code like (Or if there is a better code, I'll use that one)
var myTimer:Timer = new Timer(1000, 1); // 1 second
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
myTimer.start();
function runOnce(event:TimerEvent):void {
trace("runOnce() called # " + getTimer() + " ms");
}
How can I use this to make my game move to scene 6 if they stay alive for 45 seconds? I also want to display text on the animation that keeps track of how long they've been alive so they know how long they have left. How could I accomplish this?
private var startTime:int;
function startGame() {
// this is called when your game starts
startTime=getTimer();
... // rest of init code
}
function onEnterFrame(e:Event):void {
// main loop, whatever you need to do in here
currentTime=getTimer()-startTime; // here we receive the elapsed time
// pause handling is excluded from this example!!11
if (weAreDead()) {
survivalTime= currentTime;// here
...
} else if (currentTime>45000) {
//advance to scene 6 here
}
}
Set the listener for Event.ENTER_FRAME to onEnterFrame, start the game with setting the stored time, and pwn.
The simplest solution is to go ahead and use the timer, but set the value to 45000 and make sure to keep a reference of the timer or it will be garbage collected. Also, create a separate function which allows you to kill the timer from anywhere if this particular thing ever needs to just "go away" without completing.
public static const DELAY:int = 45;
private var _timer:Timer;
public function setTimer():void
{
_timer = new Timer( DELAY * 1000, 1 );
_timer.addEventListener( TimerEvent.TIMER_COMPLETE, timerCompleteHandler );
_timer.start();
}
private function timerCompleteHandler( event:TimerEvent ):void
{
disposeTimer();
goDoTheThingThatYouNeededToDo();
}
public function disposeTimer():void
{
_timer.stop();
_timer.removeEventListener( TimerEvent.TIMER_COMPLETE, timerCompleteHandler );
_timer = null;
}

How to stop on Enter Frame firing multiple times?

I'm trying to do a simple url requestion on enter frame, but it seems to be executing multiple times?
I tried removing the event handler on handleLoadSuccessful, that seems to stop it firing infinitely, but its still executing about 10 times before it stops.
How do I make it only fire once?
addEventListener(Event.ENTER_FRAME, onLoadHandler);
function onLoadHandler(event:Event) {
var scriptRequest:URLRequest = new URLRequest("http://ad.doubleclick.net/clk;254580535;19110122;t?http://www.gamespot.com.au/Ads/gswide/hp/1x1.gif");
var scriptLoader:URLLoader = new URLLoader();
var scriptVars:URLVariables = new URLVariables();
scriptLoader.addEventListener(Event.COMPLETE, handleLoadSuccessful);
scriptLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLoadError);
scriptRequest.method = URLRequestMethod.POST;
scriptRequest.data = scriptVars;
scriptLoader.load(scriptRequest);
function handleLoadSuccessful($evt:Event):void {
trace("Message2 sent.");
removeEventListener(Event.ENTER_FRAME, onLoadHandler);
}
function handleLoadError($evt:IOErrorEvent):void {
trace("Message1 failed.");
}
}
ENTER_FRAME is fired x times per second, where x is the document frame rate.
The code within your listening function leads me to thinking that you don't actually need the event listener or the listening function at all - if you just want what's within that function called a single time, move everything within it outside on its own.
You could also move it all into an init() function and then call that once.
Also, your functions handleLoadSuccessful() and handleLoadError() should not be defined within another function (in your case onLoadHandler()).

Flex 4 timers keep Firing

I'm trying to create a simple flex4 project which involves some timers that trigger other functions.
I don't have much experience with Action Script and even less with timer events.
Here is a bit of my code it seems to be working for the most part but you lines were I'm adding up the total score (score = score +1;) seems to just keep adding and adding when I test the application. I think its because the timers keep firing the function but I'm not sure.
private var score:int = 0;
private function submit():void {
this.currentState = 'loading';
var timer:Timer = new Timer(2200);
timer.addEventListener(TimerEvent.TIMER, removeLoading);
timer.start();
}
private function removeLoading(event:TimerEvent):void{
removeloading.play();
var timer1:Timer = new Timer(1000);
timer1.addEventListener(TimerEvent.TIMER, viewResults);
timer1.start();
this.currentState = 'results';
}
private function viewResults(event:TimerEvent):void{
if (q1_t.selected == true){
answer1m.text = 'You Answer the Question Correctly.';
score = score +1;
} else {
answer1m.text ='The Correct answer was: '+ q1_t.label;
}
if (q2_f.selected == true){
answer2m.text = 'You Answer the Question Correctly.';
score = score +1;
} else {
answer2m.text ='The Correct answer was: '+ q2_f.label;
}
finalscore.text = score.toString();
}
So I did a bit more research and turns out I hadn't included the second timer parameter.
The second parameter is the number of times that the TimerEvent.TIMER event will be dispatched before stopping. If you set the second parameter to 0 (zero) or omitted it completely, the timer would run forever (or until you called the stop() method on the timer instance.
Since I only want to run the event once I need to add 1.
From this:
var timer:Timer = new Timer(2200);
To this:
var timer:Timer = new Timer(2200,1);