为什么球只滚到右边?

问题描述 投票:0回答:1

我一直在尝试创建弹跳球动画。

我遇到了一个特殊的问题。我已经设法让球弹起但是,由于某种原因,它似乎只会向右滚动,直到它与视口的右侧碰撞

(要移动球,请用鼠标按钮单击它,然后向任意方向快速拖动它,然后释放鼠标按钮)

我想了解可能导致这种意外行为的原因以及如何纠正它。

这是我的 JavaScript 文件的片段:

var ball = document.querySelector('.ball'),
    isDragging = false,
    isAnimating = false,
    isAnimationAllowed = true, // New flag to control animation while dragging
    offsetX,
    offsetY,
    velocityX = 0,
    velocityY = 0,
    friction = 0.95,
    gravity = 0.5,
    floorLevel = 500,
    animationFrame;

ball.addEventListener('mousedown', startDragging);
ball.addEventListener('touchstart', startDragging);

function startDragging(event) {
    isDragging = true;
    isAnimating = false; // Reset isAnimating to false
    isAnimationAllowed = false; // Disable animation while dragging
    offsetX = event.clientX - ball.getBoundingClientRect().left;
    offsetY = event.clientY - ball.getBoundingClientRect().top;
  
    document.addEventListener('mousemove', drag);
    document.addEventListener('mouseup', stopDragging);
    
    document.addEventListener('touchmove', drag);
    document.addEventListener('touchend', stopDragging);
  }

function drag(event) {
  if (!isDragging) return;

  event.preventDefault();

  var newX, newY;

  if (event.type === 'mousemove') {
    newX = event.clientX - offsetX;
    newY = event.clientY - offsetY;
  } else if (event.type === 'touchmove') {
    newX = event.touches[0].clientX - offsetX;
    newY = event.touches[0].clientY - offsetY;
  }

  ball.style.left = newX + "px";
  ball.style.top = newY + "px";

  velocityX = newX - ball.offsetLeft;
  velocityY = newY - ball.offsetTop;
}

function stopDragging() {
  isDragging = false;
  isAnimationAllowed = true; // Enable animation after dragging stops

  document.removeEventListener('mousemove', drag);
  document.removeEventListener('mouseup', stopDragging);

  document.removeEventListener('touchmove', drag);
  document.removeEventListener('touchend', stopDragging);

  if (!isAnimating) {
    animate();
  }
}

function animate() {
  if (!isAnimationAllowed) return; // Check if animation is allowed
  
  isAnimating = true;

  animationFrame = requestAnimationFrame(animate);

  velocityX *= friction;
  velocityY += gravity;

  var newX = ball.offsetLeft + velocityX;
  var newY = ball.offsetTop + velocityY;

  if (newY >= floorLevel - ball.offsetHeight) {
    newY = floorLevel - ball.offsetHeight;
    velocityY *= -0.6; // Bounce effect
  }

  if (newX < 0) {
    newX = 0;
    velocityX *= -0.6; // Bounce effect for the left boundary
  } else if (newX > window.innerWidth - ball.offsetWidth) {
    newX = window.innerWidth - ball.offsetWidth;
    velocityX *= -0.6; // Bounce effect for the right boundary
  }

  ball.style.left = newX + "px";
  ball.style.top = newY + "px";

  if (Math.abs(velocityX) < 0.1 && Math.abs(velocityY) < 0.1 && newY >= floorLevel - ball.offsetHeight) {
    cancelAnimationFrame(animationFrame);
    isAnimating = false;
  }
}
div.ball {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: radial-gradient(circle at 65% 15%, white 1px, aqua 3%, darkblue 60%, aqua 100%);
  position: absolute;
}
<div class="ball"></div>

javascript html css drag mousemove
1个回答
1
投票

如果您在第一次调用

velocityX
时检查
velocityY
stopDragging()
的值,您会发现它们始终是
0
。这是因为
drag(event)
中的以下两行无法正常工作:

  velocityX = newX - ball.offsetLeft;
  velocityY = newY - ball.offsetTop;

看来

newX
ball.offsetLeft
具有相同的值,所以你的逻辑有问题。

所以,我将这两行替换为(除以 10 只是为了降低速度):

  velocityX = newX / 10;
  velocityY = newY / 10;

我们现在可以看到您所描述的效果,即在您释放球后,无论您当时是向左还是向右拖动,球总是向右滚动。

现在,如果您将

velocityX
定为负数,例如:

  velocityX = - newX / 10;

然后你会发现球总是滚到左边。那么问题来了。

因此,请研究我如何通过引入变量

drag(event)
oldX
来更改
oldY
,以跟踪球位置的先前坐标。

您可能还想在 MDN 上阅读有关

movementX
MouseEvent
属性,因为这可能对您也感兴趣。

我将

floorlevel
设置为 400,以便在 Snack 代码片段中大部分时间都可以看到球。

var ball = document.querySelector('.ball'),
  isDragging = false,
  isAnimating = false,
  isAnimationAllowed = true, // New flag to control animation while dragging
  offsetX,
  offsetY,
  velocityX = 0,
  velocityY = 0,
  friction = 0.95,
  gravity = 0.5,
  floorLevel = 400,
  animationFrame;

let newX, newY;

ball.addEventListener('mousedown', startDragging);
ball.addEventListener('touchstart', startDragging);

function startDragging(event) {
  isDragging = true;
  isAnimating = false; // Reset isAnimating to false
  isAnimationAllowed = false; // Disable animation while dragging
  offsetX = event.clientX - ball.getBoundingClientRect().left;
  offsetY = event.clientY - ball.getBoundingClientRect().top;

  document.addEventListener('mousemove', drag);
  document.addEventListener('mouseup', stopDragging);

  document.addEventListener('touchmove', drag);
  document.addEventListener('touchend', stopDragging);
}

function drag(event) {
  if (!isDragging) return;

  event.preventDefault();

  let oldX = newX;
  let oldY = newY;

  if (event.type === 'mousemove') {
    newX = event.clientX - offsetX;
    newY = event.clientY - offsetY;
  } else if (event.type === 'touchmove') {
    newX = event.touches[0].clientX - offsetX;
    newY = event.touches[0].clientY - offsetY;
  }

  let directionX = Math.sign(newX - oldX);
  let directionY = Math.sign(newY - oldY);

  ball.style.left = newX + "px";
  ball.style.top = newY + "px";

  velocityX = directionX * newX / 10;
  velocityY = directionY * newY / 10;
}

function stopDragging() {
  isDragging = false;
  isAnimationAllowed = true; // Enable animation after dragging stops

  document.removeEventListener('mousemove', drag);
  document.removeEventListener('mouseup', stopDragging);

  document.removeEventListener('touchmove', drag);
  document.removeEventListener('touchend', stopDragging);

  if (!isAnimating) {
    animate();
  }
}

function animate() {
  if (!isAnimationAllowed) return; // Check if animation is allowed

  isAnimating = true;

  animationFrame = requestAnimationFrame(animate);

  velocityX *= friction;
  velocityY += gravity;

  var newX = ball.offsetLeft + velocityX;
  var newY = ball.offsetTop + velocityY;

  if (newY >= floorLevel - ball.offsetHeight) {
    newY = floorLevel - ball.offsetHeight;
    velocityY *= -0.6; // Bounce effect
  }

  if (newX < 0) {
    newX = 0;
    velocityX *= -0.6; // Bounce effect for the left boundary
  } else if (newX > window.innerWidth - ball.offsetWidth) {
    newX = window.innerWidth - ball.offsetWidth;
    velocityX *= -0.6; // Bounce effect for the right boundary
  }

  ball.style.left = newX + "px";
  ball.style.top = newY + "px";

  if (Math.abs(velocityX) < 0.1 && Math.abs(velocityY) < 0.1 && newY >= floorLevel - ball.offsetHeight) {
    cancelAnimationFrame(animationFrame);
    isAnimating = false;
  }
}
div.ball {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: radial-gradient(circle at 65% 15%, white 1px, aqua 3%, darkblue 60%, aqua 100%);
  position: absolute;
}
<div class="ball"></div>

© www.soinside.com 2019 - 2024. All rights reserved.