p5.jsでつくる閃光

# はじめに
p5.jsというライブラリを利用してchatGPTと共に作成したアートの紹介です。
「なんかいい」をモットーに作っています。

# 作品紹介
<iframe width="560" height="315" src="https://www.youtube.com/embed/POLLbRla_gg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

```math
『閃光』
```

# 構想
光が残像を伴って高速に移動する演出がかっこいいと思って、それを表現したものがつくれないか考えて作り始めました。ゲームの演出とかでも現れるようなかっこいいものをイメージしていました。

# chatGPTと調整
まずは`レーザーポインタみたいに`と光の雰囲気を伝えて、高速に移動する光の球を生成するように指示しました。高速に移動する光の球を生成できるようにすると、次は残像を残すようにしたかったのですが、かなり苦戦しました。結局`消えない`と`徐々に透明にする`という入力を同時にいれることで、徐々に消えるようにはできなかったですが、残像らしきものは表現することができました。
移動の様子は`同心円状`と入力したのですが、何を思ったか中心を起点に動く仕様になりました。それでもどこか神秘的な様子があったのでこれを採用しました。

#作品解説
## 下準備
必要なファイルや実行方法がわからない人は以下を参考にしてください。

https://qiita.com/keigo1110/items/543423379813b49e7415

## コード
コードはchatGPTが生成しています。数字は一部調整しています。
```javascript
// 変数の宣言
let particles = []; // Particleオブジェクトを格納する配列
let textX, textY; // テキストの位置

// 初期化処理
function setup() {
  // Canvasの作成
  createCanvas(2000, 1500, WEBGL);

  // テキストの位置をCanvasの中央に設定
  textX = width / 2;
  textY = height / 2;

  // 5つのParticleオブジェクトを生成して配列に格納
  for (let i = 0; i < 1000; i++) {
    // 半径を50~150の範囲でランダムに決定
    let r = random(50, 400);
    // 色をランダムに決定
    let c = color(random(255), random(255), random(255));
    // Particleオブジェクトを生成して配列に追加
    particles.push(new Particle(r, c));
  }
}

// 描画処理
function draw() {
  // 背景色を黒に設定
  background(0);

  // 3D空間に変換して座標系を変更
  translate(-width / 2, -height / 2);

  // テキストの設定
  textSize(48);
  textAlign(CENTER, CENTER);
  // "Hello, World!"を表示
  text("Hello, World!", textX, textY);

  // 全てのParticleオブジェクトに対して、move, drawTrail, drawを呼び出す
  for (let i = 0; i < particles.length; i++) {
    particles[i].move(); // 位置を更新
    particles[i].drawTrail(); // 軌跡を描画
    particles[i].draw(); // Particleを描画
  }
}


// Particleというクラスを宣言
class Particle {
  // コンストラクター。radius, colorなどの初期値を設定する。
  constructor(radius, color) {
    this.radius = radius; // 粒子の半径
    this.color = color; // 粒子の色
    this.speed = random(0.01, 0.04); // 粒子が移動する速度。random()関数で0.01から0.03の間でランダムな値を生成する
    this.theta = random(TWO_PI); // 粒子が回転する角度。random()関数で0から2πの間でランダムな値を生成する
    this.phi = random(TWO_PI); // 粒子が回転する角度。random()関数で0から2πの間でランダムな値を生成する
    this.trail = []; // 粒子が軌跡を残すための配列
    this.trailLength = 15; // 軌跡の長さ。30個の座標が保存されたら、古い座標を削除する
    this.trailOpacity = 255; // 軌跡の透明度。軌跡を描画するたびに、255/trailLengthだけ減少させる
  }

  // 粒子を動かすための関数
  move() {
    this.theta += this.speed; // 粒子のtheta角度を加算することで、回転させる
    this.phi += this.speed; // 粒子のphi角度を加算することで、回転させる
  }

  // Particleオブジェクトを描画する関数
  draw() {
    push(); // 描画状態を保存
    translate(width / 2, height / 2); // 座標系を中央に移動
    let x = this.radius * cos(this.theta) * sin(this.phi); // x座標の計算
    let y = this.radius * sin(this.theta) * sin(this.phi); // y座標の計算
    let z = this.radius * cos(this.phi); // z座標の計算
    noStroke(); // 線を描かない
    emissiveMaterial(this.color); // 物体の色を設定
    shininess(50); // 物体の質感を設定
    sphere(10, 6, 4); // 球を描画
    pop(); // 描画状態を復元
  }

  drawTrail() {
    // 現在のパーティクル位置をトレイル配列にプッシュ
    this.trail.push({
      x: width / 2 + this.radius * cos(this.theta) * sin(this.phi),
      y: height / 2 + this.radius * sin(this.theta) * sin(this.phi),
      z: this.radius * cos(this.phi),
      opacity: this.trailOpacity,
    });
    if (this.trail.length > this.trailLength) {
      this.trail.shift();
    }
    noFill();
    beginShape();
    stroke(
      red(this.color),
      green(this.color),
      blue(this.color),
      this.trailOpacity
    );
    strokeWeight(2);
    for (let i = 0; i < this.trail.length; i++) {
      vertex(this.trail[i].x, this.trail[i].y, this.trail[i].z);
      this.trail[i].opacity -= 255 / this.trailLength;
    }
    endShape();
    this.trailOpacity -= 255 / this.trailLength;
  }
}
```

## 拡張性
最後に入力した様子を写真で共有できませんが、入力のメモが残っていたのでそれを共有しておきます。
この頃は要件を箇条書きにして伝えることを試していた時期でした。
ただ、後半の項目は反映されにくく「有効です」とおすすめできるほどではありませんでした。
```
アニメーションを作成してください。要件は以下のとおりです。
・レーザーポインタのような3Dの小さい光の玉をランダムな色で5つ生成する
・生成した光の玉の色は変更しないかつ消えることはない
・5つ光の玉が違った半径で同一の中心をもった円運動する
・光の玉の軌道を残像のような感じでぼんやりと色付けする
・光の玉の軌道は徐々に透明になるようにする
・真ん中に文字列を表示する
・プログラムはp5.js
・コメントは必要なし
これでお願いします。
```
【補足】
`消えること無い`と`徐々に透明にする`を入れ込んで今のような`一定期間保持する`に落ち着きました。
コメント必要なしはgpt-3.5（無料版）の場合入れておいたほうがいいです。コメント入れると途中で切れることが多いです。（必要であれば後から部分ごとに聞けばいい）

# おわりに
これは動画より自分のパソコンで実際に実装して見てみることをおすすめします。かなり綺麗です。