简体   繁体   中英

Javascript: Limit how quickly a keydown event listener can call a function when held down

I'm working on a JavaScript based game and I am currently working on game character movement and animation. This is controlled when the player presses the controls (WASD) during the keydown event. The problem I have is that the handler is called too quickly when these keys are pressed and held down, which makes my game character/sprite look like he's having a seizure (because it is cycling through the sprite images too quickly).

How can I limit the speed that calls to the character movement/animation behaviour are made? My code currently looks like this:

 let canvas = document.getElementById('myCanvas'); ctx = canvas.getContext('2d'); let xPos = 10 let yPos = 10 document.addEventListener('keydown', movement) function movement(e){ //Player Controls // horizontal and vertical movement if (e.keyCode === 87 ){ ctx.clearRect(0,0, canvas.width, canvas.height); y=y-3; sY = 97 runningMan(); } if(e.keyCode === 83){ ctx.clearRect(0,0, canvas.width, canvas.height); y=y+3; sY = 0 runningMan(); } if(e.keyCode === 65){ ctx.clearRect(0,0, canvas.width, canvas.height); x=x-3; sY = 32 runningMan(); } if(e.keyCode === 68){ ctx.clearRect(0,0, canvas.width, canvas.height); x=x+3; sY = 64 runningMan(); } // keeping the player inside the canvas xPos = Math.min(Math.max(x, 0+5), canvas.width-10); yPos = Math.min(Math.max(y, 0+5), canvas.height-10); } //img,SX,SY,SW,SH,DX,DY,DW,DH) let img = new Image(); img.src = 'runningGood.png' let cycle = 0 let sY; let sW = 30 let sH = 32 let x = 0 let y = 0 let increase = 0 // setInterval(runningMan, 200); function runningMan(){ ctx.clearRect(0,0,sW+increase,sH+increase); ctx.drawImage(img,cycle*sW,sY,sW,sH,x,y,70,70) cycle = (cycle + 1) % 3; } 
 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <script src='project.js' defer></script> <title>1045 Project</title> </head> <body> <canvas id='myCanvas' width='750' height ='750' style='border: 2px solid black'></canvas> </body> </html> 

One solution that integrates with your current code, and avoids the need for a third party library would be to add the following:

 let canvas = document.getElementById('myCanvas'); ctx = canvas.getContext('2d'); let xPos = 10 let yPos = 10 /* Add: track state of current throttle timer */ let throttle; /* Add: When keyup happens, just reset the throttle timer */ document.addEventListener('keyup', () => { if (throttle) { clearTimeout(throttle); throttle = null; } }) document.addEventListener('keydown', movement) function movement(e) { /* Add: only allow normal keypress processing if no throttle timer is currently active */ if (!throttle) { //Player Controls // horizontal and vertical movement if (e.keyCode === 87) { ctx.clearRect(0, 0, canvas.width, canvas.height); y = y - 3; sY = 97 runningMan(); } if (e.keyCode === 83) { ctx.clearRect(0, 0, canvas.width, canvas.height); y = y + 3; sY = 0 runningMan(); } if (e.keyCode === 65) { ctx.clearRect(0, 0, canvas.width, canvas.height); x = x - 3; sY = 32 runningMan(); } if (e.keyCode === 68) { ctx.clearRect(0, 0, canvas.width, canvas.height); x = x + 3; sY = 64 runningMan(); } // keeping the player inside the canvas xPos = Math.min(Math.max(x, 0 + 5), canvas.width - 10); yPos = Math.min(Math.max(y, 0 + 5), canvas.height - 10); /* Add: Start a "throttle" timer that prevents next keyboard processing until timer completed */ throttle = setTimeout(() => { throttle = null; /* Your throttle interval - reduce/increase this number to suit you needs */ }, 1000) } } //img,SX,SY,SW,SH,DX,DY,DW,DH) let img = new Image(); img.src = 'https://via.placeholder.com/160' let cycle = 0 let sY; let sW = 30 let sH = 32 let x = 0 let y = 0 let increase = 0 // setInterval(runningMan, 200); function runningMan() { ctx.clearRect(0, 0, sW + increase, sH + increase); ctx.drawImage(img, cycle * sW, sY, sW, sH, x, y, 70, 70) cycle = (cycle + 1) % 3; } 
 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <script src='project.js' defer></script> <title>1045 Project</title> </head> <body> <canvas id='myCanvas' width='750' height='750' style='border: 2px solid black'></canvas> </body> </html> 

The general idea here is to start a throttle timer after regular keydown processing occurs. The throttle timer basically blocks/prevents the same keydown processing (ie game character movement) from occurring immediatly in the next iteration of your app/event loop (which is the cause for the erratic motion of the game character).

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM