How to change image on key release - javascript

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)".

Related

How do you change a do while loop to a while loop?

One of the questions on my assignment was to switch a do while into a while loop. I am a little stuck I tried moving it around a butch different ways but my code still doesn't output correctly.
do {
userChoice = window.prompt("Press a to add a Robot Step to take\n, Press r to remove a Robot Step last Step to take\n, Press f to remove a Robot First Step to take\n, Press p to make the robot move the steps,");
userChoice = userChoice.toLowerCase();
switch(userChoice) {
case "a":
addStepsPerMovement(stepsPerMovement);
break;
case "r":
removeLastMovement(stepsPerMovement);
break;
case userChoice == "f":
removeFirstMovement(stepsPerMovement);
break;
case "p":
printByWhileLoop (stepsPerMovement);
break;
default:
document.write("Erroneous Choice\n");
break;
}
userContinue = window.prompt("Do you want to continue?, y or n");
userContinue = userContinue.toLowerCase();
} while (userContinue == "y")
You can easily interchange a do-while with:
while(true) {
/* body */
if(!/*condition*/)
break;
}
that ?
let userContinue = "y"
while (userContinue == "y")
{
userChoice = window.prompt("Press a to add a Robot Step to take\n, Press r to remove a Robot Step last Step to take\n, Press f to remove a Robot First Step to take\n, Press p to make the robot move the steps,");
userChoice = userChoice.toLowerCase();
switch(userChoice)
{
case "a":
addStepsPerMovement(stepsPerMovement);
break;
case "r":
removeLastMovement(stepsPerMovement);
break;
case "f":
removeFirstMovement(stepsPerMovement);
break;
case "p":
printByWhileLoop (stepsPerMovement);
break;
default:
document.write("Erroneous Choice\n");
break;
}
userContinue = window.prompt("Do you want to continue?, y or n");
userContinue = userContinue.toLowerCase();
}
Hi This is very simple ,
The difference between do while and while is:
In do while the code block will execute one time irrespective of while condition.
but in while , if and only if the condition is true then only execute.
So according to your code here is the snippet:
Declare a function which contains the body section of do while.
function dowhiletoWhile() {
userChoice = window.prompt("Press a to add a Robot Step to take\n, Press r to remove a Robot Step last Step to take\n, Press f to remove a Robot First Step to take\n, Press p to make the robot move the steps,");
userChoice = userChoice.toLowerCase();
switch(userChoi`enter code here`ce) {
case "a":
addStepsPerMovement(stepsPerMovement);
break;
case "r":
removeLastMovement(stepsPerMovement);
break;
case userChoice == "f":
removeFirstMovement(stepsPerMovement);
break;
case "p":
printByWhileLoop (stepsPerMovement);
break;
default:
document.write("Erroneous Choice\n");
break;
}
userContinue = window.prompt("Do you want to continue?, y or n");
userContinue = userContinue.toLowerCase();
}
dowhiletoWhile();
while (userContinue == "y"){
dowhiletoWhile();
}

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
}
}

Javascript operators in switch case

I'm creating a panel and there are stats for memory, CPU and HDD. I'm using a switch statement and in the case method, I'm putting the current usage of CPU, memory and HDD.
However, the problem is that I'm using operators and I don't know which operator to use because I've tried all of them and I didn't get the results that I expected.
And this is the code: https://pastebin.com/YaxCm0Be
switch(true){
case (mem_percent_get <= 0.01):
var mem_progress_color = 'progress-bar-primary';
break;
case (mem_percent_get <= 33):
var mem_progress_color = 'progress-bar-success';
break;
case (mem_percent_get <= 66):
var mem_progress_color = 'progress-bar-warning';
break;
case (mem_percent_get <= 80):
var mem_progress_color = 'progress-bar-danger';
break;
default:
mem_progress_color = 'progress-bar-theme';
}
switch(true){
case (cpu_percent_get <= 33):
var cpu_progress_color = 'progress-bar-success';
break;
case (cpu_percent_get <= 66):
var cpu_progress_color = 'progress-bar-warning';
break;
case (cpu_percent_get <= 80):
var cpu_progress_color = 'progress-bar-danger';
break;
default:
cpu_progress_color = 'progress-bar-primary';
}
switch(true){
case hdd_percent_get <= 0.01:
var hdd_progress_color = 'progress-bar-primary';
break;
case hdd_percent_get <= 30:
var hdd_progress_color = 'progress-bar-success';
break;
case hdd_percent_get <= 60:
var hdd_progress_color = 'progress-bar-warning';
break;
case hdd_percent_get <= 80:
var hdd_progress_color = 'progress-bar-danger';
break;
default:
hdd_progress_color = 'progress-bar-theme';
}
Well, my first comment is to not use a switch in this case. What you are doing is essentially if () { } else if() {} blocks. You should be using switch when you have a value that you want to strictly check against. I suggest looking into at the MDN docs for switch.
Secondly, from what I can gather is that for the memory, you need it to be red when the value is 1696 / 2098 (80.83%). All of your if/elseif cases rely on <= which would mean that the value must be less than or equal to the number on the right of the equation. In your case, you are looking for <= 80, and without seeing how you calculate mem_percent_get (if it is in the pastebin, I'm unable to open that on my current network), you're value is likely above 80.
For your danger, you likely want 80-100+% as being red, so you should be using >= or greater than or equal to operator.
MDN has an excellent resources on comparison operators.
Created a getClassName method that accepts a percent and will return a className:
const getClassName = percent => {
switch(true){
case (percent <= 0.01):
return 'progress-bar-primary';
case (percent <= 33):
return 'progress-bar-success';
case (percent <= 66):
return 'progress-bar-warning';
case (percent <= 80):
return 'progress-bar-danger';
default:
return 'progress-bar-theme';
}
}
console.log('0: ', getClassName(0));
console.log('40: ', getClassName(40));
console.log('50: ', getClassName(50));
console.log('80: ', getClassName(80));
console.log('100: ', getClassName(100));

how to use two onkeydown events at the same time?

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.

Categories