Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

javascript - 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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.

As @Azamantes stated to solve this you will want to make a boolean that is set to true on keydown and false on keyup. Then you will be using a main event loop with either a setTimeout/setInterval and/or 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:


Note: For implementing requestAnimationFrame see @MarkE's comment on this question.

Also requestAnimationFrame will refresh as much as it can by default. In other words you need to add more logic if you need to control the FPS, which can be common in HTML5 games. For using requestAnimationFrame with controlled FPS see this answer.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...