丸がたくさん振ってくるプログラムを書いてみましょう。「たくさん」と言えば「配列」でした。これまでに学んだことを使うとたとえばこんな感じに書けると思います。 ちょっと雪景色っぽく見えるように丸の初期配置や大きさをランダムに決定しています。
float[] x; float[] y; float[] size; void setup(){ x = new float[20]; y = new float[20]; size = new float[20]; for(int i = 0; i < x.length; i++){ x[i] = random(width); y[i] = random(height); size[i] = random(10); } } void draw(){ background(0); fill(255); for(int i = 0; i < x.length; i++){ y[i] = (y[i] + 2) % height; ellipse(x[i], y[i], size[i], size[i]); } }
書けたのはいいのですが、「丸がたくさん」ではなく、「丸のx座標がたくさん、y座標もたくさん、大きさもたくさん」という感じになっていて少しわかりにくいような気がします。
「丸」を表す型があればもっと素直に Circle[] circles
と書けるのですが…。
ほしい型がないなら自分で作っちゃおうということで登場するのが「クラス」です。クラスを使うと、複数の変数をひとまとめにした新しい型を定義することができます。 たとえば以下では float 型の変数 x, y, size を持つクラス Circle を定義しています。
class Circle { float x; float y; float size; }
class クラス名 {
// クラスの中身(メンバーと呼びます)
}
これで3つの変数が1セットになった新しい型ができました。ここでの x, y, size のように、クラスに属している変数のことをそのクラスの「メンバー変数」と呼びます。
クラスそのものはデータではなく、データの設計図のようなものに過ぎません。設計図であるクラスから具体的なデータを作成して利用します。作成される個々のデータのことを「オブジェクト」と呼びます。 作成したオブジェクトは他のデータと同じように変数や配列にしまっておきます。実際に、上で作成した Circle クラスのオブジェクトを作成・利用してみましょう。
Circle c; // 変数の宣言 c = new Circle(); // オブジェクトの作成 c.x = random(width); // c の x c.y = random(height); // c の y c.size = random(10); // c の size c.y = (c.y + 2) % height; ellipse(c.x, c.y, c.size, c.size);
new
を使います。
変数 = new クラス名();
文法:オブジェクトのメンバー変数を利用するには . (ドット)
を使います。
オブジェクト.メンバー変数
最初の雪景色っぽいプログラムを Circle クラスを使って書き直してみると以下のようになります。
Circle[] circles; void setup(){ circles = new Circle[20]; for(int i = 0; i < circles.length; i++){ circles[i] = new Circle(); circles[i].x = random(width); circles[i].y = random(height); circles[i].size = random(10); } } void draw(){ background(0); fill(255); for(int i = 0; i < circles.length; i++){ Circle c = circles[i]; c.y = (c.y + 2) % height; ellipse(c.x, c.y, c.size, c.size); } } class Circle{ float x; float y; float size; }
応用編として、前回までに学んだマウス操作に反応するプログラムの書き方を応用して、押された回数を数えてくれるボタンが表示されるプログラムを作成してみましょう。 まずは、クラスを使わない書き方で行きます。
boolean isPressed; int count; float cx, cy; // (cx, cy) = center of the button float w, h; // width and height of the button void setup() { size(200, 200); rectMode(CENTER); textAlign(CENTER); setupButton(width * 0.5, height * 0.5); } void draw() { background(255); drawButton(); } void mousePressed() { checkButtonPress(); } void mouseReleased() { checkButtonRelease(); } void setupButton(float x, float y) { isPressed = false; count = 0; cx = x; cy = y; w = 100; h = 40; } void drawButton() { if (isPressed) { fill(128); } else if (isOnTheButton(mouseX, mouseY)) { // Mouse is hovering on the button fill(192); } else { fill(160); } rect(cx, cy, w, h); fill(0); text("Count: " + count, cx, cy); } void checkButtonPress(){ if (isOnTheButton(mouseX, mouseY)) isPressed = true; } void checkButtonRelease(){ if(isPressed && isOnTheButton(mouseX, mouseY)) count++; isPressed = false; } boolean isOnTheButton(int x, int y) { return abs(cx - x) < w / 2 && abs(cy - y) < h; }
上記のプログラムで1つのボタンを作ることができました。それを元に複数のボタンが登場するプログラムを作ってみましょう。
boolean[] isPressed; int[] count; float[] cx, cy; float[] w, h;
となるのはかなり大変そうなので、丸のときのように Button[] bs
と書けるように Button クラスを作りましょう。
class Button { boolean isPressed; int count; float cx, cy; float w, h; }
実は、クラスには変数だけでなく関数も含めることができます。ボタンに関係する関数は同じクラスに入れてしまうのが自然な発想でしょう。
class Button { boolean isPressed; int count; float cx, cy; float w, h; void setupButton(float x, float y) { isPressed = false; count = 0; cx = x; cy = y; w = 100; h = 40; } void drawButton() { if (isPressed) { fill(128); } else if (isOnTheButton(mouseX, mouseY)) { // Mouse is hovering on the button fill(192); } else { fill(160); } rect(cx, cy, w, h); fill(0); text("Count: " + count, cx, cy); } void checkButtonPress() { if (isOnTheButton(mouseX, mouseY)) isPressed = true; } void checkButtonRelease() { if (isPressed && isOnTheButton(mouseX, mouseY)) count++; isPressed = false; } boolean isOnTheButton(int x, int y) { return abs(cx - x) < w / 2 && abs(cy - y) < h; } }
クラスに属している関数のことを「メンバー関数」と呼びます。
なかなかボリューム感のあるクラスになりました。クラスを作成するなどしてプログラムが長くなってきたときには複数のファイル(タブ)に分けるのがオススメです。
作成した Button クラスを利用して、先ほどのプログラムを書き直すと以下のようになります。
Button b; void setup() { size(200, 200); rectMode(CENTER); textAlign(CENTER); b = new Button(); b.setupButton(width * 0.5, height * 0.5); } void draw() { background(255); b.drawButton(); } void mousePressed() { b.checkButtonPress(); } void mouseReleased() { b.checkButtonRelease(); }
ボタンに関する詳細を Button クラスの中に入れてしまった分、プログラムがすっきりしました。
あとは…できますよね?
Button[] bs; void setup() { size(200, 200); rectMode(CENTER); textAlign(CENTER); bs = new Button[3]; for(int i = 0; i < bs.length; i++){ bs[i] = new Button(); bs[i].setupButton(width * 0.5, 40 + i * 60); } } void draw() { background(255); for(int i = 0; i < bs.length; i++){ bs[i].drawButton(); } } void mousePressed() { for(int i = 0; i < bs.length; i++){ bs[i].checkButtonPress(); } } void mouseReleased() { for(int i = 0; i < bs.length; i++){ bs[i].checkButtonRelease(); } }
setupButton
関数のようなオブジェクト作成時の初期化処理は、「コンストラクタ」と呼ばれる特別なメンバー関数を作成することで new
によるオブジェクト作成とまとめることができます。
setupButton
関数を以下のように書き換えてコンストラクタを作成してみましょう。
Button(float x, float y) { isPressed = false; count = 0; cx = x; cy = y; w = 100; h = 40; }
クラス名(引数) { // 初期化処理 }
クラス名と同名の関数を作るとコンストラクタになります。返り値の型指定 void
が不要になることに注意しましょう。
このようにコンストラクタを作成しておくと以下のように1行でオブジェクトの作成とメンバー変数の初期化を行うことができます。
bs[i] = new Button(width * 0.5, 40 + i * 60);
今回のようにクラスやオブジェクトを利用するプログラミングを「オブジェクト指向プログラミング」と呼びます。おつかれさまでした! Happy Programming!!!