为什么我添加了计数器变量和间隔之后我的动画不工作了?

Why is my animation not working now that I've added counter variable and Intervals?

我在 class 中有一个动画功能。

动画是一棵树 'shuddering' 沿着 x 轴快速来回移动,就像被斧头砍中一样。

我希望发生的事情:

当我单击树时,动画应该开始、停止、开始、停止、开始然后永久停止。在我看来,动画 运行 和停止的比例大约是 2s 运行,8s 停止。动画所停留的边界非常小(见最后的 if 语句),速度为 4。因此树在两者之间弹跳得非常快,给人一种 'shudder' 的印象。

该函数在函数 setup() 中调用的 class 中。 tree.shudder() 但是在循环函数 draw() 中被调用。

这是一个 iteration/cycle 工作动画的代码:

shudder() {
  let d = dist(mouseX, mouseY, this.x, this.y);
  let speed = 0;
  if (d < 50) {
    speed = 4;
    if (this.x < this.l || this.x > this.r) {
      speed = speed * -1;
    }
  } else {
  speed = 0;
  }
  this.x = this.x + speed;
}

动画一直有效,直到我尝试自动启动和停止抖动。 当我添加计数器变量和 setInterval/clearInterval 函数时,抖动不再起作用。

我正在使用 p5 库。

谁能看出为什么我的动画在这里停止工作?

function setup() {
  createCanvas(windowWidth, windowHeight);
  trees = new Trees(200, 200);
}

function draw() {
  trees.shudder();
}

shudder() {
  let d = dist(mouseX, mouseY, this.x, this.y);
  let counter = 0;
  let speed = 0;
  if (d < 50) {
    let interval = setInterval(() => {
      speed = 4;
      counter++;
      console.log(counter);
      if (this.x < this.l || this.x > this.r) {
        speed = speed * -1;
      }
      if (counter === 3) {
        clearInterval(interval)
      }
    }, 1000)
  } else {
    speed = 0;
  }
  this.x = this.x + speed;
}

在 console.log 中,如果我单击树并让 60 帧过去,就会发生这种情况:

60trees.js:31 1
trees.js:31 2
trees.js:31 1
trees.js:31 2
2trees.js:31 1
2trees.js:31 2

并无限运行...

但是,如果我在树上单击并在 60 帧通过之前单击关闭,我会得到我想要的:

26trees.js:31 1
26trees.js:31 2
26trees.js:31 3

任何帮助将不胜感激!

一些问题:

  • setIntervald < 50时执行,也就是说会连续执行几次,而不考虑已经执行过。所以你会得到一堆大约同时到期的计时器。

  • 您在 setInterval 回调中修改的 counterspeed 引用调用 setInterval 时的变量,并且对 shudder 的后续调用没有影响,其中这些变量是新变量实例。

  • 你每秒只检查一次,看this.x是否还在范围内。这最好在动画期间的每一帧完成。

  • 在为每一帧调用的函数中使用 setInterval 看起来很糟糕。它可以工作,但你需要非常小心地做事。

我会选择一种模式,您可以计算动画的结束时间,然后只读出当前时间,看看您是否已经到了。还要确保保持有关速度等的状态(在 this 中)...

像这样:

shudder() {
    if (!this.steps) { // not yet (ever) animated?
        this.speed = 0;
        let d = dist(mouseX, mouseY, this.x, this.y);
        if (d < 50) {
            // Adapt these numbers to set the time at which animation should pause/restart:
            this.steps = [0, 500, 1000, 1500, 2000, 2500].map(i => Date.now() + i);
        }
    } else if (this.steps[0] < Date.now()) { // duration completed?
        this.speed = 4 - Math.abs(this.speed); // Toggle between animate and pause
        this.steps.shift(); // Remove a step, since that duration has completed
    }
    if (this.x < this.l || this.x > this.r) this.speed = -this.speed;
    this.x += this.speed;
}