見出し画像

趣味としてのクリエイティブ・コーディング:104:原点を移動してみよう

前回は p5.js や Processing での座標に慣れるため、いろいろ演習してみました。
今回も OpenProcessing を使って演習を重ねていきましょう。

OpenProcessing の使い方はこちらの記事を参照ください。
趣味としてのクリエイティブ・コーディング:102:OpenProcessing を使おう

座標の原点とは

今回は座標の原点を移動する演習をしましょう。
ぜひ、読むだけではなく、コードを書いて試しながら進めてくださいね。😉

座標の原点は一般に O(英字のオー)と表記します。
p5.js や Processing での原点は何もしなければキャンバスの左上隅になっています。

この原点は translate() で移動させることが可能です。

translate(x, y)

// x方向に 100、y方向に 200 移動
translate(100, 200);

// キャンバスの右下に移動
translate(width, height);


円を中央に

それでは、下記のコードで円を一個描画してみましょう。

function setup() {
   createCanvas(500, 400);
   background(240);
   fill(255);
   stroke(0);
   noLoop();
}

function draw() {
   ellipse(0, 0, 100, 100);
}

原点はキャンバスの左上なのでこうなりますね。

これを、円がキャンバスの中央に描画されるようにしてみましょう。

それには、円を描く前に原点を移動させればよいですね。

   translate(width * 0.5, height * 0.5);
   ellipse(0, 0, 100, 100);

このときの原点と x軸、y軸はこうなっています。


でも、円を中央に描くだけなら別に translate() 使わなくても

   ellipse(width * 0.5, height * 0.5, 100, 100);

としてもいいですよね?
ほら、実行結果は同じですよ?

ではこのまま translate() を使わず以下のように円を 4個追加してみましょう。


コードはこんな感じになりますね?

   // 中央の円
   ellipse(width * 0.5, height * 0.5, 100, 100);
   // 左右の円
   ellipse(width * 0.5 - 100, height * 0.5, 100, 100);
   ellipse(width * 0.5 + 100, height * 0.5, 100, 100);
   // 上下の円
   ellipse(width * 0.5, height * 0.5 - 100, 100, 100);
   ellipse(width * 0.5, height * 0.5 + 100, 100, 100);

う〜ん、これちょっと煩雑ですよね。
それより translate() を使ってこう書いたほうが簡潔だし、それぞれの円の位置関係がぱっと見わかりやすくないですか?

   translate(width * 0.5, height * 0.5);
   // 中央の円
   ellipse(0, 0, 100, 100);
   // 左右の円
   ellipse(-100, 0, 100, 100);
   ellipse( 100, 0, 100, 100);
   // 上下の円
   ellipse(0, -100, 100, 100);
   ellipse(0,  100, 100, 100);

このように、translate() で原点を移動させないとできないというわけではないのですが、 原点を移動させたほうが描こうとするものの位置関係だけに集中することが出来ます。

今回のように円を上下左右に並べるぐらいでは大きな問題になりませんが、もっと複雑な位置関係のものを描こうとすると translate() を使わないと手に負えなくなる場面が出てきます。

サインカーブを中央に

では、このようなサインカーブを表示するには?

サインカーブを描くコード例はこうです。

for (i = 0.0; i < 1.0; i += 0.01) {
   ellipse(width * i, sin(TWO_PI * i) * height * 0.5, 10, 10);
}

単にそのまま実行するとこうなりますね。

原点と x軸、y軸はこうなっています。

これを見ると半分だけ下にずらせばよさそうですね。となると?

translate(0, height * 0.5);

こうですね!


では右側の山部分だけこのように表示するにはどうしたらいいでしょう?

はい、こうですね。

translate(-width * 0.25, height);

translate() の気をつけたい性質

このように translate() を使うと、自分の描画したいもの、複数の図形を組み合わせたものを丸ごと自由にキャンバス上のどこにでも移動させることができます。

今までの例では translate() で原点を一回移動して図形を描画する、といったものでした。
例えばこのように、原点を (10, 10) に移動して小さな円を一個描画。

function setup() {
   createCanvas(500, 400);
   background(240);
   fill(255);
   stroke(0);
   noLoop();
}

function draw() {
   translate(10, 10);
   ellipse(0, 0, 10, 10);
}

では、原点を複数回移動させたらどうなるんでしょう?

例えばこうしてみましょう。

   for(i = 0; i < 20; i++) {
	translate(10, 8);
	ellipse(0, 0, 10, 10);
   }

はい、このように原点は繰返し移動していきます。

translate(10, 8);

であれば、元の原点からループする度に x軸方向に +10、y軸方向に +8 ずつ移動していきます。
最終的に原点はこの位置にまで移動することになります。

なので、この後に ellipse(0, 0, 100, 100); を入れるとこうなります。


ループの中に translate() を入れることで図形を連続して移動させながら描画できるわけですね。
ということは、draw() ループの中に translate() があればそれでアニメーションを簡単に作れるのでは?

今は setup() 中の

   noLoop();

によって draw() のループは停止していますが、これを外せば draw() は繰返し実行されることになります。
なので、noLoop(); を外して、同時に draw() 中の for 分も無くしてこうしてみましょう。

function setup() {
   createCanvas(500, 400);
   background(240);
   fill(255);
   stroke(0);
}

function draw() {
   translate(10, 8);
   ellipse(0, 0, 10, 10);
}

…あり?動かない……☹

はい、これでは動きません。
動かしたい場合、例えばこのようにする必要があります。

   translate(frameCount * 10, frameCount * 8);

translate(x, y) の x, yは draw() ループが n回ループするときに下記のように変化します。

n回   x軸   y軸
1   10   8
2   20   16
3   30   24
4   40   32
5   50   40

これは原点がキャンバスの左上とした場合の円の位置そのものです。

あれれ?なんかさっきと話が違いますね?
さっきは元の原点からどれだけ移動させるかという話でしたが、今はキャンバス左上に固定された原点からどれだけ移動させるかという話になっています。

実は、draw() ループでは、ループの度に原点はキャンバスの左上に戻るんです!
つまり、draw() ループが回る度に元の原点がキャンバスの左上になるので、『元の原点からどれだけ移動させるか』という点では同じなんですね。

ちなみに、draw() ループではなく、draw() 中の for ループでこのようにすると、

   for (i = 0; i < 20; i++) {
	translate(i * 10, i * 8);
	ellipse(0, 0, 10, 10);
   }

原点はリセットされないので、こうなります。

このように translate() は 元の原点からどれだけ原点を移動させるかを指定するものですが、draw() の度に原点はリセットされるという点に注意が必要です。

今回はここまで。

今回はここまでです。
最後に translate() を使ったランダムウォークを紹介しましょう。
静止画なら変数無しでこのようにするだけでランダムウォークを描画できますよ。

   translate(width * 0.5, height * 0.5);
   for (i = 0; i < 500; i++) {
	translate(random(-10, 10), random(-8, 8));
	ellipse(0, 0, 10, 10);
   }

さて、これを draw() ループでアニメーションさせるにはどうしたらいいでしょう?🤔









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