Make "ball" follow mouse on canvas
Asked Answered
V

3

5

I'm trying to make a ball follow the mouse around inside a canvas area. But the ball only get the first position when mouse enter the canvas area (so on the edges).

What is wrong since the ball doesn't follow mouse when moving around inside canvas?

window.onload = startup;

var ballX = 400;
var ballY = 400;
var mouseX = 0;
var mouseY = 0;

function startup() {
  document.getElementById("drawingArea").onmouseover = mouseMove;
  setInterval("moveBall()", 100);
}

function mouseMove(evt) {
  mouseX = evt.clientX;
  mouseY = evt.clientY;
}

function moveBall() {
  if (ballX > mouseX) {
    ballX -= 5;
  } else {
    ballX += 5;
  }
  if (ballY > mouseY) {
    ballY -= 5;
  } else {
    ballY += 5;
  }

  var canvas = document.getElementById("drawingArea");
  var ctx = canvas.getContext("2d");

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.beginPath();
  ctx.arc(ballX, ballY, 40, 0, 2* Math.PI);
  ctx.fillStyle = "green";
  ctx.fill();
  ctx.lineWidth = 5;
  ctx.strokeStyle = "red";
  ctx.stroke();
}
#drawingArea {
  border-style: solid;
  position: absolute;
  top: 0;
  left: 0;
}
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Move Ball</title>
  </head>

  <body>
    <canvas id="drawingArea" width="800" height="800" />
  </body>
</html>
Victual answered 19/9, 2017 at 5:17 Comment(0)
H
1

On this line:

document.getElementById("drawingArea").onmouseover = mouseMove;

...you need to change onmouseover to onmousemove. Further reading: onmousemove

Full example with the change:

			window.onload = startup;
			var ballX = 400;
			var ballY = 400;
			var mouseX = 0;
			var mouseY = 0;
			
			function startup() {
				document.getElementById("drawingArea").onmousemove = mouseMove;
				setInterval("moveBall()",100);
			
			}
			
			function mouseMove(evt) {
				mouseX = evt.clientX;
				mouseY = evt.clientY;
			}
			
			function moveBall() {
				if (ballX > mouseX) {
					ballX -= 5;
				} else {
					ballX += 5;
				}
				if (ballY > mouseY) {
					ballY -= 5;
				} else {
					ballY += 5;
				}
				
				var canvas = document.getElementById("drawingArea");
				var ctx = canvas.getContext("2d");
				
				ctx.clearRect(0, 0, canvas.width, canvas.height);
				
				ctx.beginPath();
				ctx.arc(ballX, ballY, 40, 0, 2* Math.PI);
				ctx.fillStyle = "green";
				ctx.fill();
				ctx.lineWidth = 5;
				ctx.strokeStyle = "red";
				ctx.stroke();
			}
#drawingArea 
{
				border-style: solid;
				position: absolute;
				top: 0;
				left: 0;
}
<!doctype html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Move Ball</title>
	</head>

	<body>
		<canvas id="drawingArea" width="800" height="800" />
	</body>
</html>
Homer answered 19/9, 2017 at 5:21 Comment(0)
T
8

The mouseover event listener doesn't work like a "while mouse is over, execute this code". It only fires when this state get's true, in other terms, when you move the mouse from the outside, onto the node.

The proper event you'd want to use is mousemove; store the new position of the mouse, as soon as it changed.

Besides that I've made a few other changes to your code so the animation is smoother:

This approach of ballX += mouseX>ballX? 5: -5 is prone to a stutter, because it completely ignores the area, when mouse and ball are less than 5px apart on any axis.

Also din't use setInterval() for your game loop. And more broad, don't use setTimeout() or setInterval() with a string argument (at all). It's a bad practice. Un-flexible, and forces you into using global variables.

Better use requestAnimationFrame() so you stay in sync with the browsers rendering.

window.onload = startup;

var ballX = 400;
var ballY = 400;
var mouseX = 0;
var mouseY = 0;

function startup() {
  //`mousemove`, not `mouseover`
  document.getElementById("drawingArea").onmousemove = mouseMove;
  
  loop();
}

//use `requestAnimationFrame` for the game loop
//so you stay sync with the browsers rendering
//makes it a smoother animation
function loop(){
  moveBall();
  requestAnimationFrame(loop);
}

function mouseMove(evt) {
  mouseX = evt.clientX;
  mouseY = evt.clientY;
}

function moveBall() {
  //get the distance between the mouse and the ball on both axes
  //walk only the an eight of the distance to create a smooth fadeout
  var dx = (mouseX - ballX) * .125;
  var dy = (mouseY - ballY) * .125;
  //calculate the distance this would move ...
  var distance = Math.sqrt(dx*dx + dy*dy);
  //... and cap it at 5px
  if(distance > 5){
    dx *= 5/distance;
    dy *= 5/distance;
  }
  
  //now move
  ballX += dx;
  ballY += dy;
  
  var canvas = document.getElementById("drawingArea");
  var ctx = canvas.getContext("2d");

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.beginPath();
  ctx.arc(ballX, ballY, 40, 0, 2 * Math.PI);
  ctx.fillStyle = "green";
  ctx.fill();
  ctx.lineWidth = 5;
  ctx.strokeStyle = "red";
  ctx.stroke();
}
#drawingArea {
  border-style: solid;
  position: absolute;
  top: 0;
  left: 0;
}
<canvas id="drawingArea" width="800" height="800" />

Feel free to play a bit around with the movement code. Check out, what happens when you change the * .125 in calculating the distance, when removing the condition, ...

Trudietrudnak answered 19/9, 2017 at 6:9 Comment(0)
B
2

You'll also need to add the onmousemove event handler.

Bondy answered 19/9, 2017 at 5:18 Comment(0)
H
1

On this line:

document.getElementById("drawingArea").onmouseover = mouseMove;

...you need to change onmouseover to onmousemove. Further reading: onmousemove

Full example with the change:

			window.onload = startup;
			var ballX = 400;
			var ballY = 400;
			var mouseX = 0;
			var mouseY = 0;
			
			function startup() {
				document.getElementById("drawingArea").onmousemove = mouseMove;
				setInterval("moveBall()",100);
			
			}
			
			function mouseMove(evt) {
				mouseX = evt.clientX;
				mouseY = evt.clientY;
			}
			
			function moveBall() {
				if (ballX > mouseX) {
					ballX -= 5;
				} else {
					ballX += 5;
				}
				if (ballY > mouseY) {
					ballY -= 5;
				} else {
					ballY += 5;
				}
				
				var canvas = document.getElementById("drawingArea");
				var ctx = canvas.getContext("2d");
				
				ctx.clearRect(0, 0, canvas.width, canvas.height);
				
				ctx.beginPath();
				ctx.arc(ballX, ballY, 40, 0, 2* Math.PI);
				ctx.fillStyle = "green";
				ctx.fill();
				ctx.lineWidth = 5;
				ctx.strokeStyle = "red";
				ctx.stroke();
			}
#drawingArea 
{
				border-style: solid;
				position: absolute;
				top: 0;
				left: 0;
}
<!doctype html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Move Ball</title>
	</head>

	<body>
		<canvas id="drawingArea" width="800" height="800" />
	</body>
</html>
Homer answered 19/9, 2017 at 5:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.