わざと引っかかりのあるアニメーションを実装する

一般的にはアニメーションは高パフォーマンスであることが良しとされる。が、あえてFPSを下げたアニメーションにしたいことがあった。レトロゲームのような世界観を表現したいというやつだった。

tween.jsは、ユーザーがアニメーションの更新タイミングを制御できるAPIになっている。こういう感じ。

var coords = { x: 0, y: 0 };
var tween = new TWEEN.Tween(coords)
    .to({ x: 100, y: 100 }, 1000)
    .onUpdate(function() {
        console.log(this.x, this.y);
    })
    .start();

requestAnimationFrame(animate);

function animate(time) {
    requestAnimationFrame(animate);
    TWEEN.update(time);
}

つまりTWEEN.updateを呼ぶ頻度を制御できればいい。それを踏まえてこういう風になる。

const createFpsControlledTicker = (handleTick, fps = 60) => {
  let startTime = null
  let lastFrame = -1
  const secondsPerFrame = 1000 / fps
  let requestId = null
  let isRunning = false

  const tick = () => {
    requestId = requestAnimationFrame(tick)

    if (startTime == null) startTime = performance.now()

    const currentTime = performance.now()
    const elapsedTime = currentTime - startTime
    const currentFrame = Math.floor(elapsedTime / secondsPerFrame)

    if (lastFrame !== currentFrame) {
      handleTick(currentFrame)
      lastFrame = currentFrame
    }
  }

  const start = () => {
    if (isRunning) return
    requestId = requestAnimationFrame(tick)
    isRunning = true
  }

  const stop = () => {
    if (!isRunning) return
    cancelAnimationFrame(requestId)
    isRunning = false
  }

  return {
    start,
    stop,
  }
}

createFpsControlledTicker(() => {
  TWEEN.update()
}, 15).start()

以上のようなコードで15fpsのアニメーションを実装できた。