p5.js で p5.tween を使った複数のボールがバウンドするアニメーションを作る

以前、Tweenアニメーションをいくつか試作した際に、複数のライブラリを試してみました。
例えば、その 1つは以下の「anime.js」であったり、他には、今回の記事で扱う「p5.tween」やその他にも 2つか　3つのライブラリがありました。

●p5.js と anime.js を組み合わせた Tweenアニメーション - Qiita
　https://qiita.com/youtoy/items/361282f1113d88ff5f05

その中で、「p5.tween」については記事を書いていなかったので、今回、記事を書いてみました。
公式ページは以下になります。

●Milchreis/p5.tween: Tween library for P5.js
　https://github.com/Milchreis/p5.tween

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/217f23bf-3219-e331-af35-178f99750421.png)

## 動作している様子
今回実装したものが動作している様子を最初に示します。

4つのボールがバウンドする、というものです。

https://x.com/youtoy/status/1808165075410473134

この時の、円の色・初期位置の高さ・大きさは、ランダムに決めています。
そのため処理を再実行した際に、それらが変化しているのが分かるかと思います。

## 元にした公式サンプル
まず、今回の実装の元にした公式サンプルを紹介します。

上で掲載していた p5.tween のリポジトリのページ上部には、1つのボールがバウンドするアニメーションが掲載されています。

その実装は、以下の公式サンプル 6つの中に含まれています。

●p5.js Web Editor | p5.tween
　https://editor.p5js.org/Milchreis/collections/oHxcCR17k

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/fc168b18-8289-897d-bf0d-cb0796fc5816.png)


具体的には、以下の「bounce」です。

●p5.js Web Editor | bounce
　https://editor.p5js.org/Milchreis/sketches/Ypr3RYWfL

実装は以下の通りで、わりとシンプルなつくりになっていると思います。
（addMotions() がいくつか連なるところは、長くなってしまってますが）

```javascript
const myShape = {
  x: 200,
  y: 100,
  w: 50,
  h: 50
}

function setup() {
  createCanvas(400, 400);
  rectMode(CENTER)

  p5.tween.manager.addTween(myShape, 'tween1')
    .addMotions([
      { key: 'y', target: height },
      { key: 'w', target: 30 },
      { key: 'h', target: 80 },
    ], 600, 'easeInQuad')
    .addMotions([
        { key: 'w', target: 100 },
        { key: 'h', target: 10 },
      ], 120)
    .addMotions([
        { key: 'w', target: 10 },
        { key: 'h', target: 100 },
      ], 100)
    .addMotions([
        { key: 'w', target: 50 },
        { key: 'h', target: 50 },
        { key: 'y', target: 100 }
     ], 500, 'easeOutQuad')
    .startLoop()
}

function draw() {
  background(220);
  noStroke()
  fill(255, 0, 0)
  ellipse(myShape.x, myShape.y, myShape.w, myShape.h)
}

function mousePressed() {
  let tween = p5.tween.manager.getTween('tween1')

  if(tween.isPaused)  tween.resume()
  else                tween.pause()
}
```

myShape で、円の位置・大きさの初期値を決め、それを時間変化させる設定を `p5.tween.manager.addTween(myShape, 'tween1')` の後につなげている形です。

途中、「easeInQuad」「easeOutQuad」といったイージングを適用した部分もあります。
これにより、緩急のついた動きになっていると思います。

## 上記のサンプルに手を加えてみる
上記のサンプルに手を加えてみます。

実装内容は、以下の通りです。

```javascript
let myShapeList = [];
const ballNum = 6;

function setup() {
  createCanvas(550, 400);
  colorMode(HSB, 360, 100, 100, 100);

  initializeShapes();
  setupAnimations();
}

function initializeShapes() {
  for (let i = 1; i <= ballNum; i++) {
    const x = width * (i / (ballNum + 1));
    const y = height * random(0.2, 0.5);
    const wh = height * random(0.05, 0.15);

    myShapeList.push({
      x: x,
      y: y,
      w: wh,
      h: wh,
      initialX: x,
      initialY: y,
      initialW: wh,
      initialH: wh,
      colorH: random(360),
    });
  }
}

function setupAnimations() {
  for (const shape of myShapeList) {
    p5.tween.manager
      .addTween(shape, "tween1")
      .addMotions(
        [
          { key: "y", target: height },
          { key: "w", target: shape.initialW * 0.6 },
          { key: "h", target: shape.initialH * 1.6 },
        ],
        600,
        "easeInQuad"
      )
      .addMotions(
        [
          { key: "w", target: shape.initialW * 2 },
          { key: "h", target: shape.initialH * 0.2 },
        ],
        120
      )
      .addMotions(
        [
          { key: "w", target: shape.initialW * 0.2 },
          { key: "h", target: shape.initialH * 2 },
        ],
        100
      )
      .addMotions(
        [
          { key: "w", target: shape.initialW },
          { key: "h", target: shape.initialH },
          { key: "y", target: shape.initialY },
        ],
        500,
        "easeOutQuad"
      )
      .startLoop();
  }
}

function draw() {
  background(10);
  noStroke();

  for (const s of myShapeList) {
    fill(s.colorH, 60, 90);
    ellipse(s.x, s.y, s.w, s.h);
  }
}
```

変更を加えた箇所は、円を複数にする部分と、それらの複数の円の初期パラメータをランダムにばらけさせる処理を入れているところです。

この実装をした結果、冒頭のアニメーションができあがりました。

## 余談：　自分が気になる公式サンプル
上で、公式サンプルが複数あるということを書いていました。

その中で、バウンドするボール以外に、自分が個人的に気になるもののリンクを紹介しておきます。

### 時計
1つは、数字がアニメーションして変わる時計です。

●p5.js Web Editor | Clock
　https://editor.p5js.org/Milchreis/sketches/euDDMbdjP

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/501777a6-b8ba-a57e-9ecb-a9a7377e69db.png)

画像だと分からないですが、数字が切り替わるときにアニメーションが適用されています。

### マウスを追いかける残像付で動く円
次は、マウスを追いかける残像付で動く円のアニメーションです。

●p5.js Web Editor | Mouse follow
　https://editor.p5js.org/Milchreis/sketches/PIyxxZupt

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/76b68b1a-8a40-8273-0352-a04ec97fd7fb.png)

画面の中で、マウスカーソルを適用に動かしているだけで、ちょっと楽しくなる感じのものです。