Заставьте мяч следовать за мышью на холсте

Я пытаюсь заставить мяч следовать за мышью внутри области холста. Но мяч получает первую позицию только тогда, когда мышь входит в область холста (то есть по краям).

Что не так, поскольку мяч не следует за мышью при перемещении внутри холста?

			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>


person rehnoj    schedule 19.09.2017    source источник


Ответы (3)


В этой строке:

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

... вам нужно изменить onmouseover на onmousemove. Дополнительная литература: onmousemove

Полный пример с изменением:

			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>

person Clonkex    schedule 19.09.2017

Прослушиватель событий mouseover не работает как "пока наведена мышь, выполнить этот код". Он срабатывает только тогда, когда это состояние становится истинным, другими словами, когда вы перемещаете мышь извне на узел.

Правильным событием, которое вы хотели бы использовать, является mousemove; сохранить новое положение мыши, как только оно изменилось.

Кроме того, я сделал несколько других изменений в вашем коде, чтобы анимация стала более плавной:

Этот подход ballX += mouseX>ballX? 5: -5 склонен к заиканию, потому что он полностью игнорирует область, когда мышь и мяч находятся на расстоянии менее 5 пикселей по любой оси.

Также не используйте setInterval() для своего игрового цикла. И в более широком смысле не используйте setTimeout() или setInterval() со строковым аргументом (вообще). Это плохая практика. Негибкий и вынуждает вас использовать глобальные переменные.

Лучше используйте requestAnimationFrame(), чтобы синхронизироваться с рендерингом браузера.

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

Не стесняйтесь немного поиграть с кодом движения. Посмотрите, что происходит, когда вы меняете * .125 при расчете расстояния, при удалении условия...

person Thomas    schedule 19.09.2017

Вам также потребуется добавить обработчик событий onmousemove.

person AKX    schedule 19.09.2017