Making a key pressed only register once rather than continually - javascript

I am developing a game where you must press the left and right arrow keys alternatively to make the character move, the faster you do it, the quicker he runs. I have however ran into a problem whereby the key is being "held down" in a sense so no matter how quick you press the key it still manages to execute it multiple times.
So I am looking for a way to make the key only be pressed once per press rather than updating if you hold down the key.
here is the code for my key capturing and what it executes at the moment (Which is just an update of points and an update of the image used for the character.
KEY_CODES = {
37: 'left',
39: 'right',
40: 'down',
}
KEY_STATUS = {};
for (code in KEY_CODES) {
KEY_STATUS[KEY_CODES[code]] = false;
}
document.onkeydown = function (e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = true;
}
}
document.onkeyup = function (e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = false;
}
}
function move() {
movecounter++;
// Determine if the action is move action
if (KEY_STATUS.left || KEY_STATUS.right ||
KEY_STATUS.down || KEY_STATUS.up) {
// Redraw the canavs background images ready for the new ones to be placed ontop.
paintCanvas();
// to have diagonal movement.
if (KEY_STATUS.left) {
ctx.drawImage(imageStore.snowWalk, playerPosW, playerPosH);
snowStand = true;
score += 10;
} else if (KEY_STATUS.right) {
ctx.drawImage(imageStore.snowWalk, playerPosW, playerPosH);
score += 10;
} else if (KEY_STATUS.down) {
ctx.drawImage(imageStore.snowCrouch, playerPosW, playerPosH);
snowStand = false;
}
}
};
Hope you understand the problem I am facing, I have tried to explain it as best as I can here.
Thanks!

A simple solution would be to have a variable outside of the scope of the event listener that tells you if you're pressing the key for the first time:
var pressed = false;
Then, in the listener, toggle the state of that variable when the key is pressed:
.keydown(function() {
if (pressed) return;
pressed = true;
}
.keyup(function() {
pressed = false;
}

Related

How to make a key fire only once when pressed?

I'm making a simple JavaScript game (Space Invaders style) (Top-down space shooter) and I'm trying to make my character shoot a bullet per each 'space' key press. How can I do that?
I have tried multiple approaches, setting a flag, using onkeypress instead of keydown, Google searches (have also encountered this similar question yet it didn't help: Javascript onkeydown event fire only once?)
Below is an example of one solution I have tried.
document.onkeydown = function(e)
{
if(e.keyCode == 32 && space == false)
{
space = true;
}
}
document.onkeyup = function(e)
{
if(e.keyCode == 32) space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp)
{ if(space === true)
{
p.shoot();
}
window.requestAnimationFrame(gameLoop);
}
Expected results: Key being fired only once.
Actual results: Key is being fired multiple times.
There's really 3 states to a bullet - and, taking into consideration that in classic Space Invaders the player can only have one bullet in flight at a time, this makes things relatively simple
The bullet can be
NONE - doesn't exist
FIRED - i.e. need to create one
EXISTS - it's in flight
The code to handle it is relatively simple too
var BulletState = {
NONE: 0,
FIRED: 1,
EXISTS: 2
};
var bullet = BulletState.NONE;
document.onkeydown = function(e) {
if (e.keyCode == 32 && bullet === BulletState.NONE) {
bullet = BulletState.FIRED;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (bullet === BulletState.FIRED) {
bullet = BulletState.EXISTS;
p.shoot(); // p.shoot needs to set bullet = BulletState.NONE when the bullet expires
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
// not required at all
}
edit: To fire a bullet every press of spacebar (allowing multiple bullets)
var space = false;
var fireBullet = 0;
document.onkeydown = function(e) {
if (e.keyCode == 32 && !e.repeat && !space) {
fireBullet++;
space = true;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
while (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
space = false;
}
I use fireBullet++ and fireBullet-- because I guess it's plausible that someone could press and release and press the spacebar within 16ms (single frame) :p
You could also do
function gameLoop(timeStamp) {
if (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
that way you still handle multiple bullets OK, but only fire off one per frame - really depends on how you want to handle someone with a very fast trigger finger :p
As #JaromandaX suggested, space = false; after p.shoot(); will give you the desired result:
Reproducing the issue:
var space = false;
var element = document.querySelector('input');
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32)
space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space == true) {
console.log('shoot');
}
window.requestAnimationFrame(gameLoop);
}
<input />
EDIT: Added another isShot variable to keep track of shot fired and space key is down in requestAnimationFrame event:
var space = false;
var element = document.querySelector('input');
var isShot = false;
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32) {
space = isShot = false;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space && !isShot) {
console.log('shoot');
isShot = true;
}
window.requestAnimationFrame(gameLoop);
}
<input />
Here you have two event, on each key press three are three even that get's fired
1. keydown (when user press the key but not yet release the key)
2. keypress (its fired after the keydown event)
3. keyup (When user release the key)
If you want to fire only once for each keypress
implement on of those if implement all of the three all three methods will fired.
Additionally: for safety you can write e.preventDefault().

Jquery capture tab + some key combination

How can I catch, for example, tab+t combination with jQuery? I've found a lot of examples with alt, shift and ctrl, since event object contains special flags in order to understand if, for example, alt was pressed. But there is not such thing for tab.
This should work. It's a bit convoluted and there is likely an easier way, but it works fine.
JSFiddle: https://jsfiddle.net/spybhhxc/
var tabdown = false;
var tdown = false;
$(document).keydown(function(e) {
if(e.which == 9) {
tabdown = true;
}
if(e.which === 84)
{
tdown = true;
}
if(tabdown && tdown)
{
//do your thing
}
});
$(document).keyup(function(e) {
if(e.which == 9) {
tabdown = false;
}
if(e.which === 84)
{
tdown = false;
}
});
This presents a problem though, as once you press tab, the document is unfocused as the tab key navigates to elements in a browser. You would be much better off using something like alt or ctrl which don't interact with the browser.
We can have a tab key pressed [tabPressed] variable which will be set to true on key down and unset the same on its key up event. We will using the tab key pressed[tabPressed] variable to check whether it is in pressed state during the other key press activities. The tab keycode is 9.
jsfiddle link http://jsfiddle.net/e3Lveyj2/
var tabPressed=false;
function handleKeyDown(e) {
var evt = (e==null ? event:e);
if(evt.keyCode == 9){
tabPressed=true;
}
if ((tabPressed) && (evt.keyCode == 84)) {
alert ("You pressed 'Tab+t'")
}
}
function handleKeyUp(e) {
var evt = (e==null ? event:e);
if(evt.keyCode == 9){
tabPressed=false;
}
}
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;

function to move character/camera when button pressed

I'm new here and also new with web coding. So i am trying to make a function to move my game character when a button is pressed. When button is pressed down a boolean value changes to "true" and the character moves. I was trying to do it somehow like this. Can someone light me up what is the best way to make this work? I need also to do this for all the rest buttons (a,s,d,arrows).
var wButton = false;
function newfunction()
document.querySelector('#keyButtonW').addEventListener('mousedown', function(event) {
keyButtonPressed("wButton", true);
});
document.querySelector('#keyButtonW').addEventListener('mouseup', function(event) {
keyButtonPressed("wButton", false);
});
document.querySelector('#keyButtonW').addEventListener('mouseleave', function(event) {
keyButtonPressed("wButton", false);
});
Assuming translate is a method to move your char, maybe you should make a big maskArray :
var keyboard = [];
function keyDown(e)
{
var key = event.keyCode || event.which;
keyboard[key] = true;
}
function keyUp(e)
{
var key = event.keyCode || event.which;
delete keyboard[key];
}
function keyAction() {
for (i in keyboard)
{
if (keyboard[i] == true)
{
switch(eval(i))
{
case 90: //Z
character.translateY(-1);
break;
case 83: //S
character.translateY(1);
break;
case 81: //Q
character.translateX(-1);
break;
case 68: //D
character.translateX(1);
break;
}
}
}
return false;
}
document.addEventListener("keydown", keyDown, false);
document.addEventListener("keyup", keyUp, false);
Simply put keyAction() inside your main loop / rendering loop.
The value of this is to not make lags happen when you hit a button, and help with multiple pressing management =)
EDIT
To get the key numbers, simply put a console.log(key) at the end of keyDown().

Key Navigation with Javascript

Please Help! I have spent a week to complete this game and this is the final huddle i have been stuck with for a couple of days now. I know some techy out there would probably take a glance and flick something in place. But I'm not very sophisticated with javascript and therefore need some help.
$(document).keydown(function(e){
// left arrow
if (e.keyCode == 37 && currentCell > 0) {
currentCell--;
ChangeCurrentCell();
return false;
}
// up arrow
if (e.keyCode == 38 && currentRow > 0) {
currentRow--;
ChangeCurrentCell();
return false;
}
// right arrow
if (e.keyCode == 39 && currentCell < MAX_CELL) {
currentCell++;
ChangeCurrentCell();
return false;
}
//down arrow
if (e.keyCode == 40 && currentRow < MAX_ROW) {
currentRow++;
ChangeCurrentCell();
return false;
}
// enter key
if (e.keyCode == 13) {
}
});
function ChangeCurrentCell()
{
document.getElementById(Boxes[currentRow + currentCell]).focus();
SimulateMouseOver(document.getElementById(Boxes[currentRow + currentCell]));
}
// function will trigger event of selecting current focus.
function selectElement()
{
}
$(document).ready(function(){
loadDivs()
// will give initial focus to top left element paving way for key navigation
ChangeCurrentCell();
// above gives first element in Boxes the focus when loading.
The div element will not focus despite getting it and calling the focus method, i have tried to trigger mousehover on the element with no luck. Please assist me, i put my masters thesis aside despite already being on a tight schedule to do this game which is a requirement for a job position. I have done whole the whole game logic and it all works well, if i send the code in as it is it will definitely be discarded because it doesnt meet the key navigation requirement ... i am desperate i will even pay if i need to -frustrated Student
Look at this
It's my solution for a test, maybe the same...maybe can help you :) If it is, please use it as a hint and don't copy all my code :D
Regards,
L.
You can bind to the document.keydown event to capture key strokes. Then you can use event.which (normalized by jQuery) to determine which key was pressed.
$(document).on("keydown", function (event) {
if (event.which === 37) {
//code for left arrow
} else if (event.which === 38) {
//code for up arrow
} else if (event.which === 39) {
//code for right arrow
} else if (event.which === 40) {
//code for down arrow
}
});
UPDATE
I just noticed you didn't tag your question with jQuery. To use native JS you'll have to change how you bind to the document.keydown event and how you determine the key that was pressed (different browser implementations store the info under different indexes of the event object).
to make it more convenient () not necessary:
`var LEFT = 37, UP = 38, RIGHT = 39, DOWN = 40, SPACE = 32;`
then bind to keydown, keypress doesn't catch arrow keys
and do something like this:
$(document).bind("keydown", function (e){
var which = e.which;
var navigationKeyWasPressed = which !== undefined && which >= 39 && which <= 40;
//do nothing if no significant key was pressed
if (!navigationKeyWasPressed ) {
return;
}
if ($(".selectedWithKey").length === 1){
switch (which) {
case LEFT:
//...
break;
case UP:
//...
break;
case RIGHT:
//...
break;
case DOWN:
//...
break;
case SPACE:
//turn card
break;
default: //non arrow pressed
//...
}
} else {
// if no card is selected, select one to start arrow navigation
$(".sponsor:first").addClass("selectedWithKey")
}
});

Javascript multiple keys depressed

so right now I'm using a function that will set a value to true if one key being pressed, another being pressed regardless of whether or not the first one is still depressed.
function doc_keyUp1(e) {
if (e.keyCode == 37){
lPunch = true
}
}
function doc_keyUp2(e) {
if (e.keyCode == 39){
rPunch = true
}
}
document.addEventListener('keyup', doc_keyUp1, false)
document.addEventListener('keyup', doc_keyUp2, false)
The thing is, I want to be able to have it make sure that if the second key is being pressed, that the first one must still be down, so that someone can't just press one then the other quickly and make it seem as if they were both pressed down at the same time.
Any ideas?
Assuming you have some kind of "game loop" something like the following works (or perhaps I should say "should work", in that I haven't coded something like this for a long time and so haven't tested it with current browsers - definitely used to work):
var keyPressed = {};
document.addEventListener('keydown', function(e) {
keyPressed[e.keyCode] = true;
}, false);
document.addEventListener('keyup', function(e) {
keyPressed[e.keyCode] = false;
}, false);
function gameLoop() {
if (keyPressed["39"] && keyPressed["37"]) {
// do something (update player object state, whatever)
}
// etc
// update display here
setTimeout(gameLoop, 5);
}
gameLoop();
I'd suggest you use an Array to hold key states.
var keyStates = [ ];
document.addEventListener('keydown', function(e) {
keyStates.push( e.keyCode );
}, false);
document.addEventListener('keyup', function(e) {
var pos = null;
if( (pos = keyStates.indexOf( e.keyCode )) > -1 )
keyStates.splice( pos, 1 );
}, false);
So with that, you can always check that array for keys currently beeing pushed.
var currentKeyCodes=new Object();
function keyDown(e) {
currentKeyCodes['x'+e.keyCode]=true;
}
function keyUp(e) {
//Real check here
if ((e.keyCode==39) && currentKeyCodes['x37']) {
do_whatever_you_want();
}
//Housekeeping
var s='x'+e.keyCode;
if (currentKeyCodes[s]) currentKeyCodes[2]=false;
}

Categories