I am building a simple game where the ground moves when a user pressed a space bar once. My problem is that the ground does not move if I do not press a space bar.
I want the ground to move from the moment the user pressed the space bar once, and then continue to move forever.
My code:
class Ground {
constructor(position) {
this.position = position;
}
move() {
this.position.x--;
}
}
const ground = new Ground({
position: {
y: 135
}
})
window.addEventListener("keydown", (event) => {
switch(event.key) {
case " ": {
ground.move();
break;
};
};
});
As Ray raid in comment, you need to call constantly your move
function, using for example requestAnimationFrame
, or here (because I am too lazy to use requestAnimationFrame
, that requires some unrelated teaching about it), setInterval
let x=0; // global variable for bar position (use better style. Here I want a quick&dirty demo)
function move(){
x+=5;
bar.style.left=`${x}px`; // Note I rely on the fact that bar is the name of dom element of ID bar. You shouldn't do that
}
document.addEventListener('keydown', function(evt){
if(evt.key==' ') setInterval(move, 100);
});
#bar {
position: absolute;
bottom:10px;
left: 0px;
width: 60px;
height: 20px;
border: solid 1px black;
background-color:red;
display:inline-block;
}
<div id=bar></div>
As you can see in comments, I took some shortcuts. Using setInterval
rather than requestAnimationFrame
(which is not that longer to use. But it use recursion and continuations, which another concept I am not sure your are familiar with). And I use a global variable, for x
, but of course, you can adapt that with your class.
requestAnimationFrame
(But that requires recursion, continuation, plus the .bind
because of using method as callbacks, and more intialisation, because I don't know when — at which time — the user with press the space bar.
That being said, you can see that it is smoother. And with setInterval
, if you try to make it smoother by reducing the time interval, you take the risk to have no animation at all, since if interval is too small, the subsequent calls are made in the same JS "atomic run", and therefore are all played before the DOM are updated.
So, it you want to do a video game, it is worth learning to use requestAnimationFrame
. That being said, that was not your question, and my first, dirtier but simpler, code was enough to answer your question)
class Ground {
constructor(position, speed) {
this.position = position;
this.speed = speed;
this.t=0;
this.bar=document.getElementById('bar');
this.bar.style.left=`${this.position.x}px`;
this.bar.style.top=`${this.position.y}px`;
}
move(t) {
if(this.t){
this.position.x += (t-this.t)*this.speed/1000;
}
this.t=t;
this.bar.style.left=`${this.position.x}px`;
requestAnimationFrame(this.move.bind(this));
}
}
const ground = new Ground({
x:500, y:135
}, -50)
window.addEventListener("keydown", (event) => {
switch(event.key) {
case " ": {
requestAnimationFrame(ground.move.bind(ground));
break;
};
};
});
#bar {
position: absolute;
bottom:10px;
left: 0px;
width: 60px;
height: 20px;
border: solid 1px black;
background-color:red;
display:inline-block;
}
<div id=bar></div>