「イージング関数チートシートの関数」「p5.js の lerp()、frameCount」を組み合わせたイージングの繰り返しの実装【完走賞ゲット-18】

:::note info
※ [Qiita の完走賞をゲットするための条件は「単一／複数のカレンダーに投稿した記事が合計25」です](https://twitter.com/Qiita/status/1593441648796524545)
:::

この記事は、「[完走賞ゲットのため小ネタ 25記事を投稿しようとチャレンジ v2 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/youtoy)」の 18日目の記事です。

## 今回の内容
今回の内容は、[イージング関数チートシート](https://easings.net/ja)の関数と、p5.js の lerp()・frameCount を組み合わせて、以下の動画のようなイージングを実装するというものです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/JvDdPotgsDU?si=-kdeWdArL98Pnsq4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## 実装した内容
### プログラムの内容
今回は、まずは実装したプログラムの紹介から始めてみます。

上で掲載した動画について、以下のようなお試し用の実装をしました。

```javascript
function setup() {
  createCanvas(600, 400);

  fill(100, 150, 200);
}

function draw() {
  background(20);

  const t = (frameCount % 120) / 120;

  x1 = lerp(20, width - 20, easing(t, 1));
  x2 = lerp(20, width - 20, easing(t, 2));

  circle(x1, height * 0.3, 60);
  circle(x2, height * 0.7, 60);
}

function easing(t, num) {
  // https://easings.net/ja#easeOutQuart
  if (num === 1) return 1 - pow(1 - t, 4);

  // https://easings.net/ja#easeInOutQuint
  if (num === 2)
    return t < 0.5 ? 16 * t * t * t * t * t : 1 - pow(-2 * t + 2, 5) / 2;
}
```

実装のポイントの部分は、主に以下の　2点です。

1. 「easing()」という関数で、イージング処理用の関数を実装（イージング関数チートシートの内容を、少しだけ変えたもの）
1. p5.js で標準で使える「lerp()」(https://p5js.org/reference/#/p5/lerp)を使って、上記のイージング処理用の関数を使った座標計算を行う

ざっくり書くと以上なのですが、それぞれ補足をしていきます。

### 実装に関する補足1
先に、「easing()」という関数についての補足を書きます。

この中では、以下の 3行目と 7行目のそれぞれでイージング用の計算を行っています。
引数の t は、0〜1 の値が入力され、それを 2つ実装したどちらかの関数で計算した値にして返します。

```javascript
function easing(t, num) {
  // https://easings.net/ja#easeOutQuart
  if (num === 1) return 1 - pow(1 - t, 4);

  // https://easings.net/ja#easeInOutQuint
  if (num === 2)
    return t < 0.5 ? 16 * t * t * t * t * t : 1 - pow(-2 * t + 2, 5) / 2;
}
```

2つの関数について、以下でさらに説明していきます。

#### 「easeOutQuart」
1つ目の `1 - pow(1 - t, 4)` という処理のほうの話です。

これは、イージング関数チートシートのページでいうと、以下になります。

●イージング関数チートシート 「easeOutQuart」
　https://easings.net/ja#easeOutQuart

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/f64051d1-52c0-93ac-7e6e-0b73d29650d4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/65dac5f1-56d4-7995-6d38-1b1770f72219.png)

このページを見ると `1 - Math.pow(1 - x, 4)` という処理で書かれています。
処理はそのままという感じで、違いは Math.pow() を p5.js で使える [pow()](https://p5js.org/reference/#/p5/pow) にしたのと、変数名を変えたくらいです。

#### 「easeInOutQuint」
次に `t < 0.5 ? 16 * t * t * t * t * t : 1 - pow(-2 * t + 2, 5) / 2` と書いていた処理についてです。

これは、イージング関数チートシートのページでいうと、以下になります。

●イージング関数チートシート 「easeInOutQuint」
　https://easings.net/ja#easeInOutQuint

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ced5df90-4fac-cd9c-b57e-d498253c72d2.png)

![2023-12-15_21-53-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/05a64d3f-861b-9f0c-a1bd-2c06135ad99a.png)

ここで行った対応は、先ほどと同様です。

### 実装に関する補足2
次に、lerp() を使った部分の補足です。

具体的には、以下となります。

```javascript
  const t = (frameCount % 120) / 120;

  x1 = lerp(20, width - 20, easing(t, 1));
```

まず、t を求める部分は p5.js で取得できる frameCount の数値から求めています。その値を、剰余演算を使って特定範囲内でのみ動くようにし、さらに 0〜1 の値になるようにしています。
それを lerp() の第三引数で使うのですが、上で書いたイージング処理用の関数を介して渡しています。これで、0〜1 を線形に動くのではなく、イージングが適用された変化をするようになります。

あとは、lerp() の第一引数と第二引数で、円の移動をする範囲の最小値・最大値を指定しています。これと、第三引数で求まる 0〜1 の値を組み合わせることで、イージングがかかった場合の x座標の値を算出することができます。

## おわりに
今回扱ったイージングは、過去に例えば以下のライブラリを用いて扱ったことがあるものでした。

- [GSAP](https://gsap.com/)
- [anime.js](https://animejs.com/)
- [p5.func](https://idmnyu.github.io/p5.js-func/)
- [Tween24.js](https://ics.media/entry/210409/)

それを今回は、イージング関数チートシートの関数と p5.js の lerp() とを組み合わせて実装してみた形です。上記のライブラリを使ったほうが実装は容易になりますが、イージングの関数の中に手を入れたいときなどは、今回の方法を使うと良いかもしれません。

### 過去に書いたイージング関連の記事
以下は、イージング処理を含む内容を、過去に記事で書いたものです。

- [p5.js と Tween24.js を組み合わせたアニメーション・イージングのお試し](https://qiita.com/youtoy/items/ad2ade71d73fa2298723)
- [p5.js と Tween24.js を組み合わせたお試し：イージングのブレンド](https://qiita.com/youtoy/items/24dae2f6c946b41d9c82)
- [CSS-Tricks の記事で見かけた「マウスカーソルの軌跡上でパーティクルを発生させる処理」を p5.js で置きかえる（一部は簡略化）](https://qiita.com/youtoy/items/190e6049172a22d9e592)
- [p5.js Web Editor で p5.func を使ったイージング](https://qiita.com/youtoy/items/a748e1b19cd2837e447c)
- [p5.js と anime.js を組み合わせた Tweenアニメーション](https://qiita.com/youtoy/items/361282f1113d88ff5f05)
- [p5.js と anime.js を組み合わせた Tweenアニメーション【その2：キーフレームを使ってみる】](https://qiita.com/youtoy/items/61c6d57dff822c055b46)