how to use two onkeydown events at the same time? - javascript

I'm trying to build a pong game, and I want the boards to be able to move simultaneously (one with the 's' and 'w' and the other with the up and down arrows).
function movePlayer1(event) {
if (player1.y > 7.5 && player1.y < 390) {
switch (event.keyCode) {
case 83: player1.y += player1.v;
break;
case 87: player1.y -= player1.v;
break;
}
}
else if (player1.y <= 7.5) {
switch (event.keyCode) {
case 83: player1.y += player1.v;
break;
}
}
else if (player1.y >= 390) {
switch (event.keyCode) {
case 87: player1.y -= player1.v;
break;
}
}
}
document.addEventListener("keydown", movePlayer1, false);
function movePlayer2() {
if (player2.y > 7.5 && player2.y < 390) {
switch (event.keyCode) {
case 40: player2.y += player2.v;
break;
case 38: player2.y -= player2.v;
break;
}
}
else if (player2.y <= 7.5) {
switch (event.keyCode) {
case 40: player2.y += player2.v;
break;
}
}
else if (player2.y >= 390) {
switch (event.keyCode) {
case 38: player2.y -= player2.v;
break;
}
}
}
document.addEventListener("keydown", movePlayer2, false);
I've tried putting them in one function instead but it didn't help.

There are two things make you code behave not as you expect.
Autorepeating works only for last pressed key. Say if you press "A" and hold it autorepeating will generate keydown events for "A". But if you press "B" and hold both autorepeating will generate sequential keydown automatically for "B" only. On the other side I believe for MacOS it will not autorepeat at all so better not rely on this.
But actually "keyup" are triggered correctly even if mutliple keys were pressed and are hold.
So you can refactor your code: instead of relying on keyup/keydown only you need some timer and each player model will be
{
directionIsUp: true | false,
isMoving: true | false
}
So on keydown you are setting appropriate direction and make isMoving to be true. And on keyup you are making isMoving to be false.
And timer will re-render your battlefield accordingly to those models - either moving player or keeping it at the same place.

Related

Why this switch isn't giving any output? [duplicate]

Am I writing the correct switch case with conditions?
var cnt = $("#div1 p").length;
alert(cnt);
switch (cnt) {
case (cnt >= 10 && cnt <= 20):
alert('10');
break;
case (cnt >= 21 && cnt <= 30):
alert('21');
break;
case (cnt >= 31 && cnt <= 40):
alert('31');
break;
default:
alert('>41');
}
For some reason, the alert does not occur when the conditions are matched!
A switch works by comparing what is in switch() to every case.
switch (cnt) {
case 1: ....
case 2: ....
case 3: ....
}
works like:
if (cnt === 1) ...
if (cnt === 2) ...
if (cnt === 3) ...
Therefore, you can't have any logic in the case statements.
switch (cnt) {
case (cnt >= 10 && cnt <= 20): ...
}
works like
if (cnt === (cnt >= 10 && cnt <= 20)) ...
and that's just nonsense. :)
Use if () { } else if () { } else { } instead.
You should not use switch for this scenario. This is the proper approach:
var cnt = $("#div1 p").length;
alert(cnt);
if (cnt >= 10 && cnt <= 20)
{
alert('10');
}
else if (cnt >= 21 && cnt <= 30)
{
alert('21');
}
else if (cnt >= 31 && cnt <= 40)
{
alert('31');
}
else
{
alert('>41');
}
This should work with this :
var cnt = $("#div1 p").length;
switch (true) {
case (cnt >= 10 && cnt <= 20):
alert('10');
break;
case (cnt >= 21 && cnt <= 30):
alert('21');
break;
case (cnt >= 31 && cnt <= 40):
break;
default:
alert('>41');
}
Something I came upon while trying to work a spinner was to allow for flexibility within the script without the use of a ton of if statements.
Since this is a simpler solution than iterating through an array to check for a single instance of a class present it keeps the script cleaner. Any suggestions for cleaning the code further are welcome.
$('.next').click(function(){
var imageToSlide = $('#imageSprite'); // Get id of image
switch(true) {
case (imageToSlide.hasClass('pos1')):
imageToSlide.removeClass('pos1').addClass('pos2');
break;
case (imageToSlide.hasClass('pos2')):
imageToSlide.removeClass('pos2').addClass('pos3');
break;
case (imageToSlide.hasClass('pos3')):
imageToSlide.removeClass('pos3').addClass('pos4');
break;
case (imageToSlide.hasClass('pos4')):
imageToSlide.removeClass('pos4').addClass('pos1');
}
}); `
What you are doing is to look for (0) or (1) results.
(cnt >= 10 && cnt <= 20) returns either true or false.
--edit--
you can't use case with boolean (logic) experessions. The statement cnt >= 10 returns zero for false or one for true. Hence, it will we case(1) or case(0) which will never match to the length.
--edit--
function date_conversion(start_date){
var formattedDate = new Date(start_date);
var d = formattedDate.getDate();
var m = formattedDate.getMonth();
var month;
m += 1; // JavaScript months are 0-11
switch (m) {
case 1: {
month="Jan";
break;
}
case 2: {
month="Feb";
break;
}
case 3: {
month="Mar";
break;
}
case 4: {
month="Apr";
break;
}
case 5: {
month="May";
break;
}
case 6: {
month="Jun";
break;
}
case 7: {
month="Jul";
break;
}
case 8: {
month="Aug";
break;
}
case 9: {
month="Sep";
break;
}
case 10: {
month="Oct";
break;
}
case 11: {
month="Nov";
break;
}
case 12: {
month="Dec";
break;
}
}
var y = formattedDate.getFullYear();
var now_date=d + "-" + month + "-" + y;
return now_date;
}
Switch case is every help full instead of if else statement :
switch ($("[id*=btnSave]").val()) {
case 'Search':
saveFlight();
break;
case 'Update':
break;
case 'Delete':
break;
default:
break;
}
Ok it is late but in case you or someone else still want to you use a switch or simply have a better understanding of how the switch statement works.
What was wrong is that your switch expression should match in strict comparison one of your case expression. If there is no match it will look for a default. You can still use your expression in your case with the && operator that makes Short-circuit evaluation.
Ok you already know all that. For matching the strict comparison you should add at the end of all your case expression && cnt.
Like follow:
switch(mySwitchExpression)
case customEpression && mySwitchExpression: StatementList
.
.
.
default:StatementList
var cnt = $("#div1 p").length;
alert(cnt);
switch (cnt) {
case (cnt >= 10 && cnt <= 20 && cnt):
alert('10');
break;
case (cnt >= 21 && cnt <= 30 && cnt):
alert('21');
break;
case (cnt >= 31 && cnt <= 40 && cnt):
alert('31');
break;
default:
alert('>41');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div1">
<p> p1</p>
<p> p2</p>
<p> p3</p>
<p> p3</p>
<p> p4</p>
<p> p5</p>
<p> p6</p>
<p> p7</p>
<p> p8</p>
<p> p9</p>
<p> p10</p>
<p> p11</p>
<p> p12</p>
</div>

How can I fix keydown delays in Javascript game?

I am creating a javascript snake game, and have run into a problem when certain keys are pressed too fast in order. For example, (while going right) hitting the up arrow and then the left arrow key too fast will make my snake turn around completely and run into itself, ignoring the up arrow key press. Is there any code that would make sure that any key press will always be rendered? Thanks in advance.
let d = "RIGHT";
document.addEventListener("keydown", direction);
function direction(event) {
let key = event.keyCode;
if (key == 37 && d != "RIGHT" && d != "LEFT") {
d = "LEFT";
} else if (key == 38 && d != "DOWN" && d != "UP") {
d = "UP";
} else if (key == 39 && d != "LEFT" && d != "RIGHT") {
d = "RIGHT";
} else if (key == 40 && d != "UP" && d != "DOWN") {
d = "DOWN";
}
}
In separate function:
if (d == "LEFT") snakeX -= box;
if (d == "UP") snakeY -= box;
if (d == "RIGHT") snakeX += box;
if (d == "DOWN") snakeY += box;
You can also see this problem by going to https://jssnake.glitch.me/ and playing around a bit.
I briefly looked into your code. You render 10x a second, so if you manage to press more than one key during that interval, the described issue will occur:
For example, (while going right) hitting the up arrow and then the left arrow key too fast will make my snake turn around completely and run into itself, ignoring the up arrow key press.
There are two possible solutions:
Run the render loop faster, so that no one can ever press two keys during that interval.
Do not store only the last key, but all keys that were pressed between since the last render call.
Avoid half-turns.
I think solution 1 is not ideal as you should never say never. So let's continue with number 3 (a hack) and then with number 2 (the correct and clean way).
Avoid half-turns (alternative 3)
This little hack does not solve the root of the problem, but it will make the snake behave kind-of correct. The snake can move in 4 directions, but it can always turn only in two directions. You could either use a two-keys control to trigger CW/CCW change, something like
let currentDir = "RIGHT"; //note I renamed your d to currentDir
let nextDir = undefined;
document.addEventListener("keydown", direction);
function direction(event) {
const key = event.keyCode;
while (~currentDir) {}; //wait until the control function is finished
switch (currentDir) {
case "LEFT": nextDir = (key === 37 ? "DOWN" : (key === 39 ? "UP" : nextDir)); break;
case "UP": nextDir = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : nextDir)); break;
case "RIGHT": nextDir = (key === 37 ? "UP" : (key === 39 ? "DOWN" : nextDir)); break;
case "DOWN": nextDir = (key === 37 ? "RIGHT" : (key === 39 ? "LEFT" : nextDir)); break;
}
}
//and later in the movement control function:
currentDir = undefined; //avoid overwriting nextDir during this update,
// i.e. the while-loop inside of direction() will wait
switch (tmp) {
case "LEFT": snakeX -= box; break;
case "UP": snakeY -= box; break;
case "RIGHT": snakeX += box; break;
case "DOWN": snakeY += box; break;
}
currentDir = nextDir;
nextDir = undefined;
The four-keys version would work in a similar way, you can easily intergrate it to your code. The key is to use the pair of currentDir and nextDir and keeping currentDir constant over the whole 0.1s time between the render calls. But your problem would kind-of stay. A snake heading right would only continue up if you would press ↑ and ← immediately after each other.
let currentDir = "RIGHT";
let nextDir = undefined;
document.addEventListener("keydown", direction);
function direction(event) {
const key = event.keyCode;
while (~currentDir) {}; //wait until the control function is finished
switch (currentDir) {
case "LEFT":
case "RIGHT":
nextDir = (key === 38 ? "UP" : (key === 40 ? "DOWN" : nextDir)); break;
case "UP":
case "DOWN":
nextDir = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : nextDir)); break;
}
}
Keys buffer (alternative 2)
The correct solution is even easier, but requires an array. It stores all keys pressed since the last render call in a queue.
keysPressed = [];
document.addEventListener("keydown", event =>
keysPressed.push(event.keyCode); //enqueues the key pressed
Having two or three keys pressed, you could virtually update the snake position inside of the 0.1s interval applying one valid turn in each frame. This could lead to delayed snake movement if you would be able to fill the buffer quickly with commands. It can be interesting to try out as a fun excercise. The movement function for the four-keys control would look like this:
{
if (keysPressed.length > 0 {
const key = keysPresses.shift(); //dequeues the oldest key
//if there are more keys in the queue, they have to wait until next time
switch (d) {
case "LEFT":
case "RIGHT":
d = (key === 38 ? "UP" : (key === 40 ? "DOWN" : d)); break;
case "UP":
case "DOWN":
d = (key === 37 ? "LEFT" : (key === 39 ? "RIGHT" : d)); break;
}
}
switch (d) {
case "LEFT": snakeX -= box; break;
case "UP": snakeY -= box; break;
case "RIGHT": snakeX += box; break;
case "DOWN": snakeY += box; break;
}
}
What you need here is to delay the effect of a key press. You can achieve it by storing the last pressed key in a variable and only reading the key when snake is ready to turn.
let pressedKey;
document.addEventListener("keydown", event => {
pressedKey = event.keyCode;
});

Using JavaScript operators in a switch statement with event.code [duplicate]

This question already has answers here:
Switch statement for multiple cases in JavaScript
(26 answers)
Closed 3 years ago.
I have a switch statement in which I try to map keyboard shortcuts to a horizontal full page scrolling:
Space Bar or Page Down or Right Arrow
scrolls forward
Page Up or Left Arrow scrolls
backward
Home or Up Arrow goes to the beginning
of the page
End or Down Arrow scrolls to the end
of the page
Here is my attempt, which isn’t working:
switch (event.code) {
case "Space" || "PageDown" || "ArrowRight": {
scrollAmount += window.innerWidth
break
}
case "PageUp" || "ArrowLeft": {
scrollAmount -= window.innerWidth
break
}
case "Home" || "ArrowUp": {
scrollAmount = 0
break
}
case "End" || "ArrowDown": {
scrollAmount = container.scrollWidth
break
}
}
How do I propely use the operators in this case?
You should specify each case separately:
switch (event.code) {
case "Space":
case "PageDown":
case "ArrowRight": {
scrollAmount += window.innerWidth
break
}
case "PageUp":
case "ArrowLeft": {
scrollAmount -= window.innerWidth
break
}
case "Home":
case "ArrowUp": {
scrollAmount = 0
break
}
case "End":
case "ArrowDown": {
scrollAmount = container.scrollWidth
break
}
}

Why does this switch statement not work? [duplicate]

This question already has answers here:
Expression inside switch case statement
(8 answers)
Closed 6 years ago.
I created a switch statement but everything seems to be falling into the default condition. If I rewrite this in an if/else format it works correctly. Can anyone explain why this is? Thanks!
Doesn't work:
switch(delta){
case (delta<10):
xsmall++;
break;
case (delta>= 10 && delta< 50):
small++;
break;
case (delta>= 50 && delta<250):
med++;
break;
case (delta>= 250 && delta<1000):
large++;
break;
case (delta>= 1000):
xlarge++;
break;
default:
unknown++;
}
Works successfully:
if(delta<10)
xsmall++;
else if(delta>= 10 && delta < 50)
small++;
else if(delta >= 50 && delta < 250)
med++;
else if(delta >= 250 && delta <1000)
large++;
else if(delta >= 1000)
xlarge++;
else
unknown++;
This will work:
switch(true){
case (delta<10):
xsmall++;
break;
case (delta>= 10 && delta< 50):
small++;
break;
case (delta>= 50 && delta<250):
med++;
break;
case (delta>= 250 && delta<1000):
large++;
break;
case (delta>= 1000):
xlarge++;
break;
default:
unknown++;
}
Reason: You need to pass boolean to the switch statement as all your cases will return boolean and not a number

How to change image on key release

I'm working on a little game using HTML5 canvas and javascript. Now what I am trying to do is to make an image move from left to right and when pressing a key it changes image to make it look more like it is moving.
Now I got that working but I'm kind of stuck. The code is that when you press the left key he changes the player.image to player.imgLeft and when releasing change it back to the normal image.
The pressing works but the releasing doesn't.. What am I doing wrong?
Here is in short the code
// Things to do when keys are down
function onKeyDown(event)
{
if (event.keyCode >= 37 && event.keyCode<=39)
event.preventDefault(); // prevent arrow keys from scrolling the page
switch (event.keyCode) {
case 37: player.vx = -1; player.image = player.imgLeft; break; // left key
case 38: player.vy = -1; break; // up key
case 39: player.vx = 1; player.image = player.imgRight; break; // right key
}
}
// Things to do when keys are up
function onKeyUp(event)
{
switch (event.keyCode) {
case 37: case 39: player.vx = 0; player.imgLeft = player.image; break; // left or right key released
case 38: player.vy = 0; break; // up or down key released
}
}
Modify like this if you have your original image in player.original.. Onkeyup event you should use like this ...
function onKeyUp(event)
{
switch (event.keyCode) {
case 37: case 39: player.vx = 0; player.image = player.original; break; // left or right key released
case 38: player.vy = 0; break; // up or down key released
}
}
When you press the key, you do
player.image = player.imgLeft
and when you release, you do
player.imgLeft = player.image;
which does nothing, as both variables hold the same value. You need a third variable to store the original player.image value.
Remember:
If you are using onkeydown="return onKeyDown(event)" you need onkeyup="return onKeyUp(event)".

Categories