简体   繁体   English

如何使用箭头键在画布中平滑移动对象

[英]How to use arrow keys to move object smoothly in canvas

I'm working on making a simple space game where a ship moves left and right to dodge asteroids. 我正在做一个简单的太空游戏,其中一艘船左右移动以躲避小行星。

I learned to move my ship left and right from this video . 我从这段视频中学到了左右移动船舶的能力。

But the movement is pretty blocky. 但是运动非常块状。 How do I move the ship smoothly? 我如何平稳地移动船?

Here is all my code: 这是我所有的代码:

 // JavaScript Document ////// Variables ////// var canvas = {width:300, height:300 }; var score = 0; var player = { x:canvas.width/2, y:canvas.height-100, speed: 20 }; ////// Arrow keys ////// function move(e) { if(e.keyCode == 37) { player.x -= player.speed; } if(e.keyCode == 39) { player.x += player.speed; } update(); } document.onkeydown = move; ////// other functions ////// //function to clear canvas function clearCanvas() { ctx.clearRect(0,0,canvas.width,canvas.height); } // Draw Player ship. function ship(x,y) { var x = player.x; var y = player.y; ctx.fillStyle = "#FFFFFF"; ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(x+15,y+50); ctx.lineTo(x-15,y+50); ctx.fill(); } // update setInterval (update, 50); function update() { clearCanvas(); ship(); } 
 <!doctype html> <html> <head> <meta charset="UTF-8"> <title>My Game</title> <script src="game-functions.js"></script> </head> <body> <canvas id="ctx" width="300" height="300" style="border: thin solid black; background-color: black;"></canvas> <br> <script> ////// Canvas setup ////// var ctx = document.getElementById("ctx").getContext("2d"); </script> </body> </html> 

This is because keydown triggers events similarity to how you keyboard will type on Notepad, as it it will trigger once have a slight delay and they trigger many more timers. 这是因为keydown触发的事件与键盘在记事本上的键入方式类似,因为一旦稍有延迟,它将触发一次,并且触发更多的计时器。

As @Azamantes stated to solve this you will want to make a boolean that is set to true on keydown and false on keyup . 正如@Azamantes所说的那样,您需要创建一个布尔值,该值在keydown设置为true ,在keyup设置为false Then you will be using a main event loop with either a setTimeout/setInterval and/or requestAnimationFrame . 然后,您将使用带有setTimeout/setInterval和/或requestAnimationFrame的主事件循环。 In the example below I've just used setInterval for the main loop for simplicity since you already have it, we can then move move() into that main loop: 在下面的示例中,为简单起见,我仅将setInterval用于主循环,因为您已经拥有它,然后可以将move()移入该主循环:


Note: For implementing requestAnimationFrame see @MarkE's comment on this question. 注意:有关实现requestAnimationFrame请参见@MarkE在此问题上的评论。

Also requestAnimationFrame will refresh as much as it can by default. 默认情况下, requestAnimationFrame还将刷新尽可能多的内容。 In other words you need to add more logic if you need to control the FPS, which can be common in HTML5 games. 换句话说,如果需要控制FPS,则需要添加更多逻辑,这在HTML5游戏中很常见。 For using requestAnimationFrame with controlled FPS see this answer . 有关在受控FPS上使用requestAnimationFrame ,请参见此答案

 // JavaScript Document ////// Variables ////// var canvas = {width:300, height:300 }; var score = 0; var player = { x:canvas.width/2, y:canvas.height-100, speed: 3 }; var LEFT = false; var RIGHT = false; ////// Arrow keys ////// function move() { if(LEFT) { player.x -= player.speed; } if(RIGHT) { player.x += player.speed; } } document.onkeydown = function(e) { if(e.keyCode == 37) LEFT = true; if(e.keyCode == 39) RIGHT = true; } document.onkeyup = function(e) { if(e.keyCode == 37) LEFT = false; if(e.keyCode == 39) RIGHT = false; } ////// other functions ////// //function to clear canvas function clearCanvas() { ctx.clearRect(0,0,canvas.width,canvas.height); } // Draw Player ship. function ship(x,y) { var x = player.x; var y = player.y; ctx.fillStyle = "#FFFFFF"; ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(x+15,y+50); ctx.lineTo(x-15,y+50); ctx.fill(); } // update setInterval (update, 10); function update() { clearCanvas(); ship(); move(); } 
 <!doctype html> <html> <head> <meta charset="UTF-8"> <title>My Game</title> <script src="game-functions.js"></script> </head> <body> <canvas id="ctx" width="300" height="300" style="border: thin solid black; background-color: black;"></canvas> <br> <script> ////// Canvas setup ////// var ctx = document.getElementById("ctx").getContext("2d"); </script> </body> </html> 

  1. Use requestAnimationFrame 使用requestAnimationFrame
  2. Don't put update (your rendering) inside keyUp keyDown event handlers 不要将update (渲染)放在keyUp keyDown事件处理程序中
  3. Make a boolean variable (one for each directio) and set it to true on keuDown and to false on keyUp and inside your rendering functions add a simple if check 创建一个布尔变量(每个directio一个),并在keuDown上将其设置为true ,在keyUp上将其设置为false ,并在呈现函数内部添加一个简单的if检查

TL;DR TL; DR

Make your life simpler. 让您的生活更简单。

You might want to use event.key instead, which returns key name ('a', 'Esc', 'Space' etc), makes it more readable if you don't put comments next to the keyCodes. 您可能想改用event.key ,它返回键名('a','Esc','Space'等),如果您不在keyCodes旁添加注释,则使其更具可读性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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