Fighter game as3, problems with KeyboardEvent.KEY_DOWN - actionscript-3

Well the problem is that I'm having troubles with the fighter in my game. If I use the KEY_DOWN event and/or ENTER_FRAME, when I hold down the kick or punch button the fighter continuously causes damage to the enemy but I want him either to, for example kick and then return to still position or kick and be able to hold the position but only cause the damage one time. Here's some code:
stage.addEventListener(KeyboardEvent.KEY_DOWN, enterAttack);
stage.addEventListener(KeyboardEvent.KEY_UP, exitAttack);
stage.addEventListener(Event.ENTER_FRAME, attackYes);
stage.addEventListener(Event.EXIT_FRAME, attackNo);
function enterAttack(evt:KeyboardEvent):void
{
if (evt.keyCode == 84)
{
attack = true;
}
}
function exitAttack(evt:KeyboardEvent):void
{
attack = false;
}
function attackYes(evt:Event):void
{
if (attack)
{
hero.gotoAndStop("punch1");
checkHitRed();
checkIfDead();
}
}
function attackNo(evt:Event):void
{
if (!attack)
{
hero.gotoAndStop("still");
}
}
I was trying to remove the listener somewhere but that always made it look like the fighter didn't do any attack.
Is there any way to prevent holding down kick/punch button?
Any help is appreciated

You have to devise cooldowns for your abilities, e.g. "kick" can happen only once per 20 frames. So, when the player presses kick button, char does a kick, does damage, and sets the cooldown variable. Enter frame listener starts to decrement the counter, and subsequent kick commands are ignored while the cooldown is active.
stage.addEventListener(KeyboardEvent.KEY_DOWN, enterAttack);
stage.addEventListener(Event.ENTER_FRAME, enterFrame);
var kickCooldown:int=0;
function enterAttack(evt:KeyboardEvent):void
{
if (evt.keyCode == 84)
{
if (!kickCooldown) {
attack = true;
kickCooldown=15;
}
}
}
function enterFrame(evt:Event):void
{
if (attack)
{
hero.gotoAndStop("punch1");
attack=false; // we have attacked once, now dealing damage
checkHitRed();
checkIfDead();
}
if (kickCooldown>0) kickCooldown--; // waiting for cooldown end
else hero.gotoAndStop("still"); // if ends, return hero to "still" posture
}

Character state, divide into three types. As follows.
stage.addEventListener(KeyboardEvent.KEY_DOWN, enterAttack);
stage.addEventListener(KeyboardEvent.KEY_UP, exitAttack);
stage.addEventListener(Event.ENTER_FRAME, onAction);
var characterState:String = "wait"
function enterAttack(evt:KeyboardEvent):void
{
if (evt.keyCode == 84)
{
characterState = "attack";
}
}
function exitAttack(evt:KeyboardEvent):void
{
characterState = "attack_ended";
}
function onAction(evt:Event):void
{
if(characterState == "wait") return;
if(characterState == "attack")
{
hero.gotoAndStop("punch1");
checkHitRed();
checkIfDead();
}
else if(characterState == "attack_ended")
{
hero.gotoAndStop("still");
//Revert to wait state after the attack termination .
characterState = "wait";
}
}

Related

change keyboard event to mouse event as3

I am a new new person who learn action script 3.
i have problem when i convert keyboard event to mouse event when i moving a walking character.
when use the keyboard event i have no problem. this is my code
import flash.ui.Keyboard;
var speed:Number=2;
stage.addEventListener(KeyboardEvent.KEY_DOWN, stikman);
function stikman(e:KeyboardEvent)
{
if (e.keyCode==Keyboard.LEFT)
{
stik.x-=speed;
stik.scaleX=-1;
stik.stik2.play();
}
else if (e.keyCode==Keyboard.RIGHT)
{
stik.x+=speed;
stik.scaleX=1;
stik.stik2.play();
}
}
and then i try to change keyboard event to mouse event when moving character with button it should press click, click and click. i want to hold the click when moving the character and when mouse up the character stop. but i still don't know how. this my code when i try to change to mouse event
var speed:Number=2;
mundur.addEventListener(MouseEvent.MOUSE_DOWN, stikman);
function stikman(e:MouseEvent)
{
stik.x-=speed;
stik.scaleX=-1;
stik.stik2.play();
}
maju.addEventListener(MouseEvent.CLICK, stikman2);
function stikman2(e:MouseEvent)
{
stik.x+=speed;
stik.scaleX=1;
stik.stik2.play();
}
Because keyboard produces KeyboardEvent.KEY_DOWN event repeatedly as long as key is pressed, while MouseEvent.CLICK as well as MouseEvent.MOUSE_DOWN are dispatched only once per user action.
With mouse you need to change the logic.
// Subscribe both buttons.
ButtonRight.addEventListener(MouseEvent.MOUSE_DOWN, onButton);
ButtonLeft.addEventListener(MouseEvent.MOUSE_DOWN, onButton);
var currentSpeed:Number = 0;
var isPlaying:Boolean = false;
function onButton(e:MouseEvent):void
{
// Set up the directions and start the animation.
switch (e.currentTarget)
{
case ButtonLeft:
currentSpeed = -speed;
stik.stik2.play();
stik.scaleX = -1;
break;
case ButtonRight:
currentSpeed = speed;
stik.stik2.play();
stik.scaleX = 1;
break;
}
isPlaying = true;
// Call repeatedly to move character.
addEventListener(Event.ENTER_FRAME, onFrame);
// Hook the MOUSE_UP even even if it is outside the button or even stage.
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
}
function onFrame(e:Even):void
{
// Move character by the designated offset each frame.
stik.x += currentSpeed;
if (!isPlaying)
{
// Stop at last frame.
// if (stik.stik2.currentFrame == stik.stik2.totalFrames)
// Stop at frame 1.
if (stik.stik2.currentFrame == 1)
{
// Stop the animation.
stik.stik2.stop();
// Stop moving.
removeEventListener(Event.ENTER_FRAME, onFrame);
}
}
}
function onUp(e:MouseEvent):void
{
// Indicate to stop when the animation ends.
isPlaying = false;
// Unhook the MOUSE_UP event.
stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
}

Action script 3 walking animation

i need some help. im trying to make my character walk both direction(left and right) and an idle animation when standing still. i manage to make the character walk to the right and make the idle animation work. now if I copy the code from the right button to the left button, the walking animation gets stuck in the first frame on both direction. I tried to experiment with it but with no luck. im sorry if i sounded noob. i just started with studying programming.
here are the code that i used
RightBtn.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
function mouseDown(e:MouseEvent): void {
if(RightBtn){
isRight = true;
}
}
RightBtn.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
function mouseUp(e:MouseEvent): void {
if(RightBtn){
isRight = false;
}
}
stage.addEventListener(Event.ENTER_FRAME, loop);
function loop(Event){
if(isRight==true && mcPlayer.x < 750){
mcPlayer.x += 7;
mcPlayer.gotoAndStop (2);
mcPlayer.walkR.play ();
}
else{
mcPlayer.gotoAndStop (1)
mcPlayer.Idle.play ();
}
}
LeftBtn.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown2);
function mouseDown2(e:MouseEvent): void {
if(LeftBtn){
isLeft = true;
}
}
LeftBtn.addEventListener(MouseEvent.MOUSE_UP, mouseUp2);
function mouseUp2(e:MouseEvent): void {
if(LeftBtn){
isLeft = false;
}
}
stage.addEventListener(Event.ENTER_FRAME, loop2);
function loop2(Event){
if(isLeft==true && mcPlayer.x > 65){
mcPlayer.x -= 7;
mcPlayer.gotoAndStop (3);
mcPlayer.walkL.play ();
}
else{
mcPlayer.gotoAndStop (1)
mcPlayer.Idle.play ();
}
}
That's what you get from blatant copy&paste without learning the mechanics of how does it internally work. You set two listeners to stage, both altering mcPlayer regardless of whether it was already altered by the other one. So, you need to write both sets of code in one listener, and walk the code with your pen and paper to ensure that both isRight==true and isLeft==true branches work separately and don't interfere with each other. The proper condition statement should be like this:
if (isRight==true && mcPlayer.x < 750) {
// do a step right
} else if (isLeft==true && mcPlayer.x > 65){
// do a step left
} else {
// do idle animation
}
Your codes of initiating animation are correct themselves, they just get overridden by the listeners that are unaware of some other code altering mcPlayer.

Flash Game ArgumentError: Error #2025 removeChild

I'm trying to get the bat character to remove the jack/2/3 child(s) in my game here, but I keep getting the ArgumentError: Error #2025. I understand that I may be removing a child twice, perhaps? I'm looking around and I'm not really experienced in this stuff so I'm having a hard time understanding what needs to be done to fix this issue. Can someone tell me what needs to be done with my code specifically, please?
var jack:pumpkin = new pumpkin();
var jack2:pumpkin = new pumpkin();
var jack3:pumpkin = new pumpkin();
var score:Number = 0;
scoreBox.text = String(score);
addChild(jack);
jack.x = 125;
jack.y = 285;
addChild(jack2);
jack2.x = 270;
jack2.y = 310;
addChild(jack3);
jack3.x = 445;
jack3.y = 285;
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveLeft);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveRight);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveDown);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveUp);
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function moveLeft(e:KeyboardEvent):void {
if (e.keyCode == 37) {
bat.x -= 5;
}
}
function moveRight(e:KeyboardEvent):void {
if (e.keyCode == 39) {
bat.x += 5;
}
}
function moveDown(e:KeyboardEvent):void {
if (e.keyCode == 40) {
bat.y += 5;
}
}
function moveUp(e:KeyboardEvent):void {
if (e.keyCode == 38) {
bat.y -= 5;
}
}
function bump(e:KeyboardEvent):void {
stage.addEventListener(Event.ENTER_FRAME, bumpIt);
function bumpIt(e:Event):void {
if (bat.hitTestObject(jack)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack);
score++;
scoreBox.text = String(score);
}
if (bat.hitTestObject(jack2)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack2);
score++;
scoreBox.text = String(score);
}
if (bat.hitTestObject(jack3)) {
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
removeChild(jack3);
score++;
scoreBox.text = String(score);
}
}
}
Due to the nested bumpit() event handler, on every key up you're adding another enter frame event if your hit-test has no collision.
On KeyboardEvent.KEY_UP, event handler calls bump() which adds an Event.ENTER_FRAME listener that will call bumpIt().
If bat.hitTestObject() is true, you remove Event.ENTER_FRAME.
If not, you still have the Event.ENTER_FRAME listener firing bumpIt() every frame.
So, every key up you're potentially adding another frame handler.
If ten key up events occurred and none of them hit test your objects, you are now calling bumpIt ten times a frame.
If you need to hit test on key up, just put the logic there:
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function bump(e:KeyboardEvent):void {
if (bat.hitTestObject(jack)) { /* ... */ }
}
Or, if you're tracking an animation sequence after key up, maybe add some state variable, such as:
var isFlying:Boolean = false;
stage.addEventListener(KeyboardEvent.KEY_UP, bump);
function bump(e:KeyboardEvent):void {
// If bat is already flying, don't add another frame handler
if (isFlying)
return;
// Otherwise, indicate bat is now flying and add frame handler
isFlying = true;
stage.addEventListener(Event.ENTER_FRAME, bumpIt);
}
Then, if your hit-test works and you remove your frame handler, reset the state variable:
stage.removeEventListener(Event.ENTER_FRAME, bumpIt);
isFlying = false;
Another solution is to remove the nested handlers. Because you have nested bumpIt() inside bump(), you are seeing cumulative firing of callbacks due to scope:
function bump():void {
function bumpIt():void { /* ... */ }
}
Simply promote bumpIt():
function bump():void { /* ... */ }
function bumpIt():void { /* ... */ }

AS3 Key held down preventing mouse update

I'm developing a 3D game and I've noticed some odd behaviour when I hold down the movement keys; the game seems to temporarily ignore the mouse position and stops updating which way the player is facing. The game does not freeze - it's just as if it stops paying attention to the position of the mouse.
Here's the code I'm using to get key presses and releases:
public function keyPressed(e:KeyboardEvent):void {
switch (e.keyCode) {
case 32:
_keySpace = true;
break;
case 81:
if (!keyQ) {
keyQ=true;
}
break;
case 69:
if (!keyE) {
keyE=true;
}
break;
case 65:
if (!keyA) {
keyA=true;
}
break;
case 68:
if (!keyD) {
keyD=true;
}
break;
case 87:
if (!keyW) {
keyW=true;
}
break;
case 83:
if (!keyS) {
keyS=true;
}
break;
}
}
public function keyLift(e:KeyboardEvent):void {
if (e.keyCode==32) {
_keySpace = false;
} else if (e.keyCode==81) {
keyQ=false;
} else if (e.keyCode==69) {
keyE=false;
} else if (e.keyCode==65) {
keyA=false;
} else if (e.keyCode==68) {
keyD=false;
} else if (e.keyCode==87) {
keyW=false;
} else if (e.keyCode==83) {
keyS=false;
}
}
And the code to update the mouse position is just an ENTER_FRAME event:
addEventListener(Event.ENTER_FRAME, enterFrame);
...that triggers the main game loop. Here's the relevant part that uses the mouse position. The mouseX and mouseY properties are used in Player to rotate the view left/right and up/down.
private function enterFrame(e:Event=null):void {
_player.update(mouseX, mouseY);
}
All of that works fine - it's just this problem with holding down the strafing keys; it's as if, once the key starts repeating, the game is taking all its time resolving those events and neglects to update the rotation - even though it's not dependent on a MouseEvent.
Does anyone know how to make Flash ignore repeating keys when the key is held down? Or is there some other problem?
Cheers.
You could check when your key handler was last triggered, and if it's more recently than a certain threshold, ignore it. You could make it a tenth of a second:
private static const KEY_THRESHOLD:int = 100; // 100 ms = 1/10 second
private static var lastPressedAt:int;
public function keyPressed(e:KeyboardEvent):void {
var now:int = new Date().getTime();
if (lastPressedAt > 0 && now - lastPressedAt < KEY_THRESHOLD) {
return;
}
lastPressedAt = now;
// etc...

AS3 Stop character from moving through walls

I want to stop the movieclips movement when it hits a wall (another movieclip).
The example below works, but after the collision the movieclip 'blocks' all movement to the left...
My question to you is, is this a good way and why isn't it working well?
There will be something wrong in this code, but i'm learning.
For now the example with the leftArrow key;
variables to check the key, if it's hitting the walls and if it's moving or not:
var leftArrow:Boolean;
var speed:int = 10;
var hitting:Boolean;
var ismoving:Boolean;
event listeners for the keys/movement and detecting collision:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.ENTER_FRAME, walking);
stage.addEventListener(Event.ENTER_FRAME, detectHit);
detecting collision function:
function detectHit(e:Event) :void
{
if(char.hitTestObject(bounds))
{
hitting = true;
}
}
function to the left arrow key:
function keyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = true;
}
}
function keyReleased(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = false;
}
}
And the reason it's not working is probably here, but I don't understand why not:
function walking(event:Event):void {
if (rightArrow) {
char.x += speed;
}
if (leftArrow && ! hitting) {
char.x -= speed;
}
else
{
ismoving = false
}
if (leftArrow && ! hitting)
char will move if hitting is false. When char.hitTestObject(bounds) is true you are setting hitting to true. You are not setting hitting again to false anywhere. That's why once left wall is hit it stops left movement permanently. You need to figure out suitable condition to set hitting to false again.
Adding an else branch in detectHit should solve the problem.
function detectHit(e:Event):void {
if(char.hitTestObject(bounds))
{
hitting = true;
} else {
hitting = false; // add this
}
}
Allthough Taskinoor's method should work, I would suggest another way to do your hittests.
Since you probably are creating a game (character and bounds), you will have more than one bound. In that case, I would strongly suggest bitmap-hittesting. This way, you can create all your bounds in one movieclip and test for a hit.
I will explain this by using the example of a maze. The maze would then be some lines in a movieclip, randomly put together. If you use HitTestObject and you aren't hitting one of the lines, but your character is over the movieclip, hitTestObject will return true, even though you are not hitting a wall. By using bitmapHitTesting, you can overcome this problem (BitmapHitTest takes transparant pixels into account, whereas hitTestObject does not).
Below you can find an example of how to do bitmapHitTesting. Creating the bitmaps in this function is not necesarry if they do not change shape. In that case, I would suggest placing the code for the bitmapdata in a added_to_stage-method.
private var _previousX:int;
private var _previousY:int;
private var _bmpd:BitmapData ;
private var _physicalBitmapData:BitmapData;
private function walkAround(e:Event):void
{
var _xTo:int = //Calculate x-to-position;
var _yTo:int = //Calculate y-to-position;
//If your character doesn't change shape, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_bmpd = new BitmapData(char.width, char.height, true, 0);
_bmpd.draw(char);
//If your bounds are static, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_physicalBitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
_bmpd.draw(bounds);
//The below line is the actual hittest
if(_physicalBitmapData.hitTest(new Point(0, 0), 255, _bmpd, new Point(char.x, char.y), 255))
{
char.x = _previousX;
char.y = _previousY;
}
else
{
char.x = _xTo;
char.y = _yTo;
}
_previousX = char.x;
_previousY = char.y;
}
Look at my hint,
function loop(Event)
{
if(isHit==false)
{
if(isRight==true){head_mc.x+=1}
if(isLeft==true){head_mc.x-=1}
if(isUp==true){head_mc.y-=1}
if(isDown==true){head_mc.y+=1}
}
if(head_mc.hitTestObject(build_mc))
{
isHit=true;
if(isRight==true){head_mc.x-=1}
if(isLeft==true){head_mc.x+=1}
if(isUp==true){head_mc.y+=1}
if(isDown==true){head_mc.y-=1}
}
else
{
isHit=false;
}
}
I use step back to opposite direction instead.