Actionscript 3: Pausing a game - actionscript-3

Hey so I'm working on pausing my game. I have it almost working, but there's a couple malfunctions that I can't seem to understand.
Basically I have some code (below) that pauses the frame rate and then resumes the frame rate. Both snippets of code work correctly individually, but when put together, if I press "p" it instantly cycles through both snippets of code, effectively only executing the second one (I put traces in and it shows that both codes are being executed when I press "p" once.)
So my first and primary question is how do I get this to work? I just want to execute one snippet of the code when "p" is pressed to pause the game, and then after that occurs, be able to press "p" again and execute the other snippet.
My second question is...why when I trace the frame rate does it say it is 0.01 instead of 0? Found this sort of interesting....Anyways, here's the code. Tell me if you need more context, but I don't think you will.
if (stage.frameRate == 30)
{
if (keyboardEvent.keyCode == Keyboard.P)
{
dispatchEvent(new NavigationEvent(NavigationEvent.PAUSEGAME));
stage.frameRate = 0;
checkIfPaused = true;
trace("pause game");
trace(stage.frameRate);
}
}
if (stage.frameRate == 0.01)
{
if (keyboardEvent.keyCode == Keyboard.P)
{
stage.frameRate = 30;
dispatchEvent(new NavigationEvent(NavigationEvent.RESUMEGAME));
checkIfPaused = false;
trace("resume game");
}
}

Nevermind, I figured it out. I just added else if instead of if for the second snippet and now it works =), but if anyone can answer my question about the frame rate being 0.01 in a nice fashion I'll give the answer to you

Related

Actionscript 3 equivalent of KeyboardEvent.Repeat

I'm very much a beginner when it comes to programming; I'm doing a flash game for my 2D Game class on Adobe Animator, and I had a doubt about the code that my instructor couldn't answer himself. Long story short, I want the character speed to increase based on how long the key has been pressed, so I came up with this:
spdX = spdX + aclMov*(tempo) - aclFrc*(tempo);
Where the variable tempo would increase as long as the key is being held down, and I would check if it is with KeyboardEvent.repeat, as in:
if(heldDown){while(heldDown){tempo += 1}}
else{tempo = 0}
spdX = spdX + aclMov*(tempo) - aclFrc*(tempo);
However when I try to do that, the output responds with "Property repeat not found on flash.events.KeyboardEvent and there is no default value". I assume that this is because KeyboardEvent.repeat is not defined in the medium I'm using. Is there anyway I can reproduce the same effect of KeyboardEvent.repeat, perhaps by creating a function that mimics what it would have done?
Thanks in advance.
(Edit 1)
I begin apologizing for my shortness of clarification, as well as my ignorance in the topic as I am barely a beginner when it comes to as3, and am not properly presented yet to many of the terms I've read.
So, thanks to the meaningful contributions of comments, I already have been given a glimpse of what kind of workaround I would need to do to substitute KeyboardEvent.repeat. There are other parts of the code of relevance to the problem, as well:
stage.addEventListener(KeyboardEvent.KEY_DOWN,pressKey)
function pressKey (Event){
(...)
if(Event.keyCode == (Keyboard.A)) {left = true;}
(...)
}
stage.addEventListener(KeyboardEvent.KEY_UP,releaseKey)
function releaseKey (Event){
(...)
if(Event.keyCode == (Keyboard.A)) {left = false;}
(...)
}
This is how the code was intended to go. It was suggested that I use the getTimer() method to record the moment the event KEY_DOWN happens, stopping when the KEY_UP comes into effect. Problem is, how can I increment the code to make it differentiate between those two events, and more specifically, how can I adapt the ENTER_FRAME event so that differentiating between them still works with it? Here's the most relevant parts of it, by the way:
addEventListener(Event.ENTER_FRAME,walk);
function walk(Event) {
if(left) {
(...)
char.x -= spdX;
(...)
}
I assume that the code worked up till now because, as the state of "left" constantly switched between "true" and "false", the if conditional was met repeatedly, leading the character to move. However, if I try to make it so that the conditional depends on "left" staying "true" for a certain time, the code becomes incompatible with itself.
In short, it brings the question of how to adapt the "KEY_[]" event listeners and the "walk" function to work, in using the getTimer() method, to work together.
Again, thanks in advance.
I believe that would be somehow self-explanatory .
stage.addEventListener(KeyboardEvent.KEY_DOWN, onDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onUp);
addEventListener(Event.ENTER_FRAME, onFrame);
var pressedKeyA:int;
// Never name variables and arguments with the same name
// as existing classes, however convenient that might seem.
function onDown(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.A)
{
// Let's record the moment it was pressed.
pressedKeyA = getTimer();
}
}
function onUp(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.A)
{
// Mark the key as not pressed.
pressedKeyA = 0;
}
}
function onFrame(e:Event):void
{
// It is true if it is not 0.
if (pressedKeyA)
{
// That's how long it has been pressed. In milliseconds.
var pressedFor:int = getTimer() - pressedKeyA;
// Change the position with regard to it.
// For example 1 base + 1 per second.
char.x -= 1 + pressedFor / 1000;
}
}

AS3: pass Keyboard control to child movieclip and back to main timeline

EDIT: I don't know if this is the norm, but I preferred to leave the original question in and add updates. Please, feel free to let me know if I should eliminate the original code snippets and somesuch.
I am trying to create a slideshow-like presentation in flash CS6, using a main timeline with one symbol in each frame and the different animations (some quite complex) in those symbols. Since I'm going to use a presenter remote, I've captured the keystrokes and coded pg_up and pg_down to go to the next and previous frame respectively:
stage.addEventListener(KeyboardEvent.KEY_DOWN, pagerFunction);
var symb:movieClip;
function pagerFunction(e:KeyboardEvent):void
{
var myKey = e.keyCode;
if (myKey == Keyboard.PAGE_DOWN){
if (symb != null){
//some code that allows to control the symbols timeline forward
} else {
nextFrame();
}
}
if (myKey == Keyboard.PAGE_UP){
if (symb != null){
//some code that allows to control the symbols timeline backward
} else {
prevFrame();
}
}
The problem I'm having is the following. I've added framelabels and stop(); code inside the symbol animations where I needed to control the step from one animation to the next one. However, after having tried numerous solutions on the web, I haven't been able to succeed having the symbols react to pg_up and pg_down as if they were part of the main timeline.
To sum up, what I need to solve is this:
Enter Main timeline Frame
Identify symbol instance (labeled as _mc)
Inside symbol timeline, play from first frame (labeled '0') until next labeled frame ('1' and so on)
stop and wait for next pg_down to start playing from next labeled frame to the following (i.e. '1'-'2'), or pg_up to start playing from the previous labeled frame (i.e. '0' to '1') (for this, I would use a variable to keep track.
on last frame (labeled 'final') exit symbol focus and return keyboard control to main timeline to allow pg_down and pg_up to move to the next / previous frame. on pg_up on symbol.currentFrame == 0, do same.
BTW, if there's a better way to achieve this, I'm open (and quite desperate) for better suggestions / solutions.
Thank you so much to anyone who can help!
Edit: Ok, I guess I wasn't too clear on the issue, so I'll try to add a bit to this:
addEventListener(KeyboardEvent.KEY_DOWN, mc_pagerFunction);
var lbl:String;
var counter:Number = 0;
function mc_pagerFunction(e:KeyboardEvent):void {
var myKey = e.keyCode;
if (myKey == Keyboard.PAGE_DOWN){
lbl = this.currentFrameLabel;
if (this.currentFrameLabel == 'final'){
stop();
stage.focus = this.parent; //which would be the main timeline
} else if (Number(lbl) == counter){
this.gotoAndStop(lbl);
counter++;
} else {
this.gotoAndPlay(lbl);
}
}
if (myKey == Keyboard.PAGE_UP){
lbl = this.currentFrameLabel;
if (this.currentFrameLabel == '0'){
stop();
stage.focus = this.parent; //which would be the main timeline
} else if (Number(lbl) == counter){
this.gotoAndStop(lbl);
counter--;
} else {
this.gotoAndPlay(lbl);
}
}
}
Now, this bit is the behaviour I'd like to see inside the symbol when the main timeline goes into the next frame, thus being able to use the main timeline as sort of slideholder and the real thing happening inside the symbol.
Btw, I'd like to try and keep all code within the main action layer, not in the symbols. I tried that, shifting focus to the symbol and it didn't work either, and having code all over the place grates against my nerves ;).
I hope this throws some light on what I'm stuck at.
Again, any help is appreciated. Thanks all in advance
UPDATE:
Please someone help me out here!
This is what I'm trying. Logically, it makes all the sense in the world, except that it doesn't work.
var symb:MovieClip;
symb = MovieClip(root); //assign symbol I want to be controlled by pg_up/pg_down
symb.focusRect = false;
stage.focus = symb; //focus on current symbol
symb.addEventListener(KeyboardEvent.KEY_DOWN, mc_pager); //add keyboard event listener
function mc_pager(e:KeyboardEvent):void{
var myKey = e.keyCode;
if (myKey == Keyboard.PAGE_DOWN){
do{
symb.play(); // it plays, then checks if the lbl is null or final, then quits
} while (symb.currentFrameLabel == null && symb.currentFrameLabel != 'final');
symb.stop();
symb.removeEventListener(KeyboardEvent.KEY_DOWN, mc_pager);
stage.focus=MovieClip(root); //return focus to main timeline (in the next keyframes, the focus is on the nested _mc
}
if (myKey == Keyboard.PAGE_UP){
do{
symb.prevFrame();
} while (symb.currentFrameLabel == null && symb.currentFrameLabel != '0');
symb.stop();
symb.removeEventListener(KeyboardEvent.KEY_DOWN, mc_pager);
stage.focus=MovieClip(root);
}
}
Where am I being to moronic to get it right? Please, guys, you're the experts, I need your advice here. Thanks!
UPDATE:
Doing a trace on symb, it seems like as soon as it enters the function, it forgets the initial assignment (symb = MovieClip(root)) and shows null. Why?
In this sample, I created a basic proof of concept where I have a circle MC with an instance name of "c" on the main timeline. Within this mc, I created with 2 keyframes inside with stop actions on both. I colored the circle a different color on frame 2 and labeled it as "two".
In the Main timeline I have the following code:
import flash.events.KeyboardEvent;
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyEvt);
function keyEvt(e:KeyboardEvent):void{
if(e.keyCode == Keyboard.PAGE_DOWN){
trace("down");
c.gotoAndPlay("two");
}
}
This should help form a foundation for your code as long as you stick with targeting the symbol through direct reference and ensure your keyboard event is attached to the stage.
Also, always stick with getting a basic working version down first. I.E. Check to see if your keyboard listeners are working for your target object and then build additional functionality off of that.

Having trouble advancing frame in AS3 to advance frames

I'm creating a quiz with buttons and I'm new to ActionScript 3.0, but very familiar with 2.0.
I have a variable inside of a MC called NextQuestion. When it reaches a certain frame, it changes to 1, then back to 0.
On the main timeline, when NextQuestion == 1, it's supposed to NextFrame();. I can't get it to work though, this is the last thing I'm having trouble with.
This is my main code with 4 buttons, 3 wrong, 1 right. The feedback MC plays an animation, and when it finishes, it sets the VAR NextQuestion to 1, which is supposed to make the main timeline advance to the NextFrame.
stop();
right.addEventListener(MouseEvent.CLICK, rightClick1);
wrong1.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong2.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong3.addEventListener(MouseEvent.CLICK, wrongClick1);
feedback1.addEventListener(Event.ENTER_FRAME, answerRight1);
function answerRight1()
{
if (feedback1.NextQuestion == 1)
{
trace(feedback1.NextQuestion);
nextFrame();
}
else
{
trace("do nothing");
}
}
function rightClick1(ev:MouseEvent):void
{
trace(feedback1.NextQuestion);
feedback1.gotoAndPlay("right1");
}
function wrongClick1(ev:MouseEvent):void
{
trace("wrong");
feedback1.gotoAndPlay("wrong");
}
Any help is greatly appreciated! :)
The nextFrame() method in AS3 doesn't loop trough your movieClips, it just set's the movie clip to the next frame provided there is a next frame, otherwise it does nothing.
you might want to re-write the nextFrame() to:
if (totalFrames == currentFrame)
{
gotoAndStop(1); // or gotoAndPlay(1) if you need
}
else
{
nextFrame();
}
Thats regarding why the movie clip might not start from the beginning.
Another thing that look weird is that you need a FRAME_ENTER event to check if the answer is correct. You must have a lot of spam in the output log. I'd recommend you to totally ditch the ENTER_FRAME event listener for this and do it all with the CLICKED event and dispatching the event from the feedback1 object.
As much as I understand the movie clip plays when you click a button and when the animation is over you want to either progress to next frame or do nothing. If so, on the feedback1 object add a following line in the end of animation for label "right1":
dispatchEvent(new Event("right"));
and instead of the line feedback1.addEventListener(Event.ENTER_FRAME, answerRight1); have:
feedback1.addEventListener("right", answerRight1);
That way you won't need to check the answer on every frame and you don't need to check if the answer is right or not, because when the dispatchEvent(new Event("right")); fires - it's always right.
Hope I didn't misunderstand your question :)

AS3 Button to stop Movieclip after its finished playing

Ok, so I'm a beginner at AS3 and Flash and I managed to put this code together for an animation. A Button called start_btn is supposed to start and stop a movieclip called main_mc. On the first click of the Button, the Movieclip is supposed to play (which it does), however on the second click, the movie stops in the middle of its animation (which I don't want). My question is, when you click the Button a second time, how can i get the Movieclip to finish playing its animation then stop on the last frame?
I thought about using if (main_mc.currentFrame == main_mc.totalFrames); {main_mc.stop(); but the Movieclip still does not stop on the last frame. The Movieclip itself also has a gotoAndPlay(2); command on the last frame so that the animation repeats before the Button is clicked a second time.
here is the code i have:
`start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
function mainaniS(event:MouseEvent):void
{
main_mc.play();
start_btn.removeEventListener(MouseEvent.CLICK, mainaniS);
start_btn.addEventListener(MouseEvent.CLICK, mainaniSt);
}
function mainaniSt(event:MouseEvent):void
{
if (main_mc.currentFrame == main_mc.totalFrames);
{main_mc.stop();}
start_btn.removeEventListener(MouseEvent.CLICK, mainaniSt);
start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
}`
Try main_mc.gotoAndStop(main_mc.totalFrames).
I was going to provide a quick and dirty solution, but decided instead to try and explain a few of the issues with your current implementation and attempt to refactor and explain and better one. Unfortunately I don't have access to Flash right now, so the code is untested.
You're adding and removing event listeners often, which is generally a bad idea. Instead, since you're using a single button to perform multiple functions it would make sense to track the button state in a separate variable. In this case, a boolean for whether or not the movieclip is currently playing.
var playing:Boolean;
Now we can combine the mainaniS and mainaniSt into one and perform a different action based on whether or not the movieclip is playing, and just keep the one eventlistener on the button. I've also taken the liberty of naming the method something more meaningful:
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
You may be wondering why we don't call main_mc.stop() in the first block: the reason is that you don't want to stop the movieclip as soon as you click the button, but after the movieclip has finished playing if the button has been clicked. Therefore, we just set playing to false to indicate that we want it to stop later.
Finally, we need to make sure the movieclip stops upon completion, but only if playing is false. To do this we add a listener to movieclip that is called every frame, and checks whether playing is false, and if it's on the last frame. Note that the last frame is actually totalFrames - 1: this is because the frame numbers start from zero rather than one (i.e. if totalFrames is 3, the frame numbers will be 0, 1, 2).
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}
All the refactored code together:
var playing:Boolean;
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}

Parameter child must be non-null error in AS3

I have a code to pause the game, and it runs the pause function as shown:
public function onKeyPress(keyboardEvent:KeyboardEvent) :void
{
//Check for pause
if(keyboardEvent.keyCode == Keyboard.P)
{
//If the timer is still running
if(gameTimer.running)
{
gameTimer.stop();
Mouse.show();
pauseText = new PauseText();
pauseText.x = 150;
pauseText.y = 100;
addChild(pauseText);
//If the player is using the mouse, resume by clicking on the player
if(mouseControl)
{
player.addEventListener(MouseEvent.CLICK, resumeGame);
pauseText.pauseInformation.text = "click on yourself";
}
else
{
pauseText.pauseInformation.text = "press 'p'";
}
}
else
{
//Only allow the player to resume with P IF he is using the keyboard
//This prevents cheating with the mouse.
if(!mouseControl)
{
gameTimer.start();
removeChild(pauseText);
pauseText = null;
}
}
}
}
The game runs perfectly fine. On my first playthrough, the pause functions work. However, if later I die and restart the game, then pause it, I get the following message:
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/removeChild()
at Game/onKeyPress()
The game still runs fine though. However, everytime I pause, or unpause, this error appears. If I die again, restart, then pause, TWO of these errors appears. From what I can gather it seems as if it attempts to remove the pauseText…but I’ve been removing it just fine on the first playthrough, I’ve used removeChild() then set as null for other parts of my code and it works fine. Additionally, if I add a trace(“a”); statement right after the function header, I get the error before the “a” appears on the output panel.
What’s wrong?
Additional notes:
If I don’t use the pause function at all for my first playthough, there is no error when I call it up on my second playthrough.
put removeChild into 'if' ,this will solve error :
if(pauseText.parent){
pauseText.parent.removeChild(pauseText);
}
but You should anyway check what is the source of problem , maybe 'gameTimer.running' is false on beggining ?
You probably instantiate another Game object (the one that contains the whole game) while not removing the previous game's event listener. That would explain such behavior, since you have more than one KeyboardEvent.KEY_DOWN listener active, and note that when you're stopping the game, you most likely stop the timer in it, so the "else" clause of your "if (gameTimer.running)" statement is executed, but the timer was effectively stop without pauseText to be generated. So, you miss a
removeEventListener(KeyboardEvent.KEY_DOWN,onKeyPress);
in your game destruction code.
if (!mouseControl) {
gameTimer.start();
if (pauseText && contains(pauseText)) {
removeChild(pauseText);
pauseText = null;
}
}