Im creating a small game in javascript that requires multiple keys to be pressed at once for an avatars movement.
To recognize multiple key presses I'm using "Braden Best"s answer to the question JavaScript multiple keys pressed at once which works well except for the fact that the document doesn't seem to multitask keyup events. For example if I want to press the up arrow key followed by the left arrow key then release the left arrow key the avatar would stop completely.
Here is an example code: https://Jsfiddle.net/552gc9dh/1/
var c = document.getElementById("canv");
var canv = c.getContext("2d");
console.log("test");
var map = {};
var playerlist = [];
function player(width, height, x, y, color, speedx, speedy) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.color = color;
this.speedx = speedx;
this.speedy = speedy;
playerlist.push(this);
}
var player1 = new player(50, 50, 0, 0, "red", 2, 2);
console.log(playerlist[0]);
function gravity(playerY) {
}
function createplayerlistener(name, key1, key2, key3, key4) {
onkeydown = onkeyup = function(e) {
e = e || event;
map[e.keyCode] = e.type == 'keydown';
if (name.x + name.speedx < c.width - name.width) {
if (map[key1]) {
name.x += name.speedx;
}
}
if (name.x + name.speedx > 0) {
if (map[key2]) {
name.x -= name.speedx;
}
}
if (name.y + name.speedy < c.height - name.height) {
if (map[key3]) {
name.y += name.speedy;
}
}
if (name.y + name.speedy > 0) {
if (map[key4]) {
name.y -= name.speedy;
}
}
}
}
createplayerlistener(player1, 39, 37, 40, 38);
setInterval(function() {
canv.clearRect(0, 0, c.width, c.height);
for (var i = 0; i <= playerlist.length - 1; i++) {
canv.fillStyle = playerlist[i].color; // iterates through players and draws them
canv.fillRect(playerlist[i].x, playerlist[i].y, playerlist[i].width, playerlist[i].height);
}
}, 10);
This answer is more of a strategy...
I would set variables for directions and update them on keyDown
and keyUp
Sudo Code
const North = false;
const West = false;
const South = false;
const East = false;
keyUp = keyDown = (keyType) {
switch(keyType) {
case 'up':
North = !North;
break;
case 'right':
East = !East;
break;
case 'down':
South = !South;
break;
case 'left':
West = !West;
break;
};
}
setInterval({
if(North) //move up
if(South) //move down
if(East) //Move right
if(West) //Move left
}, 10);
This should maintain the current movement until you receive a command to cancel it. It will also allow up and down or right and left to counter each other if a user presses both.
Hopefully this helps!
Addition
Likely a more performant option would actually be to create a setInteval
on keydown for a specific direction and remove it on keyUp, that way if the player is not interacting you are not running extra cycles ever 1/100 of a second
directions = {
up: null,
right: null,
down: null,
left: null
}
const startInterval = (keyType) => {
direction[keyType] = setInteval(()=> move(keyType);
}
const endInterval = (keyType) => {
clearInterval( direction[keyType]);
direction[keyType] = null;
}
const keyUp = keyDown = (keyType) {
if(direction[keyType] === null) {
startInteval(keyType);
} else {
endInterval(keyType);
}
}