はじめに
p5.jsで作成した2つの異なるスケッチを1つのキャンバスに統合したいことはよくあります。
例えば:
- 別々に作った動きのあるアニメーションを組み合わせたい
- 友達と作った作品を1つの画面で表示したい
- 既存の作品に新しい要素を追加したい
しかし、単純に2つのコードを組み合わせようとすると、以下のような問題が発生することがあります:
- 同じ名前の変数がぶつかってしまう
- 描画の順序が思い通りにならない
- コードが読みにくくなる
この記事では、2つのシンプルなスケッチを例に、これらの問題を解決しながら統合する方法を順を追って解説します!
0. 今回統合する2つのスケッチ
すごくシンプルですが、変数や処理が一般的なものを2つ用意しました。
A. 動く円
シンプルに左から右に動く縁です。
let x = 0;
let speed = 2;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
circle(x, height/2, 50);
x += speed;
if (x > width) x = 0;
}
B. 波打つ四角形
四角形が上下に動くものです。
let y = 0;
let angle = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
y = height/2 + sin(angle) * 50;
rect(width/2, y, 40, 40);
angle += 0.05;
}
1. 描画処理を関数にまとめる
まず、それぞれのスケッチのbackground()より下にある描画処理を見つけ、関数にまとめます。
なぜ関数にまとめるの?
- 描画処理を関数にまとめることで、後で2つのスケッチを組み合わせる際に簡単です
- それぞれの動きが独立した関数になるので、管理がしやすくなります
- 描画順序の変更が簡単になります
- A:動く円(変更前)
let x = 0;
let speed = 2;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
circle(x, height/2, 50); // この部分を
x += speed; // 関数にまとめます
if (x > width) x = 0;
}
- A:動く円(変更後)
let x = 0;
let speed = 2;
function setup() {
createCanvas(400, 400);
}
// background()より下の処理を関数にまとめる
function drawMovingCircle() {
circle(x, height/2, 50);
x += speed;
if (x > width) x = 0;
}
function draw() {
background(220);
drawMovingCircle(); // まとめた関数を呼び出す
}
同様にして、Bについてもまとめていきます。
- B:波打つ四角形(変更前)
let y = 0;
let angle = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
y = height/2 + sin(angle) * 50; // この部分を
rect(width/2, y, 40, 40); // 関数にまとめます
angle += 0.05;
}
- B:波打つ四角形(変更後)
let y = 0;
let angle = 0;
function setup() {
createCanvas(400, 400);
}
// background()より下の処理を関数にまとめる
function drawWavingRect() {
y = height/2 + sin(angle) * 50;
rect(width/2, y, 40, 40);
angle += 0.05;
}
function draw() {
background(220);
drawWavingRect(); // まとめた関数を呼び出す
}
2. 変数の重複をチェック
両方のスケッチで使われている変数名をチェックします。
変数の確認方法
// 動く円のスケッチで使用している変数
let x = 0; // 円のx座標
let speed = 2; // 円の移動速度
// 波打つ四角形のスケッチで使用している変数
let x = 100; // ← スケッチAと同じ名前の変数
let y = 0; // 四角形のy座標
let angle = 0; // 波の角度
重複する変数の修正
変数xが両方のスケッチで使われているため、変数名を変更します。
変数名は、その変数が何のために使われているかわかりやすい名前にしましょう。
// 修正後の変数
let circleX = 0; // 円のx座標(xから変更)
let speed = 2; // 円の移動速度(変更なし)
let rectX = 100; // 四角形のx座標(xから変更)
let rectY = 0; // 四角形のy座標(変更なし)
let angle = 0; // 波の角度(変更なし)
変数名を変更する際の注意点
- わかりやすい名前をつける
xA
,xB
のような名前は避ける
circleX
,rectX
のように用途がわかる名前にする - 変数の使用箇所も修正する
// 変数名の変更前(スケッチA)
function drawMovingCircle() {
circle(x, height/2, 50);
x += speed;
if (x > width) x = 0;
}
// 変数名の変更後(スケッチA)
function drawMovingCircle() {
circle(circleX, height/2, 50);
circleX += speed;
if (circleX > width) circleX = 0;
}
このように変数の重複をチェックし、必要に応じて変数名を変更することで、2つのスケッチを安全に統合することができます。
3. コードを1つにまとめる
これで最後です!
最後はこれまでの注意点に注意しつつ、まとめてみましょう!
// グローバル変数
let circleX = 0;
let rectY = 0;
let speed = 2;
let angle = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
// 円の描画
drawMovingCircle();
// 四角形の描画
drawWavingRect();
}
function drawMovingCircle() {
circle(circleX, height/2, 50);
circleX += speed;
if (circleX > width) circleX = 0;
}
function drawWavingRect() {
rectY = height/2 + sin(angle) * 50;
rect(width/2, rectY, 40, 40);
angle += 0.05;
}
補. 描画順に気をつけよう!
後に描画したものが前面に表示されるので、コードの書き順も大事です!
function draw() {
background(220);
// 後に描画したものが前面に表示される
drawSketchA(); // 奥に表示
drawSketchB(); // 手前に表示
}
発展. クラスを使った整理
クラスを使うともっと構造的にまとめることができます。
class AnimationSketch {
constructor(x, y) {
this.x = x;
this.y = y;
this.setup();
}
setup() {
// 初期化処理
}
update() {
// 状態更新処理
}
draw() {
// 描画処理
}
}
// スケッチAをクラス化
class CircleAnimation extends AnimationSketch {
constructor(x, y) {
super(x, y);
this.speed = 2;
}
update() {
this.x += this.speed;
if (this.x > width) this.x = 0;
}
draw() {
circle(this.x, this.y, 50);
}
}
// スケッチBをクラス化
class RectAnimation extends AnimationSketch {
constructor(x, y) {
super(x, y);
this.angle = 0;
}
update() {
this.y = height/2 + sin(this.angle) * 50;
this.angle += 0.05;
}
draw() {
rect(this.x, this.y, 40, 40);
}
}
// 使用例
let sketchA;
let sketchB;
function setup() {
createCanvas(400, 400);
sketchA = new CircleAnimation(0, height/2);
sketchB = new RectAnimation(width/2, 0);
}
function draw() {
background(220);
// 更新と描画
sketchA.update();
sketchB.update();
push();
sketchA.draw();
pop();
push();
sketchB.draw();
pop();
}
まとめ
基本的な統合手順は以下のとおりです。
- 描画処理を関数にまとめる
- background()より下の描画処理を独立した関数にする
- 関数名は処理の内容がわかりやすい名前をつける
- 例:
drawMovingCircle()
,drawWavingRect()
- 例:
- 変数の重複をチェック
- 同じ名前の変数を見つける
- わかりやすい名前に変更する
- 片方のスケッチでしか使わない変数はそのままでOK
- 描画順序を制御
- push()とpop()で描画設定を管理
- 後に描画したものが前面に表示されることを意識
発展的な方法
- クラスを使って整理する
- 設定を分離したり、イベント処理を統合することも効果的です!
気をつけるポイント
- 変数名は用途がわかる名前にする
- 描画設定は互いに影響しないように注意
- コードの見通しを良くする
- 拡張性を考慮する
このような手順で統合することで、きれいに整理されたコードを作ることができます。
p5.js で作ったいろんなスケッチを混ぜ合わせて、もっと楽しいスケッチを作りましょう!