AS3 key presses cause animation error - actionscript-3

I'm making a game and basically I'm having some errors with the animation state.
public function movementChar()
{
if (touchingGround)
{
if (rightKey)
{
gotoAndStop("run");
scaleX = 1;
}
if (leftKey)
{
gotoAndStop("run");
scaleX = -1;
}
if (upKey)
{
gotoAndStop("jump");
this.y -= 15;
//touchingGround = false;
}
if (attackKey)
{
gotoAndStop("attack");
}
if (!rightKey && !leftKey && !upKey && !attackKey)
{
gotoAndStop("stop");
}
}
}
I have some other coding which says if the player is touching the ground then touchingGround = true;
and if it is true then the player can move right, left, jump and attack.
The problem is that when I press the attack key, it keeps on looping the animation and attacking.
I want the attack key to play the animation once and make the boolean hasAttacked = true; once.
Another problem is that when the player is moving and the attack key has been pressed/ hold down the animation freezes. Flash gets confused on which animation to play so it stops at frame 1 and glitches.
I would appreciate it if someone can give me an idea on how to fix this.
Thank you.

Ok I have a few recommendations. First let's address the fact that your attack animation is looping. You will need to go into the SirTimmyAttack movieclip timeline and add
stop();
In to frame 4 to keep the animation from looping forever. After you do that the animation will play once. You have a timer that you are starting when you tell him to attack, after the timer execute he will attack again. So if you hold the "A" key he will ATTACK...Wait for timer...ATTACK...Wait for timer....ATT ect. if you want him only to attack once per press of the "A" key remove that timer and never start it.
On to address your second concern about the player being unable to attack and walk at the same time. That is a technical limitation of the way you are currently animating. Since the players entire animation is contained inside a set of frames you cant mix and match to combine them. I would suggest breaking your player graphics/animations into to halves. An Upper body, and a lower body. That way you can trigger walking/running/standing animations independently from the upperbody/attack animations.
Hope this helps, let me know if you have any other questions.

I don't have my flash dev stuffs on my current machine so I can't open the fla but:
I suspect that this is caused by not 'consuming' the key event. i.e. presumably you are setting rightKey, leftKey, attackKey etc on key up and key down events and checking the state during the update function?
The problem with this is that each update it will act as if pressing the key the first time, every time, you need some method of knowing that the key press has been handled.
As I say I can't check your fla so I can't comment on the best method but I suspect you may have to substantially change your input handling.

Related

Use AS3 to turn on/off a graphic's visibility

I found other threads/questions that were similar but didn't quite provide the answer I need.
This should be incredibly simple, but I'm not very versed in AS3 yet so I'm stuck.
I have a movie clip on the stage whose alpha is set at 0. I want to make it so that when I press a certain key on my keyboard the alpha for that movie clip is set to 1 (100%). I already have several other keys coded in AS3 to do other actions (jump to certain frames in the timeline, move certain objects up, down, left and right, etc). So I added this code:
if (e.keyCode == 77){
graphic_object.alpha == 1;
}
"graphic_object" is the instance name for the movie clip I want to show.
However, when I press the "M" key (77), nothing shows up. The movie clip apparently remains at 0.
So what's the incredibly simple resolution to this that I'm overlooking?
Thanks.
== => comparison
= => setter
graphics_object.alpha = 1;

Actionscript 3: How to have a keyboard Keystroke "Button" go to specific Frame FROM a specific Frame?

I'm Super New to Programming in general and very New to Actionscript 3. It's been a rough but fun ride.
Anyway For the work I am doing I have my animation Play up to a certain point and it asks the viewer a question, The viewer has 3 choices, and each of those choices are connected to a button on the keyboard. A B C or D.
After searching for someone with a similar problem, My solution so far is this:
stage.addEventListener(KeyboardEvent.KEY_DOWN, cNote);
function cNote(event:KeyboardEvent):void {
trace(event.keyCode);
if (event.keyCode==67) {
gotoAndPlay(21);
}
I have this repeated 4 times each for the different Keys.
This works and allows me to move the viewer to the Frame with their response, however Any time during the animation they can press the button and it will move them to the Frame of the corresponding button (in this case Frame 21). How do I set it so that the keypress will only respond and move them to Frame 21 when they are on Frame 20 for example? (I suspect it has something to do with the "stage" part in the code but I cant get it to work without it.)
I also have the audio for the animation on a separate Layer and even though the visuals change as it goes to the correct frame, the audio continues as if the key was not pressed. Is there also a way to connect the key to make it stop the current audio and then play the new audio? Or is there a better way to do this?
Sorry if this is confusing. Thank you for your help :)
It has been quite awhile since I touch flash. From what I remembered, you can click on the frame at your movieclip, insert a keyframe by pressing f6, and press f9 to insert the listener at that frame and that frame only, after an input has been pressed, you remove it. for example:
if (event.keyCode==67) {
gotoAndPlay(21);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, cNote);
}
For the audios, I usually plays them using code, but I'm quite sure there's a way to drag and drop the audio from library to the movieclip. so I can do sound1.play(), when a button is pressed, I can do sound1.close() and sound2.play()
For more reference:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html

Keyboard listener is killing my framerate

I'm working on a game that uses four simultaneous key presses. It all works fine, except that when the keys are rapidly pressed, my framerate slows down significantly (if I hammer even just one of the keys, I can halve the framerate).
I initially just assumed that there was too much going on in the method that the key press triggers, but if I take the code out of the method completely, the slowdown still occurs.
Has anyone run into this before? The keypress is one where you hold the key down, so it's repeatedly firing a method call every frame, but this is pretty standard for many uses and I've never encountered this before.
EDIT: clarification.
Structurally, there's a KEY_DOWN and KEY_UP listener attached to the stage:
stage.addEventListener(KeyboardEvent.KEY_DOWN, menuKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, menuKeyUp);
which then calls a method with a single switch statement in, that contains five lines like this:
case ONE: pressing1 = true; break;
There's an ENTER_FRAME event that checks to see if any of the boolean flags are true, and handles character movement. This calculation happens regardless of key presses (i.e. if you let go of the keys, gravity still has an effect). This holds 60fps easily.
The issue is literally at the exact moment the key is pressed or released, there's an almost imperceptible frame drop. Repeatedly pressing the keys causes the framedrop to get worse and worse. Holding a key down doesn't kill the framerate, apart from the single split second frame drop when the key is pressed down. After that the game carries on as normal. Letting go of the key causes another tiny hitch and then the framerate goes back to normal.
EDIT 2 - I added a framerate checker so I could see exactly what was happening to the framerate. Interestingly, I can't make it go any lower than EXACTLY 30fps even when I press keys very rapidly. Is there some sort of restriction in play here with Flash Player?
Turns out that the code was correct all along. Playing 60FPS content in the debug player or the standalone player causes any events (mouse and keyboard) to hitch the framerate. Viewing the same content in a browser, or exported to AIR, stops the issue entirely. The content is now running perfectly at 60fps without any slowdown.
Hope this helps someone, I was tearing my hair out!
Do you have multiple different listeners, or one listener that appropriately routes the keypress? I would suspect the former. The solution is to switch to the latter.
What I typically do is have one object that's responsible for listening to key presses and translating keyboard events into other, more meaningful events.
For example:
protected function handleKeyboardEvent(e:KeyboardEvent):void {
if (e.ctrlKey) {
switch (e.keyCode) {
case Keyboard.A:
eventBus.dispatchEvent(new Event(ViewEventKind.SELECT_ALL));
return;
case Keyboard.Y:
eventBus.dispatchEvent(new Event(ModelEventKind.REDO));
return;
case Keyboard.Z:
eventBus.dispatchEvent(new Event(ModelEventKind.UNDO));
return;
}
}
}

If statement in AS3 not working

This is an if stament on a frame on the root. I want to loop Carrera(a lenghthy movieclip) from frame 2 back to frame 1. (For testing purposes)
This is the code:
if (MovieClip(root).Carrera.currentFrame==2){
MovieClip(root).Carrera.gotoAndPlay(1);
}
The MovieClip keeps going, ignoring the if statement.
What I'm doing working?
There's no bug with the if statement, it's just not being evaluated when you expect it to be.
When you place code in a frame, it gets executed right away, when that frame gets entered. So, when the first frame starts, the if is executed, whose condition is false at that time. And it never gets re-executed, because you never tell it to be. There is no such thing as "standing orders" in AS3 ;-)
Instead, you can check on every frame by adding an event listener:
addEventListener(Event.ENTER_FRAME, function (e) {
if (MovieClip(root).Carrera.currentFrame==2){
MovieClip(root).Carrera.gotoAndPlay(1);
}
});
Or, you can just place gotoAndPlay(1); on the second frame of Carrera (not the root).
You have to understand that you are running this if statement only once. Even if the Carrera clip is at frame 2 in that exact moment, the clip will jump to play 1 and continue playing - there is nothing to make it do the jump again, and thus there can never be a loop.
In order for this to work, you have to run this same statement again and again - every time the clip jumps to a new frame.
For example, you can do this by a) attaching this script to frame 2 of the Carrera clip (not the root!):
gotoAndPlay(1);
or b) adding an event listener to it:
MovieClip(root).Carrera.addEventListener (Event.ENTER_FRAME,
function ( ev:Event ) : void {
var cl:MovieClip = ev.target as MovieClip;
if (cl.currentFrame == 2) cl.gotoAndPlay(1);
}
There are many more ways to do this, but unless you are going to do more complicated things than jumping to frames every now and then, I would advise you to go for the first option - it seems you should learn more about ActionScript before trying out event listeners.
Things to test...
Is MoveClip(root) defined at the point in execution?
Is MoveClip(root).Carrera defined at the point in execution?
Is MovieClip(root).Carrera playing (or have you called stop on it so it's just sittin in frame 1?

AS3/CS4 removed TextField reappearing after tween finishes

I load a swf via the Loader() class. As the swf is loaded I loop through all the children of root and remove any TextField with removeChild(). This works initially - the TextField is removed. But as a tween in the loaded swf finishes and loops, the removed TextField somehow reappears. The TextField is Dynamic text. If I remove some StaticText, this stays removed. What is going on here?
loopChildren(root);
function loopChildren(dispObj:*):void {
for (var i:int = 0; i< dispObj.numChildren; i++) {
var obj:DisplayObject = dispObj.getChildAt(i);
if (obj is DisplayObjectContainer) {
loopChildren(obj);
}
else {
if (obj is TextField) {
obj.parent.removeChild(obj);
i--;
}
}
}
}
If I call loopChildren with a timer (5 sec intervall) and trace(obj.name) for all children, I notice that the obj.name changes. The TextField is called instance11, instance32, instance54 and so on. It seems that a new instance is created and added continuously?
EDIT:
If I transfer the code directly to the swf and run it without using the wrapper it works as expected. I must be missing something that happens when its loaded through another movie?
EDIT2:
I should say that the TextField I'm trying to remove is in a separate layer on the same time line as the tween. If I put the tween in its own timeline, it seems to work as expected. But can't dynamic text and tween live together?
It sounds like your text field is defined on the stage (i.e. in the FLA, not instantiated by script), and the layer it's on probably has a keyframe that is played through at some point in your tween.
If that's correct, then what you're running into is a fairly low-level limitation of Flash regarding the competing natures of the timeline and the script environment. When you play through a tween, every timeline keyframe encodes some information for Flash about what sorts of object should be on the stage at that point, and where they should be, etc.
But when you also start referencing those same object with script, in general Flash has to guess whether you want the script or the information in the timeline to take precedence. In this case, probably what's happening is that after you remove the text field with script, one of the frames your tween plays through references the same field, and Flash doesn't know whether the removal was supposed to be permanent, or whether to honor the keyframe and recreate the field.
Thus, the short answer (too late!) to your question is, in general you should try to handle your stage elements with timeline tweens, or script, but not both. This is why your solution in edit #2 worked; because by moving the tween onto its own timeline, (I'm guessing) you no longer played across keyframes that encoded information about the text field in question. Another solution would probably be to remove the offending text field via the timeline (by playing to a keyframe where that text field no longer exists). Or, of course you could also control your textfield solely by script, creating it and destroying it, so it's never part of the timeline at all.
Why not just set the text field to empty?
loopChildren(root);
function loopChildren(dispObj:DisplayObjectContainer):void
{
for each(var i:int = 0; i < dispObj.numChildren; i++)
{
var obj:DisplayObject = dispObj.getChildAt(i);
if (obj is DisplayObjectContainer)
{
loopChildren(obj);
}
else if (obj is TextField)
{
TextField(obj).text = "";
}
}
}