見出し画像

趣味としてのクリエイティブ・コーディング:009:もう面倒な計算しなくていいの

コードをきれいに整理したので、変更するのがやりやすくなりました。
どんどん変更して大暴れしちゃいましょう!

本シリーズの趣旨は初回をご覧ください。

思いつくままいろんなパターン

前回のソースコードはこれでした。
これを元に遊んでみましょう。

    <html>
    <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js"></script>
    </head>
    <body>
<script>
// Creative Commons CC0
// sc008 趣味としてのクリエイティブ・コーディング:008:パズルはお好き?

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);

    prevWaveNo = 1;
    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 * 25 * (prevWaveNo + waveNo - 1);
		eY = -sin(radians) * radians * lineNo * waveNo * waveNo * 2.0;
		eR = lineNo;
		
		fill(
		    eHue,
		    eSat,
		    eBri,
		    100
		);
		ellipse(
		    eX,
		    eY,
		    eR,
		    eR
		);
	    }
	}
	prevWaveNo = waveNo;
    }

}

</script>
    </body>
    </html>

まずは、このコードを動かして描かれる結果はこう。

波形をひとつ追加してみましょうか。
それには?

for (waveNo = 1; waveNo <= 4; waveNo += 1) {

こうですね。


線の本数も増やしてみましょうか。
方法はいくつかありますが、線と線の間隔を狭めてみましょう。
それには?

for (lineNo = -2; lineNo < 5; lineNo += 0.1) {

例えばこうですね。


もっと狭めると?

for (lineNo = -2; lineNo < 5; lineNo += 0.05) {

ちょっとやり過ぎかな?

じゃあ、線を構成する円と円の間隔を広げてみましょう。
それには?

for (radians = 0; radians < TWO_PI; radians += 0.2) {

例えばこう。

お!なんかまた面白い絵になりました!


よし、次は色を変えてみましょう。今は線毎に色を変えていますね。

		eHue = lineNo * 60;

これ、 lineNo が -2 のときとか、 eHue = -2 * 60 = -120 とマイナスの色というあり得ないことになってました。
これはバグなのですが、マイナスの色だと赤扱いになるみたいで、その色が気に入ってそのままにしてたんです。

詳しくはシリーズ第6話参照ください。

バグのある状態で十分楽しんだので、そろそろこのバグを無くしておきましょう
例えば、lineNo が -2 から 5 にかけて色を 0 から 360 まで変化させるというのはどうでしょう?
(色が 0 から 360 というのも第6話参照してね)

それには?

lineNo が -2, 5

eHue を 0 , 360

このパズルを解けばいいですね。

-2 が 0 になるようにするには 2を足せばいいから

-2 + 2, 5 + 2

0 , 360

0 には何を掛けても 0 だし、7 に何かを掛けて 360 になるようにすればいいから、これが、

0, 7

0 , 360

こんな感じ?

0 * 360 / 7, 7 * 360 / 7

0 , 360

これをコードにすると、

(lineNo + 2) * 360 / 7

こうじゃないですかね?

やってみましょう。
線と円の間隔はもとに戻して、

for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
    for (radians = 0; radians < TWO_PI; radians += 0.01) {
	eHue = (lineNo + 2) * 360 / 7;

う〜ん、よくわかんないけど、なんか出来てるっぽい!
これでバグ無くなりましたね!
(色についてはね…)

計算めんどいよ…

さて、めでたく lineNo の -2, 5 を色の 0, 360 に変換することができました。

…でも、計算式考えるの面倒くさかったですね。
これを 0, 360 じゃなくて 360, 0 にしたかったら?
う〜、考えたくない!

こういう プログラム上面倒くさいとか、しんどいと感じた場合、大抵のことにはいい方法が用意されています

今回の場合に使えるのは、「map()」です!
これ超便利!

例えばさっきの例だと、

	eHue = map(lineNo, -2, 5, 0, 360);

と書くだけで OK! 面倒な計算を肩代わりしてくれるんです!

書き方は、

map(これが, ここから, ここまでを, ここから, ここまでに変換)

です。
正にやりたかった計算ですね!
さっきの「0, 360 じゃなくて 360, 0 にしたかったら?」は、

	eHue = map(lineNo, -2, 5, 360, 0);

とするだけなんです! 簡単で感嘆!

map() について紹介した別記事もあるので、よかったらどうぞ。

プログラマはしんどいのが大嫌い
プログラマはめんどくさがりです。怠惰ともいいます。
面倒くさくてしんどいことはしたくないので、それを回避することを真面目に一所懸命に考えます。
おかげで、大抵のことにはしんどくない方法が用意されてるわけです。
怠惰な先人に感謝です。

ここでも出てくるプログラミングのキモ!

じゃあ今度は、色を左から右に行くにつれて変化するようにしてみましょう。

左から右は x 軸ですから、eX の値が例えば 0 から 400 までに、色が 0 から 360 になるように、map() を使って書くと、

	eHue = map(eX, 0, 400, 0, 360);

こうですね。

あれ?

…動かない。

はい! 単に eHue の式を変えるだけでは動きません。

そうです。 eX はこの時点ではまだ計算されてないんですね。

	eHue = map(eX, 0, 400, 0, 360);
	eSat = 100 - radians * 5;
	eBri = radians * waveNo * waveNo * 3;

	eX = radians * 25 * (prevWaveNo + waveNo - 1);

eX が計算されるより前に eHue の map() で eX を使おうとしたのがマズいです。
前回やった変数のセットと使う場所の関係ですね。

解決するには、eX の計算の後に eHue の式を持ってくればいいわけです。

eHue だけ持っていけば解決なんですが、eSat と eBri も fill() の中で使う eHue の仲間ですから、コードのわかり易さのために一緒に移動しましょう。

	eX = radians * 25 * (prevWaveNo + waveNo - 1);
	eY = -sin(radians) * radians * lineNo * waveNo * waveNo * 2.0;
	eR = lineNo;

	eHue = map(eX, 0, 400, 0, 360);
	eSat = 100 - radians * 5;
	eBri = radians * waveNo * waveNo * 3;

グッド、グッド! OK ですね!

いろいろな技伝授!

0 の赤から始まって、黄色、緑、水色、青、紫と変わってまた 360 の赤に戻るとなってます。
この図の角度 0度から 360度 にかけて一周してるかたちですね。


じゃあ、これを二周、三周させることはできないでしょうか?

三周なら 3倍?

	eHue = map(eX, 0, 400, 0, 360 * 3);

あら、違うみたい…

0 から 360 まで行って、361 になったらまた 1 から始まるといいんですが、これって…

そう! 360 で割り算した余りですね。

これは % で表すことが出来て、 % 360 とすると、360 で割った余りを計算してくれます。
なので、さっきの三周させたかったものは、

	eHue = map(eX, 0, 400, 0, 360 * 3) % 360;

これで、

こう!
うわー、派手!


面白いからここに y 軸も追加して、y 軸は大体 -200 から 200 の間の変化なのでこうしてみましょう。

eHue = (map(eX, 0, 400, 0, 360 * 3) + map(eY, -200, 200, 0, 360 * 3)) % 360;

結果がどうなるか考える前に動かしちゃえ!

ほう!斜めになるのね。


x 軸側を一周にすると?

eHue = (map(eX, 0, 400, 0, 360 * 1) + map(eY, -200, 200, 0, 360 * 3)) % 360;

ああ、そうか!斜めが緩やかになるのか。
こっちのほうが好きかも。


じゃあ、極端に y 軸側を 10周とかしてみたら?

eHue = (map(eX, 0, 400, 0, 360 * 1) + map(eY, -200, 200, 0, 360 * 10)) % 360;

わあ!気持ち悪い!ダメだこりゃー。楽しー!

…いや、でもこれで線を増やしてみたら…

for (lineNo = -2; lineNo < 5; lineNo += 0.1) {

これはこれで…
いや、やっぱり気持ち悪いや。


最後にこうしてみましょう。

eHue = (map(eX, 0, 400, 0, 360 * 1) + map(abs(eY), 0, 200, 0, 360 * 1)) % 360;

なんか良い感じじゃありません?

abs() というのが出てきましたが、これは絶対値を計算してくれるものです。
-200 は 200 になるんで、範囲は 0 から 200 として、y 軸を対称に上下が同じ結果になるわけです。

lineNo がマイナスのときに色がマイナスになってしまうバグ、実はもうひとつバグがあって、

		eR = lineNo;

ここで、円の大きさもマイナスになってました。

これを解決するには?
そう!

		eR = abs(lineNo);

こうですね!天才!


はい、今回はここまでです。
今回は

map() 計算を楽にしてくれる
% 割り算の余りを出してくれる
abs() 絶対値を出してくれる

こんなに沢山覚えました!

遊び道具がまた増えましたね!
今回の最後の例のコードを掲載しておきます。新しい遊び道具を使ってまた遊んでみてください。

    <html>
    <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js"></script>
    </head>
    <body>
<script>
// Creative Commons CC0
// sc009 趣味としてのクリエイティブ・コーディング:009:もう面倒な計算しなくていいの

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);

    prevWaveNo = 1;
    for (waveNo = 1; waveNo <= 4; waveNo += 1) {
	for (lineNo = -2; lineNo < 5; lineNo += 0.5) {
	    for (radians = 0; radians < TWO_PI; radians += 0.01) {

		eX = radians * 25 * (prevWaveNo + waveNo - 1);
		eY = -sin(radians) * radians * lineNo * waveNo * waveNo * 2.0;
		eR = abs(lineNo);

		eHue = (map(eX, 0, 400, 0, 360) + map(abs(eY), 0, 200, 0, 360)) % 360;
		eSat = 100 - radians * 5;
		eBri = radians * waveNo * waveNo * 3;
		
		fill(
		    eHue,
		    eSat,
		    eBri,
		    100
		);
		ellipse(
		    eX,
		    eY,
		    eR,
		    eR
		);
		
	    }
	}
	prevWaveNo = waveNo;
    }

}

</script>
    </body>
    </html>






この記事が面白かったらサポートしていただけませんか? ぜんざい好きな私に、ぜんざいをお腹いっぱい食べさせてほしい。あなたのことを想いながら食べるから、ぜんざいサポートお願いね 💕