いつの間にかGitHub Copilotの問題が直っていました。GitHubさんに感謝。
今回はGitHub Copilot(以下、単にAI)を使って、図形やアニメーションなどのグラフィックスをp5.jsで描画するプログラムを生成させてみます。
私にプログラミングさせるより、はじめから絵を生成するAIに任せればいいのでは…
検証手順
AIに型情報を与えた方がコードを上手く生成できると考え、p5.jsをTypeScriptで書くための環境を構築しました。
次の手順でAIにグラフィックスを描いてもらいます。
- 描画したいグラフィックスのヒントとして、コメントと関数名および引数だけを書いてAIに与えます。
- GitHub Copilotにコードの続きを補完させます。Ctrl+Enterキーで複数のコード候補を提示してくれるので、期待する絵を描いてくれそうなコードを選びます。
- プログラムを実行して描画結果を確認します。
はたしてAIはどれだけ意図を汲んでくれるのでしょうか。
初級編:プリミティブ
まずはシンプルな図形を書かせてみます。ちなみにp5.jsをインスタンスモードで利用しているので、各機能を呼び出すp
オブジェクトがソースコード中に表れます。
六角形
太字がAIの生成したコードです。
// draw hexagon with vertex
const drawHexagon = (p: p5, x: number, y: number, r: number) => {
let angle = p.PI / 3;
p.beginShape();
for (let i = 0; i < 6; i++) {
p.vertex(x + r * p.cos(angle * i), y + r * p.sin(angle * i));
}
p.endShape(p.CLOSE);
}
星形
// draw star with vertex
const drawStar = (p: p5, x: number, y: number, r1: number, r2: number) => {
let angle = p.PI / 5;
p.beginShape();
for (let i = 0; i < 10; i++) {
p.vertex(x + r1 * p.cos(angle * i), y + r1 * p.sin(angle * i));
p.vertex(x + r2 * p.cos(angle * (i + 0.5)), y + r2 * p.sin(angle * (i + 0.5)));
}
p.endShape(p.CLOSE);
}
難なく書けていますね。星といえば5つの凸をイメージしていましたが、これはこれで。
中級編
アートっぽいものにチャレンジします。
泡のアニメーション
// draw hovering bubbles animation
const sketch = (p: p5) => {
const bubbles: Bubble[] = [];
p.setup = () => {
p.createCanvas(p.windowWidth, p.windowHeight);
p.background(0);
p.colorMode(p.HSB, 360, 100, 100, 100);
p.noStroke();
p.ellipseMode(p.CENTER);
p.frameRate(60);
for (let i = 0; i < 100; i++) {
bubbles.push(new Bubble());
}
};
p.draw = () => {
p.background(0);
for (let i = 0; i < bubbles.length; i++) {
bubbles[i].update();
bubbles[i].show();
}
};
class Bubble {
x: number;
y: number;
vx: number;
vy: number;
r: number;
color: p5.Color;
constructor() {
this.x = p.random(p.width);
this.y = p.random(p.height);
this.vx = p.random(-1, 1);
this.vy = p.random(-1, 1);
this.r = p.random(5, 10);
this.color = p.color(p.random(360), 100, 100);
}
update() {
this.x += this.vx;
this.y += this.vy;
if (this.x > p.width || this.x < 0) {
this.vx *= -1;
}
if (this.y > p.height || this.y < 0) {
this.vy *= -1;
}
}
show() {
p.fill(this.color);
p.ellipse(this.x, this.y, this.r * 2, this.r * 2);
}
}
}
実際はアニメーションしています。あまりhovering bubblesという感じでもありませんが、許容範囲です。
グリッチエフェクト
const drawGlitchEffect = (p: p5, frameCount: number) => {
p.background(255);
p.noStroke();
p.fill(0);
const gridSize = 40;
const grid = [];
for (let i = 0; i < p.width / gridSize; i++) {
grid[i] = [];
for (let j = 0; j < p.height / gridSize; j++) {
grid[i][j] = p.random(0, 1);
}
}
for (let i = 0; i < p.width / gridSize; i++) {
for (let j = 0; j < p.height / gridSize; j++) {
const x = i * gridSize;
const y = j * gridSize;
const size = gridSize * 0.5;
const offset = gridSize * 0.25;
const angle = p.map(p.sin(frameCount * 0.01), -1, 1, 0, p.TWO_PI);
const s = p.map(grid[i][j], 0, 1, 0, 1) * 0.5;
p.push();
p.translate(x + offset, y + offset);
p.rotate(angle);
p.scale(s);
p.rect(0, 0, size, size);
p.pop();
}
}
}
実際はアニメーションしています。せっかくなのでブラウザ上で見られるようにしました。思っていたグリッチエフェクトとは違いますが、程よい不規則さは見ていて少し面白いです。
まとめ
まずAIがp5.jsというライブラリにしっかり対応したコードを出力して、しかも手直し0でエラーも吐かず動くことに感動しました。単純な図形はいとも簡単に出力する一方で、少し複雑な描画結果を得ようとするとなかなかイメージ通りとはいきませんでした。とはいえ、もう少しコメント等で情報を補足してやれば精度が上がりそうな予感もします。また、思いがけないコードや結果が得られることもあり、インスピレーションを刺激されます。出力されたコードをベースに手を加えていくのも面白いのではないでしょうか。
記事が面白かった方、参考になった方は、是非「イイね」お願いします👍