見出し画像

ChatGPTにp5.jsのメンターをしてもらった

この記事はProcessing Advent Calendar 2023の19日目に寄せた投稿です。

お久しぶりです。Toriiです。前回の投稿から1年空きました。この更新頻度からわかる通り、大抵のことを断続的にしか続けられない性分で、クリエイティブコーディングもその限りではありません。今回の投稿のために約2か月ぶりにp5.jsのエディタ(OpenProcessing)を開きましたが、何から書くべきか見当もつかず。というわけで、話題の対話型AIにメンターを務めてもらいました。

ChatGPTとの対話

エディタに標準で表示されているsetup()とdraw()を目の前にして「ここから何してたっけ?」とぼんやりするくらいのブランクがあります。ChatGPTに自分のスキルや知識に見合った練習メニューを作ってもらい、レビューや添削をしてもらいます。

課題設定

まずは手を動かすことから始めたかったので、写経すべきコードを依頼します。テキトーに自分のレベルを伝えると、適当なテーマを設定してくれました。

ざっくり頼んでもしっかり応えてくれる

この時点のコードは割愛します。比較的粒度の粗いパーティクル表現で、30行程度のものです。

等速度運動する粒たち

ChatGPT自身が生成したパーティクルシステムのコードをもとに、私向けに課題を出してもらいました。

課題1: パーティクルの色とサイズを変更する
パーティクルの色を時間の経過に応じて変化させてみてください。また、サイズもランダムまたは特定のルールに従って変更してみてください。

課題2: パーティクルの動きに変化を加える
現在はランダムな動きですが、マウスの位置に応じてパーティクルが動くように変更してみてください。例えば、マウスに向かって動く、またはマウスから逃げるような動きです。

課題3: パーティクル間の相互作用を追加する
2つのパーティクルが一定の距離に近づいたときに、線でつながるようにしてみてください。これにより、動的なネットワークのような視覚効果を生み出すことができます。

回答と添削

各課題に対して、わかる範囲で書いてみます。わからない箇所は根を詰めて調べたりせず、空白の状態でとりあえず提出してみました。こんなにもラフな態度でプログラミングに向き合うことは、これまでになかった経験ですね。

曖昧なまま実装するなよ

課題2の解説に「マウスの位置に応じて」と記載されているのを無視して書いてみるとやんわりと正されました。すごく丁寧に怒られている気分です。

課題2の実装に関して、マウスの位置に基づいてパーティクルのサイズを調整する方法として、マウスとパーティクルの距離に依存したシンプルな計算を行うのが一般的です。以下にそのための修正例を示します。

訂正してもらったコードはこちら。

class Particles { 
 // ... 
  show(col) { noStroke(); fill(col); 
  let d = dist(mouseX, mouseY, this.position.x, this.position.y); 
  this.blob = map(d, 0, width, 4, 1); // マウスに近いほど大きくなる 
  circle(this.position.x, this.position.y, this.size * this.blob); } 
 // ... 
}

続いて、完全に匙を投げた課題3についての解説です。

課題3: パーティクル間の相互作用の実装について
課題3でのパーティクル間の相互作用は、通常「近接するパーティクルを検出して線でつなぐ」という方法で行います。基本的なアプローチは、全てのパーティクルに対して繰り返し処理を行い、あるパーティクルから特定の距離内にある他のパーティクルを見つけ、それらの間に線を描画することです。以下に基本的な実装例を示します。

うーん、言ってることは分かるけど「コードにしてみて」って言われるとやっぱり書き出しがわからない。というわけで早速解答を見てみます。

function draw() {
 background(250, 250, 240);
 for (let i = 0; i < particles.length; i++) {
  particles[i].update();
  particles[i].show(map(sin(radians(frameCount)), -1, 1, 0, 100));
  connectParticles(i); // パーティクル間を線でつなぐ関数を呼び出す
 }
}

function connectParticles(index) {
 for (let j = 0; j < particles.length; j++) {
  if (index != j) {
   let d = dist(particles[index].position.x, particles[index].position.y, particles[j].position.x, particles[j].position.y);
   if (d < 50) { // 50ピクセル未満の距離にある場合、線でつなぐ
    stroke(0, 50);
    line(particles[index].position.x, particles[index].position.y, particles[j].position.x, particles[j].position.y);
   }
  }
 }
}

実行してみるとそれっぽいものが出来上がっていました。

カーソルを右上にもっていった場合

アレンジしたもの

ノード表現の実装があまり呑み込めていないので、
課題1 :パーティクルの色とサイズを変更する
課題2:パーティクルの動きに変化を加える
を実装した状態から自分なりにアレンジしてみます。今回はlerpColorを使って色が滑らかに変化するようにしました。…いや、そうしたかったのですが、意図した挙動にならなかったのでメンターに聞きました。

私にできることは要件の整理だけ

というわけで無事に制作できました。作品はこちら

パーティクル(円)の色が滑らかに変わる!

おわりに

久々のp5.js練習は無事に形になりました。ChatGPT様様です。一応この後の展開も考えてもらいました。

(前略)
パフォーマンスを向上させるためには、空間分割やクワッドツリーのような高度なデータ構造を使うことも検討できます。
(中略)
空間分割とクワッドツリーは、コンピューターグラフィックス、ゲーム開発、物理シミュレーションなどでよく使用される、空間を効率的に管理するための技術です。

空間分割(Spatial Partitioning)
空間分割は、大きな空間を小さな部分に分割する技術です。これにより、特定のオブジェクトやポイントを効率的に検索、管理できるようになります。例えば、2D空間をいくつかのグリッドに分割し、各グリッドセルに含まれるオブジェクトを管理することで、特定のエリア内のオブジェクトを迅速に見つけることができます。これは、衝突検出、可視性計算、近接クエリなどに有効です。

クワッドツリー(Quadtree)
クワッドツリーは、空間分割の一種で、特に2D空間に適しています。クワッドツリーは、各ノードが最大4つの子ノードを持つ木構造です。これは空間を再帰的に4つの象限に分割し、各象限を子ノードとして管理します。

各ノードは特定の空間領域を表し、その領域内のオブジェクトを格納します。オブジェクトがノードの容量を超えると、そのノードは4つの子ノードに分割され、オブジェクトはこれらの子ノードに再分配されます。このプロセスは、空間が適切に分割されるまで再帰的に行われます。
(後略)

ちょっと何言ってるかわからないです。

わからないですが、せっかく道しるべなので、これもまたカリキュラム化してもらって取り組んでみようと思います。それではまた1年後に


この記事が気に入ったらサポートをしてみませんか?