Chapter 08

イージング

miku
miku
2021.11.25に更新

イージング

3つのボールがあり、上のボールは常に等速で動いている。真ん中と下のボールは、上のボールをもとに緩急をつけたものだ。

このように、オブジェクトに緩急を付ける機能のことをイージングと呼ぶ。

イージングの条件

イージングにおける緩急の付け方だが、移動時間を0~100%とする場合、0%と100%のときは必ず等速の位置と同じでなければならない。いくら緩急を付けたいからといっても、移動元(0%)と移動先(100%)の位置を変えるような機能は使えないからだ。

全体的な緩急の付け方は用途によって変わるが、たとえば、最初はゆっくりだが、途中で加速し、最後に減速するような、グラフにするとS字型になるような緩急がある。このような形はシグモイドやsmoothstepという関数で作れるが、これらについては後の章で扱う。

イージングの作り方

等速の運動をもとに緩急を付けるのだから、まずは等速の運動の実装をしよう。これは以前の章で扱った線形補間で実装できる。

コード全体を見る
let t, x1, y1, x2, y2;

function setup() {
  createCanvas(windowWidth, windowHeight);

  x1 = 0;
  y1 = height;
  x2 = width;
  y2 = 0;

  t = 0;
}

function draw() {
  const x = lerp(x1, x2, t);
  const y = lerp(y1, y2, t);
  t += 0.005;
  if (t > 1) {
    t = 0;
  }

  clear();
  circle(x, y, 20);
}
x = lerp(x1, x2, t);
y = lerp(y1, y2, t);

始点 (x1, y1), 終点 (x2, y2) の線形補間を計算し、たとえば t = 0.5 のときは50%の位置を返す。

緩急を付けるということは t0.5 のときに、0.40.7 になっていたりするわけだから、t を渡して緩急をつけた新しい t を返す関数を作ればいい。

function linear(t) {
  return t;
}

x = lerp(x1, x2, lenear(t));
y = lerp(y1, y2, lenear(t));

lineart を受け取って t をそのまま返す関数だ。つまり何もしないのでそのまま等速の運動のままになる。

function tt(t) {
  return t * t;
}

x = lerp(x1, x2, lenear(t));
y = lerp(y1, y2, lenear(t));

ttt を受け取って t * t を返す関数だ。

移動時間の0%と100%のときは等速の場合と同じ位置にいなければならないので、t = 0t = 1 のときにイージング関数に t を渡すと、そのまま t が返るような形でなければならない。tt の場合、tt(0) = 0, tt(1) = 1 と条件を満たしているので、これは立派なイージング関数になる。

tt のイージング関数を適用した動きは下記の通り。

コード全体を見る
let t, x1, y1, x2, y2;

function setup() {
  createCanvas(windowWidth, windowHeight);

  x1 = 0;
  y1 = height;
  x2 = width;
  y2 = 0;

  t = 0;
}

function tt(t) {
  return t * t;
}

function draw() {
  const x = lerp(x1, x2, tt(t));
  const y = lerp(y1, y2, tt(t));
  t += 0.005;
  if (t > 1) {
    t = 0;
  }

  clear();
  circle(x, y, 20);
}

これと同じように上の条件を満たすような新しい t を返せば、自作のイージング関数を作ることができる。

イージングの種類

https://easings.net/ja

イージングを作る関数にはテンプレートとして名前が付けられて共有されているので、自分で作るよりかはまずはこちらの外部サイトを見たほうがいいだろう。

CSSでは transition のようなプロパティにイージングの指定が可能で、Chromeの開発者ツールで、イージングの曲線を直接触ることもできる。

イージング例

let prevR, nextR, d, t;

function setup() {
  createCanvas(windowWidth, windowHeight);

  d = 200;
  reset();
}

function reset() {
  prevR = d;
  nextR = random(20, 400);
  t = 0;
}

function draw() {
  t += 0.01;

  // イージング後の余韻を持たせるため、すぐにはリセットしない
  if (t >= 1.4) {
    reset();
    return;
  }

  // t = 1.0 でイージング終了なので、t > 1.0 の場合は画面を更新しない
  if (t > 1.0) {
    return;
  }

  clear();
  d = lerp(prevR, nextR, easeInOutBack(t));
  circle(width / 2, height / 2, d);
}

function easeInOutBack(t) {
  const c1 = 1.70158;
  const c2 = c1 * 1.525;

  return t < 0.5 ? (pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2 : (pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
}

円の大きさを変化させる動きにイージングを適用した作例。円の大きさを prevR から nextR に変化させる際、上記のサイトに掲載されている easeInOutBack を利用している。