Sequentially-specific combination of keys held for function? - actionscript-3

I'm trying to give my character in a platformer game a movement mechanic in which holding the left key then also the right will cause the character to still move left but at a slower pace (i.e. movementSpeed/2) as if moon-walking (and visa versa):
public var leftKey:Boolean = false;
public var rightKey:Boolean = false;
public var upKey:Boolean = false;
public var leftFlag:Boolean = false;
function ifKeyDown(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT && rightKey == false)
{
leftKey = true;
if (event.keyCode == Keyboard.LEFT && event.keyCode == Keyboard.RIGHT)
{
leftFlag = true;
trace("leftFlag true");
}
}
if (event.keyCode == Keyboard.RIGHT && leftKey == false)
{
rightKey = true;
}
}
function ifKeyUp(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftKey = false;
leftFlag = false;
}
if (event.keyCode == Keyboard.RIGHT)
{
rightKey = false;
}
}
public function ifEnterFrame(event:Event):void
{
if (leftKey == true && leftFlag == false)
{
player1_mc.x -= mainSpeed;
trace("L");
}
if (rightKey == true && leftFlag == false)
{
player1_mc.x += mainSpeed;
trace("R");
}
if (leftKey == true && rightKey == true)
{
if (leftFlag == true)
{
player1_mc.x -= mainSpeed/2;
trace("L + R");
}
else
{
player1_mc.x += mainSpeed/2;
trace("R + L");
}
}
My output would look like this:
I hold left key
L
L
L
L
I let go of left key. Then,
I hold right key
R
R
R
R
I let go of right key. Then,
I hold right then also hold left
L
R
R+L
L
R
R+L
I let go of both. Then,
I hold left then also right
L
R
R+L
L
R
R+L
Though I know by my traces that the leftFlag is not being run, I've spent hours trying to figure out why to no avail. :(

I think your problem is this expression:
event.keyCode == Keyboard.LEFT && event.keyCode == Keyboard.RIGHT
Though I am not familiar with actionscript, if it is anything like Java, the keyboard events are called once for each key press. "event" corresponds to only one key, not two different keys, and thus your expression will always return false.
The solution to your problem will probably involve something like this in both the key pressed and released functions.
if (event.keyCode == Keyboard.LEFT)
{
if (leftFlag)
{
//code here
}
if (rightFlag)
{
//code here
}
}
if (event.keyCode == Keyboard.RIGHT)
{
if (leftFlag)
{
//code here
}
if (rightFlag)
{
//code here
}
}
Hope that helps!

Related

AS3 Restrict ship in visible stage area

Hey so i've been making a space shooter game and i created the movement but i'm trying to restricting the ship to the visible stage area and i can't figure out how to do that
also i'm sorry if my code it's really messy i'm really new at this
the stage size it's 1920 x 1080
here's the code of the movement
var leftKeyPressed: Boolean = false;
var rightKeyPressed: Boolean = false;
var upKeyPressed: Boolean = false;
var downKeyPressed: Boolean = false;
var xMoveSpeed: Number = 15;
var yMoveSpeed: Number = 15;
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
function keyDownHandler(e: KeyboardEvent): void
{
if (e.keyCode == Keyboard.LEFT)
{
leftKeyPressed = true;
}
if (e.keyCode == Keyboard.RIGHT)
{
rightKeyPressed = true;
}
if (e.keyCode == Keyboard.UP)
{
upKeyPressed = true;
}
if (e.keyCode == Keyboard.DOWN)
{
downKeyPressed = true;
}
}
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
function keyUpHandler(e: KeyboardEvent): void
{
if (e.keyCode == Keyboard.LEFT)
{
leftKeyPressed = false;
}
if (e.keyCode == Keyboard.RIGHT)
{
rightKeyPressed = false;
}
if (e.keyCode == Keyboard.UP)
{
upKeyPressed = false;
}
if (e.keyCode == Keyboard.DOWN)
{
downKeyPressed = false;
}
}
stage.addEventListener(Event.ENTER_FRAME, moveHero);
function moveHero(e: Event): void
{
if (leftKeyPressed)
{
ship.x -= xMoveSpeed;
}
if (rightKeyPressed)
{
ship.x += xMoveSpeed;
}
if (upKeyPressed)
{
ship.y -= yMoveSpeed;
}
if (downKeyPressed)
{
ship.y += yMoveSpeed;
}
}
Well, you can start with this.
// One map is much better than a separate variable for each and every key.
var keyMap:Object = new Object;
// Initial keymap values.
keyMap[Keyboard.UP] = 0;
keyMap[Keyboard.DOWN] = 0;
keyMap[Keyboard.LEFT] = 0;
keyMap[Keyboard.RIGHT] = 0;
// With the keymap you don't need these big event handlers,
// you need a single one with one line of code.
stage.addEventListener(KeyboardEvent.KEY_DOWN, onUpDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onUpDown);
function onUpDown(e:KeyboardEvent):void
{
// The members of the object with the names of key codes
// will be set to 1 in case of KEY_DOWN event or 0 in case of KEY_UP.
keyMap[e.keyCode] = int(e.type == KeyboardEvent.KEY_DOWN);
}
stage.addEventListener(Event.ENTER_FRAME, moveHero);
// This will provide you with min and max values for both X and Y coordinates.
// You will probably need to adjust it because the ship have width and height.
var conStraints:Rectangle = new Rectangle(0, 0, 1920, 1080);
var xMoveSpeed:Number = 15;
var yMoveSpeed:Number = 15;
function moveHero(e:Event):void
{
var anX:Number = ship.x;
var anY:Number = ship.y;
// Use keymap to figure the new coordinates.
// Take into account all the relevant keys pressed.
anX += xMoveSpeed * (keyMap[Keyboard.RIGHT] - keyMap[Keyboard.LEFT]);
anY += yMoveSpeed * (keyMap[Keyboard.DOWN] - keyMap[Keyboard.UP]);
// Now set the new ship coordinates with the regard to constraints.
ship.x = Math.min(conStraints.right, Math.max(conStraints.left, anX));
ship.y = Math.min(conStraints.bottom, Math.max(conStraints.top, anY));
}
I think this is the easiet solution, tell me if it worked or not
function keyDownHandler(e: KeyboardEvent): void
{
if (e.keyCode == Keyboard.LEFT && ship.x > 15)
{
leftKeyPressed = true;
}
if (e.keyCode == Keyboard.RIGHT && ship.x < 1905)
{
rightKeyPressed = true;
}
if (e.keyCode == Keyboard.UP && ship.y > 15)
{
upKeyPressed = true;
}
if (e.keyCode == Keyboard.DOWN && ship.y < 1065)
{
downKeyPressed = true;
}
}

Single Action with Button Click

I am currently building a small version of a fighting game in flash, but I don't want the character to continuously hit etc. by just holding down a key, but rather to have the key be pressed everytime. This is what I currently have:
function moveChar(event:Event):void{
if(rightKeyDown && !hitting && !combo){
hitting = true;
gotoAndPlay("basic_punch");
kickbag.gotoAndPlay("hit1");
countHits++;
}
if(downKeyDown && !hitting && !combo){
hitting = true;
gotoAndPlay("basic_kick");
kickbag.gotoAndPlay("hit1");
countHits++;
}
if(downKeyDown && combo){
gotoAndPlay("kick_combo1");
kickbag.gotoAndPlay("hit2");
kickbag.stop();
}
if(rightKeyDown && combo){
gotoAndPlay("punch_combo");
kickbag.gotoAndPlay("hit2");
kickbag.stop();
}
}
function checkKeysDown(event:KeyboardEvent):void{
if(countHits == 2) bar.gotoAndStop("bar2");
if(countHits == 6) bar.gotoAndStop("bar3");
if(countHits == 10) {
bar.gotoAndStop("bar4");
combo = true;
gotoAndPlay("combo_stand");
}
if(event.keyCode == 39 || event.keyCode == 68){
rightKeyDown = true;
}
else if(event.keyCode == 40 || event.keyCode == 83){
downKeyDown = true;
}
}
function checkKeysUp(event:KeyboardEvent):void{
if(event.keyCode == 39 || event.keyCode == 68){
rightKeyDown = false;
}
else if(event.keyCode == 40 || event.keyCode == 83){
downKeyDown = false;
}
}
But as I explained this allows for the buttons to be held down.
Create onKeyDown and onKeyUp listeners. In the onKeyDown listener kill the onKeyDown listener, perform action, and init the onKeyUpListener. In the onKeyUp listener, kill the onKeyUp listener and re-init the onKeyDown listener.
I think #Ribs is on the right track, but given your current code the answer seems simple.
Remove the Event.ENTER_FRAME from moveChar() and change the function definition line so it looks like this:
function moveChar():void //e:Event removed from parameters
Then in your checkKeysDown function, call the moveChar() for the key pressed (your moveChar() evaluates the booleans anyway):
if(event.keyCode == 39 || event.keyCode == 68){
rightKeyDown = true;
moveChar();
}
else if(event.keyCode == 40 || event.keyCode == 83){
downKeyDown = true;
moveChar();
}
Now you can alter the if statements above to make it a bit more concrete:
if ( !downKeyDown && !rightKeyDown ) {
if(event.keyCode == 39 || event.keyCode == 68){
rightKeyDown = true;
moveChar();
}
else if(!downKeyDown && !rightKeyDown && (event.keyCode == 40 || event.keyCode == 83)){
downKeyDown = true;
moveChar();
}
}
This is basically just handling the down or right key pressed one at a time, and ignoring everything else while those are running. It could also be assume that you might not want to do anything while down or right keys are pressed, therefore you can just do this:
function checkKeysDown(event:KeyboardEvent):void{
if ( downKeyDown || rightKeyDown ) return; //do nothing, we are pressing a key
if(countHits == 2) bar.gotoAndStop("bar2");
if(countHits == 6) bar.gotoAndStop("bar3");*/
if(countHits == 10) {
bar.gotoAndStop("bar4");
combo = true;
gotoAndPlay("combo_stand");
}
if(event.keyCode == 39 || event.keyCode == 68){
rightKeyDown = true;
moveChar();
}
else if(event.keyCode == 40 || event.keyCode == 83){
downKeyDown = true;
moveChar();
}
}
This will return in the checkKeyDown function if we are currently pressing the down or right key. I'm assuming this is probably the desired effect you are going for so your counters do not increment each KEY_DOWN registration. As you can see you have some options and there are multiple ways of doing this. Hope this provides some guidance.
I too have been working on a platformer flash game, and here's how I accomplished a clean attack code: Declare an "attack" Boolean to help decide whether or not the character can or cannot attack. You can prevent the character from continuously attacking by creating an enter frame event listener that checks what frame the character is in during his attack. If the character play-head is at the last frame of the animation than simply set the attack Boolean to false.

A conflict exists with definition leftIdle1 in namespace internal

I'm scripting a game with Actionscript 3.0 in Flash Professional CS5.5, but I get an error.
Scene 1, Layer 'as2', Frame 153, Line 4 1151: A conflict exists with definition leftIdle1 in namespace internal.
(I get these with the other Variables too.)
Now it's a platform game, and I am going to put cutscenes throughout in the game and I need to switch from frames and put the code in another frame. But it gives that error, I turned off the 'Automatic Declare stage instances' function, now I checked this website and Googled it, people get it with their Movieclips, I get it with my variables.
This is my script:
var leftKeyDown1:Boolean = false;
var rightKeyDown1:Boolean = false;
var spaceKeyDown1:Boolean = false;
var leftIdle1:Boolean = false;
var rightIdle1:Boolean = true;
var mainSpeed1:Number = 4;
player.addEventListener(Event.ENTER_FRAME, moveChar);
function moveChar(event:Event)
{
if (leftKeyDown1)
{
player.x -= mainSpeed1;
leftIdle1 = true;
rightIdle1 = false;
player.gotoAndStop("walk_left");
}
if (rightKeyDown1)
{
player.x += mainSpeed1;
rightIdle1 = true;
leftIdle1 = false;
player.gotoAndStop("walk_right");
}
if (rightIdle1 && !rightKeyDown1 && !leftKeyDown1)
{
player.gotoAndStop("idle_right");
}
else if (leftIdle1 && !rightKeyDown1 && !leftKeyDown1)
{
player.gotoAndStop("idle_left");
}
if (collide.hitTestObject(player))
{
player.x = player.x + mainSpeed1;
}
if (trigger1.hitTestObject(player))
{
son1.gotoAndStop("walkRight");
trigger1.gotoAndStop(2);
son1.x += 2;
}
if (trigger2.hitTestObject(player))
{
gotoAndPlay(4);
}
}
stage.addEventListener(KeyboardEvent.KEY_DOWN, checkKeysDown);
function checkKeysDown(event:KeyboardEvent)
{
if (event.keyCode == 37 || event.keyCode == 65)
{
leftKeyDown1 = true;
}
if (event.keyCode == 39 || event.keyCode == 68)
{
rightKeyDown1 = true;
}
if (event.keyCode == 32)
{
spaceKeyDown1 = true;
}
}
stage.addEventListener(KeyboardEvent.KEY_UP, checkKeysU1);
function checkKeysUp(event:KeyboardEvent)
{
if (event.keyCode == 37 || event.keyCode == 65)
{
leftKeyDown1 = false;
}
if (event.keyCode == 32)
{
spaceKeyDown1 = false;
}
if (event.keyCode == 39 || event.keyCode == 68)
{
rightKeyDown1 = false;
}
}
It's probably coded in a weird way, but whatever.
I have no idea what to do at this point.
Help would be really appreciated.
EDIT:
Oh I got another error too. It's with Duplicate function, and I can't seem to fix it but to rename those, and it will take a long time to rename them every-time. So if someone has something for that, thanks!
you have duplicated definitions.
For example:
var leftIdle1:Boolean
exists multiple times - remove the duplicates

fluidly dealing with multiple keypresses in ActionScript3

I'm currently building an engine for a platformer game at the moment, but I've noticed that ActionScript3 is having difficulty in keeping fluid when multiple keypresses are in use. For example;
function onKeyDown(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.UP || event.keyCode == Keyboard.W || event.keyCode == Keyboard.SPACE) {
if (isTouchingGround()) {
isJumping = true;
yv = -100;
}
} else if (event.keyCode == Keyboard.DOWN || event.keyCode == Keyboard.D) {
if (xv == 0) {
player.gotoAndPlay(275);
}
} else if (event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.A) {
if (xv == 0) {
xv = -24;
} else if (xv != -120) {
xv-=2;
}
} else if (event.keyCode == Keyboard.RIGHT || event.keyCode == Keyboard.D) {
if (xv == 0) {
xv = 24;
} else if (xv != 120) {
xv+=2;
}
}
}
So, as listed above, using the UP (or W, or Space) key triggers the player to jump (seperate onframe event handler handles gravity etc). Using the RIGHT (or D..) key triggers increases the player acceleration, which is again applied to the player in a seperate onframe event handler.
Everything works fine by itself - but the problem arises when multiple keystrokes are used. If a player starts to move to the right, and hits jump, he will cease accelerating. At the same time, he will not decelerate, as instructed in the Keyboard.UP method. Instead, he will maintain constant at his current rate, until the RIGHT key is hit again.
In short, it is as though Actionscript begins ignoring both the keyboard.down and keyboard.up methods for the RIGHT or LEFT movement keys, until they are no longer being pressed. This obviously causes for some very rigid gameplay - is there any solution anyone would be willing to share with me on this?
Your problem lies in the fact that your if conditionals are followed by if else conditionals. Drop the else and just have the if conditionals. Basically if the user holds down space then none of the other if conditionals are going to be tested since space is being held down and it's the first if statement. So just drop the else off of the if's. Just remove the if else conditionals that are testing keystrokes, not the conditionals inside of the if statements that deal with keystrokes.
Here is what your code should look like:
function onKeyDown(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.UP || event.keyCode == Keyboard.W || event.keyCode == Keyboard.SPACE) {
if (isTouchingGround()) {
isJumping = true;
yv = -100;
}
}
if (event.keyCode == Keyboard.DOWN || event.keyCode == Keyboard.D) {
if (xv == 0) {
player.gotoAndPlay(275);
}
}
if (event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.A) {
if (xv == 0) {
xv = -24;
} else if (xv != -120) {
xv-=2;
}
}
if (event.keyCode == Keyboard.RIGHT || event.keyCode == Keyboard.D) {
if (xv == 0) {
xv = 24;
} else if (xv != 120) {
xv+=2;
}
}
}
Something else you may notice is that when the UP key and RIGHT key are both being held down, the computer seems to freeze keyboard input, however when the W key and D key are being held down you can still press other keys and the computer will register their input. The answer to that question is here.
Update:
For the fluid part, instead of triggering something when a keystroke takes place, it is better to have a boolean variable such as keyUP or UP that holds a true if the key is down or false when the key is up. Then have a function onEnterFrame(event:Event):void {} that performs an action when keyUP is true. Like so:
import flash.events.*;
public class keyEvents extends MovieClip {
private var keyRIGHT:Boolean = false;
public function keyEvents():void
{
this.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
this.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
function onKeyDown(event:KeyboardEvent):void
{
if(event.keyCode == Keyboard.RIGHT) {
this.keyRIGHT = true;
}
}
function onKeyUp(event:KeyboardEvent):void
{
if(event.keyCode == Keyboard.RIGHT) {
this.keyRIGHT = false;
}
}
function onEnterFrame(event:Event):void
{
if(this.keyRIGHT) {
// This code is executed while the RIGHT arrow key is down.
}
}
}
If the above code does not work I think that your problem lies with your keyboard, not that it's broken or anything but the way it was made might be messing things up.
Let me know if this didn't help and I'll continue trying.

Adding a single instance of an object to the stage

Good Evening,
I can't seem to get my code to only add one instance of an object to the stage. It seems to add atleast 3 instances of the object to the stage. The objects added is r2, r3 and r4.
stop();
import flash.events.Event;
stage.focus=stage;
var upKeyDown5:Boolean = false;
var rightKeyDown5:Boolean = false;
var downKeyDown5:Boolean = false;
var leftKeyDown5:Boolean = false;
var enterkey:Boolean = false;
var interaction:Boolean = false;
p5.addEventListener(Event.ENTER_FRAME, moveChar5);
stage.addEventListener(KeyboardEvent.KEY_DOWN, checkKeysDown5);
stage.addEventListener(KeyboardEvent.KEY_UP, checkKeysUp5);
Mouse.hide();
function moveChar5(e:Event):void{
if(downKeyDown5 && !upKeyDown5 && !rightKeyDown5 && !leftKeyDown5)
{
p5.gotoAndStop("walk_down");
if(p5.y < 492.75)
p5.y += 6;
}
if(upKeyDown5 && !downKeyDown5 && !rightKeyDown5 && !leftKeyDown5)
{
p5.gotoAndStop("walk_up");
if(p5.y > 202.85)
p5.y -= 6;
}
if(rightKeyDown5 && !upKeyDown5 && !downKeyDown5 && !leftKeyDown5)
{
p5.gotoAndStop("walk_right");
if(p5.x < 871.5)
p5.x += 6;
}
if(leftKeyDown5 && !upKeyDown5 && !rightKeyDown5 && !downKeyDown5)
{
p5.gotoAndStop("walk_left");
if(p5.x > 203.65)
p5.x -= 6;
}
if(enterkey && interaction && p5.hitTestObject(c1)){
if (!(Boolean(stage.getChildByName('r2')))) {
var rat2:r2;
rat2 = new r2();
addChild(rat2);
rat2.y=38;
rat2.x=32;
}
}
if(enterkey && interaction && p5.hitTestObject(c2)){
if (!(Boolean(stage.getChildByName('r3')))) {
var rat3:r3;
rat3 = new r3();
addChild(rat3);
rat3.y=38;
rat3.x=32;
}
}
if(enterkey && interaction && p5.hitTestObject(c3)){
if (!(Boolean(stage.getChildByName('r4')))) {
var rat4:r4;
rat4 = new r4();
addChild(rat4);
rat4.y=38;
rat4.x=32;
}
}
}
function checkKeysDown5(event:KeyboardEvent):void{
if(event.keyCode == 87){
upKeyDown5 = true;
}
if(event.keyCode == 68){
rightKeyDown5 = true;
}
if(event.keyCode == 83){
downKeyDown5 = true;
}
if(event.keyCode == 65){
leftKeyDown5 = true;
}
if (event.keyCode == 13){
enterkey = true;
}
}
function checkKeysUp5(event:KeyboardEvent):void{
if(event.keyCode == 87){
upKeyDown5 = false;
p5.gotoAndStop("still_up");
}
if(event.keyCode == 68){
rightKeyDown5 = false;
p5.gotoAndStop("still_right");
}
if(event.keyCode == 65){
leftKeyDown5 = false;
p5.gotoAndStop("still_left");
}
if(event.keyCode == 83){
downKeyDown5 = false;
p5.gotoAndStop("still_down");
}
if (event.keyCode == 13){
enterkey = false;
}
if(p5.hitTestObject(c1) || p5.hitTestObject(c2) || p5.hitTestObject(c3)){
p5.gotoAndStop("interaction");
interaction = true;
}
else
interaction = false;
}
Thanks in advance
It would be more efficient and cleaner to use a switch statement instead all those if statements (if you only ever want one and only one of those conditions to be met)
You're issue I think has to do with the way you're tracking your rats - eg. using the stage.getChildByName.
Below is an example, plus some commented notes on some of your other potential issues.
switch(true){
case (enterkey && interaction && p5.hitTestObject(c1)):
if (!(Boolean(stage.getChildByName('r2')))) { //your not giving your rat a name so this will always return false, plus you're not adding the rat to the stage but to this class
var rat2:r2;
rat2 = new r2();
addChild(rat2); //use stage.addChild if you want the above check (stage.getChildByName) to work
rat2.y=38;
rat2.x=32;
rat2.name = "r2"; //if you want the above check to work
break; //break out of the switch if you don't want any of the others evaluate since this rat got added
}
//do a case for your other blocks
}
It would be better to not use stage.getChidByName at all, and instead create a method like this:
function checkRatExists(ratClass:Class):Boolean {
var tmp:DisplayObject;
var i:int = numChildren;
while(i--){
tmp = getChildAt(i);
if(tmp is ratClass){
return true;
}
}
return false;
}
Then use that new function instead of stage.getChildByName:
if (!checkRatExists(r2)) //r2 is the class of rat you want to check
As an aside from your issue, it would be much cleaner to create a method/function to do your rat positioning and adding instead of duplicated the code over and over and over...
function addRat(rat:RatCommonBaseClass, ratName:String):void {
addChild(rat);
rat.y=38;
rat.x=32;
rat.name = ratName;
}
//now you can just do this for all your rats:
addRat(new r2(),"r2);
You don't have an else condition for the your statements where you add the objects, so most likely what is happening is that all the statements are satisfying the condition at once. Adding an else statement should prevent this from happening:
if(enterkey && interaction && p5.hitTestObject(c1)){
if (!(Boolean(stage.getChildByName('r2')))) {
var rat2:r2;
rat2 = new r2();
addChild(rat2);
rat2.y=38;
rat2.x=32;
}
}
else if(enterkey && interaction && p5.hitTestObject(c2)){
if (!(Boolean(stage.getChildByName('r3')))) {
var rat3:r3;
rat3 = new r3();
addChild(rat3);
rat3.y=38;
rat3.x=32;
}
}
else if(enterkey && interaction && p5.hitTestObject(c3)){
if (!(Boolean(stage.getChildByName('r4')))) {
var rat4:r4;
rat4 = new r4();
addChild(rat4);
rat4.y=38;
rat4.x=32;
}
}
This way it will first check to see if p5 has hit c1 and only if it hasn't will it check if it has hit c2 and then the same thing for c3.