趣味としてのクリエイティブ・コーディング:007:コードを整理!
今回はコードを整理しましょう。
「趣味のクリエイティブ・コーディング」なのでコードは汚くても読みづらくても全然自由なんですが、読みづらいソースコードって書き間違いや勘違いを起こしたり、後から修正するのがやりづらかったりするんです。
遊び場がジャングルになってしまって、枝にひっかかったり雑草に足を取られたりで遊びづらくなるって感じ。
思いっきり駆け回れるように、ここらでちょっとソースコードを整理しましょう。
本シリーズの趣旨は初回をご覧ください。
…というわけで整理しました!
前回の実行結果とソースコードがこれ。
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js"></script>
</head>
<body>
<script>
// Creative Commons CC0
// sc006 趣味としてのクリエイティブ・コーディング:006:色彩を操ろう!
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
blendMode(SCREEN);
noStroke();
noLoop();
}
function draw() {
background(0, 0, 0, 100);
translate(40.0, height / 2.0);
for (j = -2; j < 5; j += 0.5) {
for (i = 0; i < TWO_PI; i += 0.01) {
fill(j * 60, 100 - i * 5, i * 5, 100);
ellipse(i * 25, -sin(i) * j * 3 * i, j, j);
fill(j * 60, 100 - i * 5, i * 10, 100);
ellipse(i * 50, -sin(i) * j * 8 * i, j, j);
fill(j * 60, 100 - i * 5, i * 30, 100);
ellipse(i * 100, -sin(i) * j * 20 * i, j, j);
}
}
}
</script>
</body>
</html>
図はなかなかイイですよね。もうアートなんじゃないですか?
でもコードの方は fill() と ellipse() の所がごちゃっとしてますね。
これもアートなのかな…? いやいや、見づらいだけ。
ということで、ズバリ!整理したコードがこちらになります!
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js"></script>
</head>
<body>
<script>
// Creative Commons CC0
// sc007 趣味としてのクリエイティブ・コーディング:007:ちょっとコードを整理!
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
blendMode(SCREEN);
noStroke();
noLoop();
}
function draw() {
background(0, 0, 0, 100);
translate(40.0, height / 2.0);
for (waveNo = 1; waveNo <= 3; waveNo += 1) {
for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
for (radians = 0; radians < TWO_PI; radians += 0.01) {
eHue = lineNo * 60;
eSat = 100 - radians * 5;
eBri = radians * waveNo * waveNo * 3;
eX = radians * waveNo * 25;
eY = -sin(radians) * radians * lineNo * waveNo * waveNo * 2.0;
eR = lineNo;
fill(
eHue,
eSat,
eBri,
100
);
ellipse(
eX,
eY,
eR,
eR
);
}
}
}
}
</script>
</body>
</html>
このコードで描かれる図はこちら。
結果が前とちょっと違いますね。
今回はコードの整理を優先して、結果は妥協しちゃいました。
今回はここまでです!
整理の過程にご興味があれば続きをお読みください。
そうでない方は次回まで、さようなら!
よく変更するところを変数でまとめよう
ロジック中の数値をいじってると、違う所を書き間違ったりして危険があぶない!
fill(j * 60, 100 - i * 5, i * 5, 100);
ellipse(i * 25, -sin(i) * j * 3 * i, j, j);
この例では fill() の中の 2箇所に「i * 5」があって、両者を取り違えたりとか。
ellipse() の方は xy座標の計算がどうなってんのかパッと見でよくわかんないし、 「,」 の数とか入れる位置を間違えちゃいそうで、本当に怖い。
できれば、よく変更するところは一箇所にまとめておきたいですね。
fill(j * 60, 100 - i * 5, i * 5, 100);
fill(j * 60, 100 - i * 5, i * 10, 100);
fill(j * 60, 100 - i * 5, i * 30, 100);
例えば 3つの fill() を見ると、色と彩度のところは全く同じですね。
ここを変数にすれば、変更するところをまとめることができます。
例えば、
色を eHue という変数(ellipse の Hue = 色相 という意味で名付けました)、
彩度を eSat という変数(ellipse の Saturation = 彩度)
にして、
eHue = j * 60;
eSat = 100 - i * 5;
fill(eHue, eSat, i * 5, 100);
fill(eHue, eSat, i * 10, 100);
fill(eHue, eSat, i * 30, 100);
としても同じ結果が得られますし、eHue、eSat のところを書き換えるだけで、3箇所の fill() をいちいち書き換える必要がなくなります。
それに、こっちの方がだいぶ見やすいですよね。
コードが見やすいことは、わかり易いことに繋がります。
ついでに、明度のところも変数 eBri という変数(ellipse の Brightness = 明度)にして、
eHue = j * 60;
eSat = 100 - i * 5;
eBri = i * 5;
fill(eHue, eSat, eBri, 100);
fill(eHue, eSat, eBri * 2, 100);
fill(eHue, eSat, eBri * 6, 100);
としてもいいですね。
こうすると、2番めの fill() は 1番目の 2倍の明るさ、3番目の fill() は 6倍の明るさというように、見やすくなるだけでなく、コードの意味がわかりやすくなってきます。
じゃあ、同じような考えで ellipse() の方もやってみると?
ellipse(i * 25, -sin(i) * j * 3 * i, j, j);
ellipse(i * 50, -sin(i) * j * 8 * i, j, j);
ellipse(i * 100, -sin(i) * j * 20 * i, j, j);
これを、例えばこうやって、
eX = i * 25;
eY = -sin(i) * i * j;
eR = j;
ellipse(eX, eY * 3, eR, eR);
ellipse(eX * 2, eY * 8, eR, eR);
ellipse(eX * 4, eY * 20, eR, eR);
これでだいぶ見やすくなりました。
変数は意味を大切にね
え? 『eR は j そのものなんだからわざわざ書き換える必要ないじゃないか』って?
それ、良い質問です!
確かにこれだと eR にも j にも同じ値が入るので、プログラムの動きとしてはわざわざ書き換える意味はありませんし、見やすさも大して変わりません。
でもね、これ見やすさより「意味」という点で大事なんです。
そもそも j は、for ループで使っていた変数でした。
for (j = -2; j < 5; j += 0.5) {
j が -2 から始まって、 0.5 刻みでプラスしていきながら、5 になる手前まで繰り返すってことでしたね。
その j を ellipse() の中で、円の幅と高さのところでも使っていました。
ellipse(省略, 省略, j, j);
これ、一方は繰り返しをコントロールするため、もう一方は円の幅と高さを表すもので、同じ j でも意味や目的が全然違いますよね?
意味や目的が全然違うものに同じ名前を付けるってなんかヤバそうじゃありません?
こういう場合は別の名前(別の変数)付けといたほうがいいんですよ。
実用的にも、例えば先の図を見てて「これ、もうちょっと線を太くしたら面白くなるのでは?」となったとき、
eR = j * 2;
「いやいや、細くしたほうがキレイになるに違いない」と思ったら、
eR = j * 0.5;
ってするだけで簡単に、楽に試せるんです。
これが別の変数にしてないと、
ellipse(i * 25, -sin(i) * j * 3 * i, j * 2, j * 2);
ellipse(i * 50, -sin(i) * j * 8 * i, j * 2, j * 2);
ellipse(i * 100, -sin(i) * j * 20 * i, j * 2, j * 2);
と 6箇所も修正しないといけない!
おまけに、試した挙げ句結果があんまり良くなかったら、ま〜た 6箇所元に戻さないといけないのよ!!(←これしょっちゅう)
『じゃあ、円の幅と高さはそれぞれ意味が違うんだから、それに同じ名前の eR と付けるのはおかしいんじゃない?』
ごもっとも!
しかし、ここでは幅も高さも同じ eR とすることで「幅と高さは同じ、つまり、まん丸い円を描くよ」ということを表明できるんです。
i と j って何? 意味分かんないじゃん!
そうなってくると、for ループのコントロールに使っている i と j も意味分かんないですよね。
単に繰り返しのコントロールに使うだけならこれでもいいんですが、こんな風にループの中で他の計算にも使うようになるとちょっと問題です。
for (j = -2; j < 5; j += 0.5) {
for (i = 0; i < TWO_PI; i += 0.01) {
eHue = j * 60;
eSat = 100 - i * 5;
eBri = i * 5;
プログラムの動き的には全く問題無いんですよ。
ですが、ここだけ見ても j が何を意味するのかわかりませんよね?
eHue = j * 60;
ループのコントロールに使ってるだけなら i とか j でもいいんですが、こういう式が沢山増えてくると、i とか j だと段々苦しくなってくるんです。
i と j って字面も似てて間違いやすそうですし。
ということで、 i と j にも意味が解る名前を付けてみましょう。
j を変えるとサインカーブのカーブの本数が変わりましたね。
であれば、線の数ってことで lineNo とかどうでしょう?
i は、サインカーブを描くときの sin(i) で使うことが最初の目的でした。
sin() は三角関数というやつで、このカッコの中はラディアンという角度の単位なんですね。
なので、 radians という名前にしましょうか。
そうすると、こんな感じ。
for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
for (radians = 0; radians < TWO_PI; radians += 0.01) {
eHue = lineNo * 60;
eSat = 100 - radians * 5;
eBri = radians * 5;
これなら、
eHue = lineNo * 60;
を見て、線の本数によって色を変えるんだなという見当が付きますよね。
for (lineNo = -2;
は、線の数が -2 ってなんだ? となりますが、そこは妥協です…
なんか楽しくなってきた!もっともっと見やすく!
ここまでの変更をまとめると、こうなります。
for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
for (radians = 0; radians < TWO_PI; radians += 0.01) {
eHue = lineNo * 60;
eSat = 100 - radians * 5;
eBri = radians * 5;
eX = radians * 25;
eY = -sin(radians) * radians * lineNo;
eR = lineNo;
fill(eHue, eSat, eBri, 100);
ellipse(eX, eY * 3, eR, eR);
fill(eHue, eSat, eBri * 2, 100);
ellipse(eX * 2, eY * 8, eR, eR);
fill(eHue, eSat, eBri * 6, 100);
ellipse(eX * 4, eY * 20, eR, eR);
}
}
だいぶ見やすくなりましたが、fill() と ellipse() のところがまだごっちゃり感ありますね。
ここを、例えばこうしたらどうでしょう?
fill(
eHue,
eSat,
eBri,
100
);
ellipse(
eX,
eY * 3,
eR,
eR
);
どうです?
横に並べるより縦に並べたほうがわかり易くないですか?
fill(
eHue,
eSat,
eBri,
100
);
ellipse(
eX,
eY * 3,
eR,
eR
);
fill(
eHue,
eSat,
eBri * 2,
100
);
ellipse(
eX * 2,
eY * 8,
eR,
eR
);
fill(
eHue,
eSat,
eBri * 6,
100
);
ellipse(
eX * 4,
eY * 20,
eR,
eR
);
行数はすんごい増えるけど…
整理はいいけど、どこまでやるの?
このように、人が読みやすくするために縦に書いたり、適切に空白を入れたり、行頭を揃えたりなどをよくします。
どのレベルが適切かは、今はあまり気にせず、自分の好みで自由に書いてみましょう。
どういう書き方が見やすいかな? と、いろいろ試してみるのもいいと思います。
でも、こうして縦に並べてみると、
・fill() は eBri に掛け算してる数値が違うだけ。
・ellipse() は eX と eY に掛け算してる数値が違うだけ。
というのがよくわかりますよね。
てことは、この掛け算してる数値を変数にしてやれば、3つの fill() と ellipse() を一つにまとめることができて、もっと整理されるんじゃないでしょうか。
イメージとしてこんな感じ。
for (xxx で 3回ループ) {
fill(
eHue,
eSat,
eBri * xxx,
100
);
ellipse(
eX * xxx,
eY * xxx,
eR,
eR
);
}
このループは、波の形の違う3つのサインカーブを描くためのものになります。
一個目の波
二個目の波
三個目の波
なので、ループの変数の名前を waveNo にしてみましょう。
そうすると、こんな感じ。
for (waveNo = 1; waveNo <= 3; waveNo += 1) {
for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
for (radians = 0; radians < TWO_PI; radians += 0.01) {
eHue = lineNo * 60;
eSat = 100 - radians * 5;
eBri = radians * waveNo * waveNo * 3;
eX = radians * waveNo * 25;
eY = -sin(radians) * radians * lineNo * waveNo * waveNo * 2.0;
eR = lineNo;
fill(
eHue,
eSat,
eBri,
100
);
ellipse(
eX,
eY,
eR,
eR
);
}
}
}
掛け算の部分全てが等倍というわけではなかったので、試行錯誤しながら結果が近くなるように計算式を調整しました。
ただし、 eX の計算は全然違っちゃってて、一番大きな波形のカーブが全く違う形になってしまってます。
元々はこうで 4倍の掛け算だったのが、
3倍の掛け算にしかできずにこうなっちゃった。
う〜ん、ここは断腸の思いで妥協!
涙を呑んで今回はここまでです!
ここまで読んだ方だけにボーナスです!
そろそろ、自分で描いた図を SNS に上げたり、壁紙にしたりとかしてみたいんじゃありません?
そのためには描いた図をファイルとして保存したいですよね?
ここまでコードのお掃除に付き合ってくださった方だけにお教えします。
saveCanvas() を使えばそれが可能になるんです。
今回の場合であればコードの最後の } の前に入れてみて下さい。
saveCanvas();
}
</script>
これを書き入れてコードを保存し、ブラウザで再読込すれば、どこにファイルを保存するか聞いてくるようになりますよ。
試してみてね!
これ、途中で読むの止めちゃった人は知らないんですよ。
最後まで読めばよかったのにね~! イーッヒッヒッヒ!
この記事が面白かったらサポートしていただけませんか? ぜんざい好きな私に、ぜんざいをお腹いっぱい食べさせてほしい。あなたのことを想いながら食べるから、ぜんざいサポートお願いね 💕