setInterval() only fires once - javascript

var x = 0;
window.addEventListener("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
setInterval(changeValue, 1000, "up");
break;
case "ArrowRight":
setInterval(changeValue, 1000, "down");
break;
}
})
function changeValue(direction) {
switch (direction) {
case "up":
x += 10;
console.log(x);
break;
case "down":
x -= 10;
console.log(x);
break;
}
}
I was expecting my code to keep adding or subtracting 10 from x every second depending on what arrow key the user has pressed. However, setInterval only seems to fire once, and I can't figure out why.

A way to do what you are looking for:
var
conterVal = 0
, addValue = -10
, refIntv = null
;
bt_tenMoreLess.onclick =_=>
{
addValue = -addValue
if (!refIntv)
{
counter.textContent = conterVal += addValue
refIntv = setInterval( changeValue , 1000)
bt_stop.disabled = false
}
}
bt_stop.onclick =_=>
{
clearInterval( refIntv )
refIntv = null
bt_stop.disabled = true
}
function changeValue()
{ counter.textContent = conterVal += addValue }
<p id="counter">0</p>
<button id="bt_tenMoreLess">count ± 10</button>
<button id="bt_stop" disabled >stop</button>

Related

How to put an interval inside a switch case statment of keycode without allowing the user to tab twice

Im building a pacman game and i put a switch statement and put interval so that the user has to press right arrow once and pacman will keep moving right the problem is that if i tab twice it move twice as fast and i tab right then left it'll move right left right left.....
i'll show the first code where there was no problem this code is without interval
JS code without interval:
const grid = document.querySelector('.grid');
const scoreEl = document.getElementById('score');
const width = 28;
let squares = [];
let score = 0;
const layout = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
1,3,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,3,1,
1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,
1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,4,4,4,4,4,4,4,4,4,4,1,1,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,4,1,1,1,2,2,1,1,1,4,1,1,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,4,1,2,2,2,2,2,2,1,4,1,1,0,1,1,1,1,1,1,
4,4,4,4,4,4,0,0,0,4,1,2,2,2,2,2,2,1,4,0,0,0,4,4,4,4,4,4,
1,1,1,1,1,1,0,1,1,4,1,2,2,2,2,2,2,1,4,1,1,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,4,1,1,1,1,1,1,1,1,4,1,1,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,4,1,1,1,1,1,1,1,1,4,1,1,0,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,1,
1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
1,3,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,3,1,
1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,
1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,
1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,
1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,
1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
];
// 0 - pacdots
// 1 - wall
// 2 - ghost lair
// 3 - powerpellets
// 4 - empty
function createBoard() {
for (let i = 0; i < layout.length; i++) {
const square = document.createElement('div');
grid.appendChild(square);
squares.push(square);
if (layout[i] === 0) {
squares[i].classList.add('pac-dot');
} else if (layout[i] === 1) {
squares[i].classList.add('wall');
} else if (layout[i] === 2) {
squares[i].classList.add('ghost-lair');
} else if (layout[i] === 3) {
squares[i].classList.add('power-pallets');
}
}
}
createBoard();
let pacManPosition = 490;
squares[pacManPosition].classList.add('pac-man');
function move(e) {
squares[pacManPosition].classList.remove('pac-man');
//console.log(e.key)
//fix all these cases
switch (e.key) {
case 'ArrowUp':
if (!squares[pacManPosition - width].classList.contains('wall')) {
pacManPosition -= width;
}
break;
case 'ArrowRight':
if (!squares[pacManPosition + 1].classList.contains('wall')) {
pacManPosition++;
}
break;
case 'ArrowDown':
console.log('DOWN');
if (!squares[pacManPosition + width].classList.contains('wall')) {
pacManPosition += width;
}
break;
case 'ArrowLeft':
if (!squares[pacManPosition - 1].classList.contains('wall')) {
pacManPosition--;
}
break;
}
squares[pacManPosition].classList.add('pac-man');
pacdotsEaten();
powerPelletsEaten();
}
document.addEventListener('keyup', move);
JS Code with intervals:
//
let myInt = '';
//
function move(e) {
squares[pacManPosition].classList.remove('pac-man');
//console.log(e.key)
//fix all these cases
switch (e.key) {
case 'ArrowUp':
myInt = setInterval( function () {
//console.log('up')
if (!squares[pacManPosition - width].classList.contains('wall')) {
squares[pacManPosition].classList.remove('pac-man');
pacManPosition -= width;
squares[pacManPosition].classList.add('pac-man');
}
}, 400)
break;
case 'ArrowRight':
myInt = setInterval( function () {
//console.log('up')
if (!squares[pacManPosition + 1].classList.contains('wall')) {
squares[pacManPosition].classList.remove('pac-man');
pacManPosition++;
squares[pacManPosition].classList.add('pac-man');
}
}, 400)
break;
case 'ArrowDown':
console.log('DOWN');
myInt = setInterval( function () {
//console.log('up')
if (!squares[pacManPosition + width].classList.contains('wall')) {
squares[pacManPosition].classList.remove('pac-man');
pacManPosition += width;
squares[pacManPosition].classList.add('pac-man');
}
}, 400)
break;
case 'ArrowLeft':
myInt = setInterval( function () {
//console.log('up')
if (!squares[pacManPosition - 1].classList.contains('wall')) {
squares[pacManPosition].classList.remove('pac-man');
pacManPosition--;
squares[pacManPosition].classList.add('pac-man');
}
}, 400)
break;
}
squares[pacManPosition].classList.add('pac-man');
pacdotsEaten();
powerPelletsEaten();
}
how can i fix this?
some guy answered as a comment that i should clear the inteval on each key pressed. i don't know why i haven't thought about that
the answer :
case 'ArrowUp':
clearInterval(myInt);
myInt = setInterval( function () {
//console.log('up')
if (!squares[pacManPosition - width].classList.contains('wall')) {
powerPelletsEaten();
squares[pacManPosition].classList.remove('pac-man');
pacManPosition -= width;
squares[pacManPosition].classList.add('pac-man');
pacdotsEaten();
}
}, 400)
break;

Disable keyboard in javascript

I'm trying to figure out how to make the keyboard get disabled after the score equals five. with everything else I'm fine. I got everything else done that I need to get done I'm just having issues with the keyboard, if I could get some help on this it would greatly be appreciated. this is just giving me a hard time so I thought I would get some help.
//Arrow key codes
var UP = 38;
var DOWN = 40;
var RIGHT = 39;
var LEFT = 37;
//Directions
var moveUp = false;
var moveDown = false;
var moveRight = false;
var moveLeft = false;
//Add keyboard listeners
window.addEventListener("keydown", function(event)
{
switch(event.keyCode)
{
case UP:
moveUp = true;
break;
case DOWN:
moveDown = true;
break;
case LEFT:
moveLeft = true;
break;
case RIGHT:
moveRight = true;
break;
}
}, false);
window.addEventListener("keyup", function(event)
{
switch(event.keyCode)
{
case UP:
moveUp = false;
break;
case DOWN:
moveDown = false;
break;
case LEFT:
moveLeft = false;
break;
case RIGHT:
moveRight = false;
break;
}
}, false);
function loadHandler()
{
update();
}
function update()
{
//The animation loop
requestAnimationFrame(update, canvas);
//Up
if(moveUp && !moveDown)
{
cat.vy = -5;
}
//Down
if(moveDown && !moveUp)
{
cat.vy = 5;
}
//Left
if(moveLeft && !moveRight)
{
cat.vx = -5;
}
//Right
if(moveRight && !moveLeft)
{
cat.vx = 5;
}
//Set the cat's velocity to zero if none of the keys are being pressed
if(!moveUp && !moveDown)
{
cat.vy = 0;
}
if(!moveLeft && !moveRight)
{
cat.vx = 0;
}
//Move the cat
cat.x += cat.vx;
cat.y += cat.vy;
//Check for a collision between the cat and the monster
//and change the monster's score when they collide
if(hitTestRectangle(cat, monster) && score < 5)
{
if(!collisionHasOccured)
{
score++;
collisionHasOccured = true;
}
}
else
{
collisionHasOccured = false;
}
if(score === 5)
{
message = " - Game Over!";
}
//Render the sprites
render();
}
function hitTestRectangle(r1, r2)
{
//A variable to determine whether there's a collision
var hit = false;
//Calculate the distance vector
var vx = r1.centerX() - r2.centerX();
var vy = r1.centerY() - r2.centerY();
//Figure out the combined half-widths and half-heights
var combinedHalfWidths = r1.halfWidth() + r2.halfWidth();
var combinedHalfHeights = r1.halfHeight() + r2.halfHeight();
//Check for a collision on the x axis
if(Math.abs(vx) < combinedHalfWidths)
{
//A collision might be occuring.
//Check for a collision on the y axis
if(Math.abs(vy) < combinedHalfHeights)
{
//There's definitely a collision happening
hit = true;
}
else
{
//There's no collision on the y axis
hit = false;
}
}
else
{
//There's no collision on the x axis
hit = false;
}
return hit;
}
function render(event)
{
drawingSurface.clearRect(0, 0, canvas.width, canvas.height);
if(sprites.length !== 0)
{
for(var i = 0; i < sprites.length; i++)
{
var sprite = sprites[i];
drawingSurface.drawImage
(
image,
sprite.sourceX, sprite.sourceY,
sprite.sourceWidth, sprite.sourceHeight,
Math.floor(sprite.x), Math.floor(sprite.y),
sprite.width, sprite.height
);
}
}
drawingSurface.fillText(score + message, monster.x, monster.y - 40);
}
</script>
You just need to add an if statement to your event listeners. ( IF score == 5 ) then don't do anything. You can place the code right above the switch statements.
EDIT
#JasonEnts:
window.addEventListener("keydown", function(event)
{ if (score < 5) {
switch(event.keyCode)
{
case UP:
moveUp = true;
break;
case DOWN:
moveDown = true;
break;
case LEFT:
moveLeft = true;
break;
case RIGHT:
moveRight = true;
break;
}
}
}, false);

How can I make box transition only for horizontal and vertical?

I'm trying to make a box moving by horizontal and vertical on the arrows press. But when I pres for example up arrow and right arrow it goes by diagonal.
Here is my codepen
.box {
background-color: gray;
height: 100px;
width: 100px;
transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
console.log(box.style.marginLeft, box.style.marginTop)
switch(keycode) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
});
Try the following:
const box = document.getElementsByClassName('box')[0];
let moving = false;
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
console.log(box.style.marginLeft, box.style.marginTop)
if (!moving && [37, 38, 39, 40].includes(keycode)){
switch(keycode) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
moving = true;
window.setTimeout(() => moving = false, 400); // Not 500, because visually it is very slow towards the end anyway.
}
});
Either you could implement a Promise solution in here but I don't think it's worth justifying. Basically what we can do is to store all the keys pressed in an array and make sure the javascript only goes through the array of pressed keys once every x milliseconds.
const box = document.getElementsByClassName('box')[0];
let pressedKeys = [];
let timeoutHandler = -1;
document.addEventListener('keydown', function({keyCode, which}) {
// As soon as the user presses a key we will clear the time out
clearTimeout(timeoutHandler);
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px';
pressedKeys.push(keycode);
// register the timeout to a variable in order for this function
// only run once every x second. This implementation is also
// known as 'debounce function to poor people'
timeoutHandler = setTimeout(() => {
pressedKeys.forEach((key, index) => {
// The animation time for each key pressed will be incremental
// which means the second key pressed will have an animation delay
// higher than the first one
const timeoutSeconds = index === 0 ? 1 : index + (index * 100);
setTimeout(() => {
switch(key) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
}, timeoutSeconds)
});
pressedKeys = [];
}, 100)
});
One possible solution: you could keep track of which moves have been requested and wait to perform the move until the previous move has finished. Example:
const box = document.getElementsByClassName('box')[0];
const startValue = '0px';
const shiftValue = '400px';
function moveDown() {
// The move* functions only perform the move if is valid - i.e.,
// if it would actually cause a visible change.
if (box.style.marginTop !== shiftValue) {
box.style.marginTop = shiftValue;
return true;
}
// The move* functions return true iff the move was made.
return false;
}
function moveRight() {
if (box.style.marginLeft !== shiftValue) {
box.style.marginLeft = shiftValue;
return true;
}
return false;
}
function moveUp() {
if (box.style.marginTop !== startValue) {
box.style.marginTop = startValue;
return true;
}
return false;
}
function moveLeft() {
if (box.style.marginLeft !== startValue) {
box.style.marginLeft = startValue;
return true;
}
return false;
}
const moves = [];
let timeOfLastMoveInMilliseconds = null;
const animationDurationInSeconds = 0.5; // should match css transition duration
const animationDurationInMilliseconds = animationDurationInSeconds * 1000;
function onFrame() {
if (!timeOfLastMoveInMilliseconds) {
timeOfLastMoveInMilliseconds = performance.now();
}
const timeSinceLastMove = performance.now() - timeOfLastMoveInMilliseconds;
if (moves.length > 0 && timeSinceLastMove >= animationDurationInMilliseconds) {
const wasMoved = moves.pop()();
if (wasMoved) {
timeOfLastMoveInMilliseconds = performance.now();
}
}
window.requestAnimationFrame(onFrame);
}
window.requestAnimationFrame(onFrame);
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which;
switch(keycode) {
case(40):
moves.unshift(moveDown);
break;
case(39):
moves.unshift(moveRight);
break;
case(38):
moves.unshift(moveUp);
break;
case(37):
moves.unshift(moveLeft);
break;
}
});
Note that the code above keeps track of every move the user makes, so, e.g., if you press down, up, down, up, down quickly, that sequence will play back. Depending on your application, you might want to add restrictions so that, e.g., only horizontal+diagonal moves are allowed and/or only moves coming from keypresses that happen within a short timeframe.
So, I decided to set 500 milliseconds breaks between every press on the key with animation and if it's faster without animation, but without any additional asynchronous code. Thanks for the help.
.box {
background-color: gray;
height: 100px;
width: 100px;
}
.animation {
transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];
let prevTime = 0;
document.addEventListener('keydown', function({keyCode, which}) {
const keycode = keyCode ? keyCode : which,
startValue = '0px',
shiftValue = '400px',
currentTime = Date.now();
let diff = 0;
diff = currentTime - prevTime;
if (diff > 500) {
box.classList.add('animation');
} else {
box.classList.remove('animation');
}
switch(keycode) {
case(40):
box.style.marginTop = shiftValue;
break;
case(39):
box.style.marginLeft = shiftValue;
break;
case(38):
box.style.marginTop = startValue;
break;
case(37):
box.style.marginLeft = startValue;
break;
}
prevTime = currentTime;
});

Clear interval not working on javascript timer

Here is my code
document.addEventListener("keydown", move);
function move(e) {
switch (e.keyCode) {
case 37:
x = x - speed;
break;
case 38:
// up key pressed
y = y - speed
break;
case 39:
x = x + speed
break;
case 40:
y = y + speed
break;
case 32:
if (iTouched == true) {
startCounter();
}
break;
}
sendData();
}
document.addEventListener("keyup", getStuff);
function getStuff(e) {
switch (e.keyCode) {
case 32:
if (iTouched == true) {
shoot();
}
break;
}
}
function startCounter() {
function count() {
time += 1
console.log(time)
}
interval = setInterval(count, 100)
}
function shoot() {
clearInterval(interval)
}
The startCounter() function is triggered by a keydown event listener and the shoot() function is triggered by a keyup event listener. For some reason the setInterval will not stop when I lift the key up. The shoot() function works with other commands like an alert() just not the clearInterval(). Am I doing something wrong? Thanks!
Keydown fires multiple times as you hold down the key.
var bod = document.body;
bod.addEventListener("keydown", () => console.log('keydown', new Date()))
bod.addEventListener("keyup", () => console.log('keyup', new Date()))
So you create more than one interval so you overwrite the last one. So you need to clear the interval before you create a new one
if (interval) clearInterval(interval)
interval = setInterval(count, 100)
or do not create one if it exists
if (!interval) {
interval = setInterval(count, 100)
}
and when you clear it
function shoot() {
clearInterval(interval)
interval = null
}

Jquery: count using setInterval

Im trying to create two counter when I press downKey I want to counter1 start counting and when I press keyLeft I want to stop the first counter and start counter2 .... I know that I need to use clearInterval() function but I dont know where I need to use it, here is a JSFiddle
to see what I mean
html:
<div id="left"></div>
<div id="down"></div>
js:
$('body').keydown(function (e) {
switch (e.which) {
case 39:
clearInterval(down_move);
var i=0;
var right_move = setInterval(function(){
$('#left').html(i);
i++
}, 1000)
break;
case 40:
clearInterval(right_move);
var j = 0;
var down_move = setInterval(function(){
$('#down').html(j)
j++;
}, 1000);
break;
default:
}
e.preventDefault();
});
You need to declare down_move and right_move outside of keydown:
var right_move, down_move;
$('body').keydown(function (e) {
switch (e.which) {
case 39:
clearInterval(down_move);
var i=0;
right_move = setInterval(function(){
$('#left').html(i);
i++
}, 1000)
break;
case 40:
clearInterval(right_move);
var j = 0;
down_move = setInterval(function(){
$('#down').html(j)
j++;
}, 1000);
break;
default:
}
e.preventDefault();
});
it seems like a scope issue, here is how I would make it:
updated fiddle
var Interval = function(intervalFunc, selector){
var interval;
this.start = function(){
interval = setInterval(intervalFunc, 1000);
},
this.stop = function(){
clearInterval(interval);
}
}
var i = 0;
var rightBtnInterval = new Interval(function downInterval(){
$('#right').html(i)
i++;
});
var j = 0;
var downBtnInterval = new Interval(function downInterval(){
$('#down').html(j)
j++;
});
$('body').keydown(function (e) {
switch (e.which) {
case 39:
rightBtnInterval.stop();
downBtnInterval.start();
break;
case 40:
downBtnInterval.stop();
rightBtnInterval.start();
break;
default:
}
e.preventDefault();
});
You have to store outside of function the interval to stop.
Warning the ascii code of left is 37.
Here is a JSFiddle to see my change:
var storeInterval = null;
$('body').keydown(function (e) {
switch (e.which) {
case 37:
clearInterval(storeInterval);
var i=0;
storeInterval = setInterval(function(){
$('#left').html(i);
i++
}, 1000)
break;
case 40:
clearInterval(storeInterval);
var j = 0;
storeInterval = setInterval(function(){
$('#down').html(j)
j++;
}, 1000);
break;
default:
}
e.preventDefault();
});
<div id="left"></div>
<div id="down"></div>

Categories