Search code examples
javascriptgame-physics

Why does my game character keep accelerating when I use the keydown event?


I am trying to make a simple game. The green block is my game character. I used a the keydown event to make my character able to move right and left. When I hold down the right or left arrow key, the character keeps on accelerating. If you start by tapping the right or left arrow key, you will see that the space interval between where the character was and where it is increases as you click more. How can I make my character move at a constant speed with constant space intervals.

//variables
var canvas = document.getElementById("canvas");
var draw = canvas.getContext("2d");
var characterx = 20;
var charactery = window.innerHeight - 60;
var dx = 0.01;
var dy = 0.01;

//canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;



//main game function
function run() {

	//loops the function
	requestAnimationFrame(run);

	//clears the screen
	draw.clearRect(0, 0, canvas.width, canvas.height)

	//draws the ground
	draw.beginPath();
	draw.fillStyle = "#823819";
	draw.fillRect(0, canvas.height - 20, canvas.width, 20);
	draw.fill();
	draw.closePath();

	//draws the main character
	draw.beginPath();
	draw.fillStyle = "#128522";
	draw.fillRect(characterx, charactery, 40, 40);
	draw.fill();
	draw.closePath();

	//key evevnts
	window.addEventListener("keydown",function(event) {
		if(event.keyCode == 39) {
			characterx  += dx;
		}
	});

	window.addEventListener("keydown",function(event) {
		if(event.keyCode == 37) {
			characterx  -= dx;
		}		
	});

};
run();
<!DOCTYPE html>
<html>
<head>
	<title>Test</title>
	<style type="text/css">
		body {
			margin: 0;
			overflow: hidden;
		}
		canvas {
			margin: 0;
			overflow: hidden;
		}
	</style>
</head>
<body>
	<canvas id="canvas"></canvas>
	<script type="text/javascript" src="script.js"></script>
</body>
</html>


Solution

  • Your event listeners should be added outside of your game loop.

    Currently you are adding an extra listener for each keypress on every frame, meaning that on the first frame you will move dx * 1 for a keypress, but on frame 100 you will move dx * 100 for a single keypress.

    This is also why your dx value had to be so low - I've increased it in the sample below, but you can adjust it as needed.

    //variables
    var canvas = document.getElementById("canvas");
    var draw = canvas.getContext("2d");
    var characterx = 20;
    var charactery = window.innerHeight - 60;
    var dx = 3.0;
    var dy = 3.0;
    
    //canvas size
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    //key evevnts
    window.addEventListener("keydown",function(event) {
    	if(event.keyCode == 39) {
    		characterx  += dx;
    	}
    });
    window.addEventListener("keydown",function(event) {
    	if(event.keyCode == 37) {
    		characterx  -= dx;
    	}		
    });
    
    //main game function
    function run() {
    
    	//loops the function
    	requestAnimationFrame(run);
    
    	//clears the screen
    	draw.clearRect(0, 0, canvas.width, canvas.height)
    
    	//draws the ground
    	draw.beginPath();
    	draw.fillStyle = "#823819";
    	draw.fillRect(0, canvas.height - 20, canvas.width, 20);
    	draw.fill();
    	draw.closePath();
    
    	//draws the main character
    	draw.beginPath();
    	draw.fillStyle = "#128522";
    	draw.fillRect(characterx, charactery, 40, 40);
    	draw.fill();
    	draw.closePath();
    
    };
    run();
    <!DOCTYPE html>
    <html>
    <head>
    	<title>Test</title>
    	<style type="text/css">
    		body {
    			margin: 0;
    			overflow: hidden;
    		}
    		canvas {
    			margin: 0;
    			overflow: hidden;
    		}
    	</style>
    </head>
    <body>
    	<canvas id="canvas"></canvas>
    	<script type="text/javascript" src="script.js"></script>
    </body>
    </html>