【问题标题】:Which part of this movement code should I apply delta time?我应该应用这个运动代码的哪一部分?
【发布时间】:2022-01-12 13:21:41
【问题描述】:
 this.up = function () {
  this.velocity += this.lift;
  };
 this.update = function () {
   this.velocity += this.gravity;

   this.velocity *= 0.9;
   this.y += this.velocity;

  }

嗨,所以我在画布绘制循环中有这段代码可以使形状上下移动,这取决于它的帧速率,所以我试图将增量时间应用于这些函数。有人知道我会怎么做吗?

我们将不胜感激

【问题讨论】:

  • 也许您需要检查最短时间已过? if(deltaTime > minTime) { this.up() }?
  • delta 是像素距离的一个因素。例如,60 FPS 应该给出 0.01666 的增量。因此,每秒 50 像素的速度转化为每帧 50 * 0.01666 像素的速度。这很可能意味着您需要执行 this.velocity += this.lift * delta;this.velocity += this.gravity * delta;
  • 所以在更改 y 和 *= 0.9 时我不必应用增量?
  • 不,绝对不是。根据经验,delta 仅适用于添加的值,而不适用于因子。而且this.velocity已经被delta减少了,所以在修改this.y的时候就不需要再实现delta了。
  • 请注意,您也可以将每秒速度用于升力、重力和速度,并且只使用this.y += this.velocity * delta;,即仅在更改位置时使用增量。

标签: javascript canvas


【解决方案1】:

requestAnimationFrame 使用时间戳调用其回调。这使您可以跟踪两帧之间经过的时间:

let t = null;

const frame = dt => {
  // Update and render your canvas
};

const loop = ts => {
  const dt = t === null ? 0 : ts - t;
  t = ts;
  frame(dt / 1000);
  requestAnimationFrame(loop);
};

这个例子调用帧 以秒为单位的经过时间。这意味着您可以在pixels/second 中表达您的速度和加速度。

你会得到:

  • px 中的位置
  • px/s 中的速度
  • px/s/s 中的加速

更新三个变成这样:

px += vx * dt;
vx += ax * dt;

在下面的示例中,我实现了一个快速随机动画。尝试使用数字输入增加实体计数。

对于少数实体,我们能够以 60fps 的速度进行渲染,而使用实际经过的时间并不重要。

但是当你增加实体的数量时,如果我们不考虑经过的时间,你会发现事情开始变得非常缓慢!

const G = 300; // px / s / s

const cvs = document.createElement("canvas");
cvs.width = 300;
cvs.height = 300;
cvs.style.border = "1px solid red";

const ctx = cvs.getContext("2d");

const Ball = (x, y, vx = 0, vy = 0, ax = 0, ay = G, color = "black") => {
  const render = () => {
    ctx.fillStyle = color;
    ctx.beginPath();
    ctx.arc(x, y, 10, 0, 2 * Math.PI);
    ctx.closePath();
    ctx.fill();
  };
  
  const update = (dt) => {
    return Ball(
      x + dt * vx,
      y + dt * vy,
      vx + dt * ax,
      vy + dt * ay,
      ax,
      ay,
      color
    );
  }
  
  return { render, update };
}

const randomBalls = n => Array.from(
  { length: n },
  () => Ball(
    Math.random() * 300,
    Math.random() * 300,
    -100 + Math.random() * 200,
    Math.random() * -200,
    0,
    G,
    `#${[
      (Math.floor(Math.random() * 255)).toString(16),
      (Math.floor(Math.random() * 255)).toString(16),
      (Math.floor(Math.random() * 255)).toString(16)
    ].join("")}`
  )
);

// Game
let balls = randomBalls(100);

let t = null;
let useFrameTime = true;

const frame = dt => {
  if (!useFrameTime) dt = 1 / 60;

  // Update entities
  balls = balls.map(b => b.update(dt));
  
  // Clear window
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  
  // Draw new rects
  balls.forEach(b => b.render());
}

const loop = ts => {
  const dt = t === null ? 0 : ts - t;
  t = ts;
  frame(dt / 1000);
  requestAnimationFrame(loop);
}

document.body.append(cvs);


requestAnimationFrame(loop);

document.querySelector("button").addEventListener("click", () => {
  const n = +document.querySelector("input[type=number]").value;
  balls = randomBalls(n);
});

document.querySelector("input[type=checkbox]").addEventListener("change", (e) => {
  useFrameTime = e.target.checked;
});
body { display: flex; }
<div style="width: 300px"> 
  <p>Increase the count here. Time for all balls to exit the frame should stay roughly the same, but you should see the frame rate drop as you increase the number of entities to render.
  </p>
  <input type="number" value="100">
  <button>Go</button>
  <br>
  <label><input type="checkbox" checked> Use frame time in render loop</label>
</div>

【讨论】:

    猜你喜欢
    • 2012-06-04
    • 2010-10-24
    • 2015-03-01
    • 2014-02-27
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多