PDA

View Full Version : Stop keyboard action repeating when key is held down?



dst
April 10th, 2009, 11:52 AM
Hi, I'm developing a game for my final year project at university that has a character who can move up and down on screen. The upper half of the screen is reflected in the lower half so that there are actually two characters on screen at once, each reacting exactly the same way to keyboard input.

One of the mechanics involves the two avatars changing positions relative to their halves of the screen which requires a spacebar press to execute. The problem I'm having is that I don't want the characters to change positions once every frame if the spacebar is held down. I need to implement some sort of delay once the spacebar is pressed so that the characters won't swap positions for another second or so.

Here is my project blog with the embeded swf files. At the moment they are just whitebox tests as I want to get the engine sorted before I drop in any of the art assets.

http://dsthompson.blogspot.com/

If anyone can help me out with this I'd really appreciate it. Here's the code for the flip mechanic as it exists at the moment:



var plachaFlipPointY:Number = char.mc.y;
var shadowPlachaFlipPointY:Number = schar.mc.y;

if (placha.flip) {
placha.flip = false;
if (char.mc.y <= midPoint-3) {
char.mc.y = shadowPlachaFlipPointY;
schar.mc.y = plachaFlipPointY;
char.mc.scaleY = -1;
schar.mc.scaleY = -1;
}
else if (char.mc.y >= midPoint+3) {
char.mc.y = shadowPlachaFlipPointY;
schar.mc.y = plachaFlipPointY;
char.mc.scaleY = 1;
schar.mc.scaleY = 1;
}
}


(Please note, I have very little experience with actionscript and most of my code has been adapted from Gary Rosenzweig's Game Programming University book.)

JonnyR
April 10th, 2009, 11:58 AM
Hi DST,

I find it interesting that you've posted the code for the "flip mechanic" when it's the Input Code which is causing the problem (ie: when the user holds down space, it keeps flipping). Personally, I would consider removing the "Space Key" event listener when the event handler picks it up. You could then start a Timer instance, which, when elapsed, will re-instate the listener.

However, there's more than one way to skin a rabbit; I'm sure you could implement the solution into the "flip mechanic" but I'm pretty sure the solution will end up using a timer, or some kind of asynchronus action (ie: when a Tween completes).

Good Luck with your project.
Jonny.

Shaedo
April 10th, 2009, 12:13 PM
two ways that I know to achieve this
This first and easiest way is using a limiting counter as below



addEventListener(Event.ENTER_FRAME, counter);
stage.addEventListener(KeyboardEvent.KEY_DOWN,doSt uff);
var myCounter:uint = 0;
var limit:uint = 30; // I am the minimum frames that are required before doStuff will run
function counter(e:Event):void
{
myCounter += 1; // I increase by 1 every frame.
}
function doStuff(event:KeyboardEvent)
{
if(event.keyCode == Keyboard.SPACE && myCounter > limit)
{
myCounter = 0; // resets counter
trace('yey');
//I will execute only when space is pressed AND after 30 frames ie limit.
}
}



The other way is more complicated and I will post it next

Shaedo
April 10th, 2009, 12:15 PM
I just read JonnyRs entry.

" Personally, I would consider removing the "Space Key" event listener when the event handler picks it up. "

Its probably a better solution to mine if you only need to flip once as it removes excess pressure on system resources.

Shaedo
April 10th, 2009, 12:30 PM
Ok this is my second solution and the one I use for these situations.
It means that the key has to be released before the action can be triggered again.
I am fairly sure that there is a much more elegant way to achieve this and hopefully someone might post it but otherwise here it is:



addEventListener(Event.ENTER_FRAME, pressKeyOnce);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyP ressHandler);
stage.addEventListener(KeyboardEvent.KEY_UP,keyRel easeHandler);
var space:Boolean = false;
var checkOn:Boolean = true;
var checkOff:Boolean = false;

function pressKeyOnce(e:Event):void
{
if(space && checkOn && checkOff == false)
{
checkOn = false;
checkOff = true;
trace ('ONLY trigger ONCE pre press!!!');
}
if(space == false && checkOn == false)
{
checkOn = true;
}
if(space && checkOn && checkOff)
{
checkOn = false;
checkOff = false;
}
}

function keyPressHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.SPACE)
{
space = true;
}
}

function keyReleaseHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.SPACE)
{
space = false;
}
}



If you want to test these then create a new .fla , F9 the first frame copy it and and CTRL + ENT it to test.

then try adding comments // to see what happens.

Sorry if this last was teaching you to such eggs.

dst
April 10th, 2009, 12:41 PM
Wow, thanks for the swift replies guys. JonnyR - the reason I posted the flip mechanic code was because of exactly the reason you mentioned; I was trying to solve the problem by implementing a solution inside that code rather than elsewhere. I hadn't even thought about removing the event listener to be honest (I told you I was new to this!)

I have been trying to use getTimer to work out the solution but it would just reset everytime the code ran, obviously every frame. I then tried making an array that would log the amount of frames since the spacebar was pressed, but I didn't know (and couldn't find) a "get frame number" function, if one even exists.

I can see myself trying to work out the solution using far more complicated methods than I need to. I put that down to lack of experience though.

Shaedo - thanks for the code you posted, I'll be trying to implement it into my code once I fully get my head around it :)

dst
April 10th, 2009, 12:53 PM
Just saw your latest post Shaedo, thanks very much. I hadn't even thought about just cancelling out the flip after the first flip if the key was held down. That makes for a much simpler solution that doesn't require any timers etc. And no, your last post wasn't teaching me to suck eggs, I'm very grateful as your solution hadn't even occured to me. Thanks.

Shaedo
April 10th, 2009, 01:05 PM
Timers can slow down code and make things come unstuck. That said alot of game programers (as far as I can tell) love them and certainly ones that are masters of their craft (of which I am not at all) use them often. A faster method (or so it is said somewhere on these forums) is to use the frame counter.

One last point of warning: when useing a frame counter remember that uint ranges from 0 to a very high number (2^32 I think) and when it exceeds that it ticks over to 0 again. Int and Num dont tick over to 0 they tick over to a very negative number (about -2^16 I think) so this can REALLY stuff your game because it will take a long time before the counter>limit again.

JonnyR
April 10th, 2009, 01:23 PM
@Shaedo - The use of the Timer Class should not slow down your code as long as you don't let the instances stack up.

@dst - You mention that you're trying to use the getTimer() method, this has been depricated in AS3, you should instead be looking to use the Timer Class (http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Timer.html). You also mention that it keeps getting re-set on every frame - you will need to move the timer outside of your game loop. Once the timer completes (ie: after 1000ms), you can re-bind the "Space Key" event handler to cause your game state to "flip".

Regards
Jonny.