これまで,クラスの属性にはint,float,booleanなど初めから用意されている型を用いてきた.しかしながら,自分で作ったクラスも型であるので,当然ながらそれもまたクラスの属性の型に利用できる.
例えばこれまで書いてきたボールを例に挙げると,位置(x,y),速度(vx,vy)は2次元ベクトルである.そこで,新たに2次元ベクトルを表すクラス(型)Vector2を作り,それを利用することもできる.
Ball ball0; final float GRAVITY = 9.8 / 60; final float ELAS = 0.98; void setup(){ size(500, 500); ball0 = new Ball(width / 2, height / 2, 10, -10, 50); } void draw(){ background(255, 255, 255); ball0.move(); ball0.draw(); } class Vector2{ float x; float y; Vector2(float x, float y) { this.x = x; this.y = y; } } class Ball{ Vector2 p; Vector2 v; float d; Ball(float x, float y, float vx, float vy, float d){ this.p = new Vector2(x, y); this.v = new Vector2(vx, vy); this.d = d; } void move(){ this.p.x += this.v.x; this.v.y += GRAVITY; this.p.y += this.v.y; if (this.p.x < (this.d / 2)){ this.p.x = this.d / 2; this.v.x = ELAS * -this.v.x; } if (this.p.x > (width - (this.d / 2))){ this.p.x = width - (this.d / 2); this.v.x = ELAS * -this.v.x; } if (this.p.y > height - (this.d / 2)){ this.p.y = height - (this.d / 2); this.v.y = ELAS * -this.v.y; } } void draw(){ ellipse(this.p.x, this.p.y, this.d, this.d); } }
以下のようにあるクラスが,他のクラスを属性(メンバ変数)として持つことを包含関係と呼ぶ.has-a関係とも呼ぶ.
class Ball{ Vector2 p; Vector2 v;
final float turtleD = 100; // 亀の大きさ(甲羅の直径) Turtle turtle; void setup() { size(480, 480); noStroke(); colorMode(HSB, 360, 100, 100); turtle = new Turtle(turtleD, width / 2, height - turtleD); } void draw() { background(0, 0, 100); turtle.drawFigure(); turtle.move(); } class Turtle { final float vx0 = 0; final float vy0 = -0.3; float x; float y; float vx; float vy; float d; Shell shell; Head head; Leg[] legs; //足は四本なので素直に配列を使う Turtle(float d, float x, float y) { // 甲羅の直径と中心の初期位置 this.d = d; this.x = x; this.y = y; vx = vx0; vy = vy0; head = new Head(d / 3, 0, - d / 2, x, y); shell = new Shell(d, 0, 0, x, y); //足を作る //足は4本,すべて位置が違うので,インスタンス生成時にはfor文を用いていない legs = new Leg[4]; legs[0] = ???; ... legs[3] = ???; } void drawFigure() { head.drawFigure(); // 頭を描画する shell.drawFigure(); // 甲羅を描画する //足を描く for(int i = 0; i < legs.length; i++){ legs[i].drawFigure(); } } void move() { // 上端判定 if (head.getTopY() < 0) { vy = 0; } // 移動 x += vx; y += vy; head.move(x, y); // 頭を移動する shell.move(x, y); // 甲羅を移動する //足を移動する for(int i = 0; i < legs.length; i++){ legs[i].move(x, y); } } } /** 甲羅 */ class Shell { float d; // 甲羅の直径 float x; // 甲羅の中心のx座標 float y; // 甲羅の中心のy座標 float offsetX; // 体の中心からのx方向のoffset float offsetY; // 体の中心からのy方向のoffset Shell(float d, float offsetX, float offsetY, float baseX, float baseY) { // this.d = d; this.offsetX = offsetX; this.offsetY = offsetY; x = baseX + offsetX; y = baseY + offsetY; } void drawFigure() { fill(150, 50, 50); ellipse(x, y, d, d); } void move(float baseX, float baseY) { x = baseX + offsetX; y = baseY + offsetY; } } /** 頭 */ class Head { float d; // 頭の直径 float x; // 頭の中心のx座標 float y; // 頭の中心のy座標 float offsetX; // 体の中心からのx方向のoffset float offsetY; // 体の中心からのy方向のoffset Head(float d, float offsetX, float offsetY, float baseX, float baseY) { this.d = d; this.offsetX = offsetX; this.offsetY = offsetY; x = baseX + offsetX; y = baseY + offsetY; } /** 頭頂のy座標を返す */ float getTopY() { return y - d / 2; } void drawFigure() { fill(50, 50, 70); ellipse(x, y, d, d); } void move(float baseX, float baseY) { x = baseX + offsetX; y = baseY + offsetY; } } /*足*/ class Leg { ??? }