yoppa.org


人工言語入門 A 2010

Processingでオブジェクト指向プログラミング (2)

Processingでオブジェクト指向プログラミング (2)

前回の復習

  • オブジェクト指向プログラミング (= OOP)のポイント

オブジェクト指向プログラムのポイント:その1

  • 「もの (= オブジェクト)」という単位でプログラムを構成する
  • オブジェクトは、プロパティー(性質)とメソッド(動作・ふるまい)から構成

オブジェクト指向プログラムのポイント:その2

  • オブジェクト同士がメッセージを送りあう

オブジェクト指向プログラムのポイント:その3

  • オブジェクトはメッセージを受け取り、それに応じた処理を行う
  • メッセージの処理方法は、オブジェクト自身が知っていて、その処理はオブジェクトによって異なる (ポリモーフィズム)

オブジェクト指向プログラムのポイント:その4

  • 必要のない情報は隠す (カプセル化)
  • プログラムの実装全てを知る必要はない
  • 必要なインターフェイス(接点)だけ見せて、あとは隠す

オブジェクト指向プログラムのポイント:その5

  • オブジェクトから新たなオブジェクトを派生させることができる (継承)

オブジェクト指向プログラムのポイント:その6

  • クラスとは:オブジェクトの「型紙」
  • クラスをインスタンス化 (実体化) することでインスタンス(オブジェクト)となる

先週の内容の確認

  • 円を描くクラス Spot を作成
  • クラスを宣言、クラスをインスタンス化
  • 円のプロパティを定義 – x, y, diameter
  • 円を描画するメソッドを定義 – display()
  • コンストラクタを定義 – Spot(float x, float y, float diameter)
  • 動きを追加する – move();
  • 複数のインスタンスの生成 – sp1, sp2, sp3 …
  • インスタンスの配列を生成 – Spot[] spots

  • 今日の授業は先週のつづきから始めます
  • 先週の最終的なプログラムをダウンロード

[code language=”java”]
int numSpots = 400;

Spot[] spots = new Spot[numSpots];

void setup() {
size(800, 600);
noStroke();
smooth();
frameRate(60);
for (int i = 0; i < spots.length; i++) {
spots[i] = new Spot(random(0,width), height/2, random(5,40), random(-4,4));
}
background(0);
}

void draw() {
fill(0,0,0,10);
rect(0, 0, width, height);
fill(255);
for (int i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].display();
}
}

class Spot {
float x, y;
float diameter;
float speed;

//コンストラクター
Spot(float _x, float _y, float _diameter, float _speed) {
x = _x;
y = _y;
diameter = _diameter;
speed = _speed;
}

void move() {
y += speed;
if ((y > (height – diameter / 2)) || (y < diameter / 2)) {
speed *= -1;
}
}

void display() {
fill(31,127,255,63);
ellipse(x, y, diameter, diameter);
}
}
[/code]

より複雑な動きを作成する

  • Spotクラスの再設計
  • 円は上下だけでなく、左右にも移動するように変更

  • Spotクラスの再設計
  • 必要となる属性
    • x座標、y座標 → float x, y;
    • x方向の速度、y方向の速度 → float vx, vy;
    • 大きさ → float diameter
  • 必要となるメソッド
    • コンストラクタ → Spot
    • 座標の更新 → update
    • 画面に表示 → display
  • Spotクラス、クラス図を作成

– 設計したクラスをもとにプログラムを作成

[code language=”java”]
int numSpots = 400;

Spot[] spots = new Spot[numSpots];

void setup() {
size(800, 600);
noStroke();
smooth();
frameRate(60);
for (int i = 0; i < spots.length; i++) {
color col = color(random(255),random(255),random(255),63);
spots[i] = new Spot(random(0,width), height/2, random(5,40), random(-4,4),col);
}
background(0);
}

void draw() {
fill(0,0,0,10);
rect(0, 0, width, height);
fill(255);
for (int i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].display();
}
}

class Spot {
float x, y;
float diameter;
float speed;
color col;

Spot(float _x, float _y, float _diameter, float _speed, color _col) {
x = _x;
y = _y;
diameter = _diameter;
speed = _speed;
col = _col;
}

void move() {
y += speed;
if ((y > (height – diameter / 2)) || (y < diameter / 2)) {
speed *= -1;
}
}

void display() {
fill(col);
ellipse(x, y, diameter, diameter);
}
}
[/code]

  • 完成した動き

クラスの継承:重力を付加

  • さらにリアルな動きを追求してみる
  • 重力の概念を適用してみる
  • 移動中は、常に重力の影響を受けつづける

  • Spotクラスはそのままで、継承を使用してクラスを拡張する
  • 親クラスの性質を引き継いで、別の性質を付加した子クラスを生成
  • Spotクラス (親クラス)
    • 上下左右に移動する円
    • 画面の端でバウンドする
  • GravitySpot (子クラス)
    • Spotクラスを継承
    • つねに一定の重力の影響を受け続ける – 重力 → float gravity
  • クラスを継承する際の、クラス定義のやりかた
    • 何のクラスを継承したかを記述する
    • class 子クラス extends 親クラス {….}
    • 例:GravitySpotクラスが、Spotクラスを継承する場合
      • class GravitySpot extends Spot {…}
  • 子クラスから、親クラスのコンストラクタを呼びだす方法
    • super(引数1, 引数2, 引数3…);
    • 例:GravitySpotからSpotのコンストラクタを設定
      • super(_x, _y, _vx, _vy, _diameter);
  • 子クラスから親クラスのメソッドを呼び出す
    • super.メソッド名(引数1, 引数2, 引数3…);
    • 例:GravitySpotからSpotのmove()を呼び出す
      • super.move();

  • 設計したクラスをもとにプログラムを作成

[code language=”java”]
int numSpots = 400;

GravitySpot[] spots = new GravitySpot[numSpots];

void setup() {
size(800, 600);
noStroke();
smooth();
frameRate(60);
for (int i = 0; i < spots.length; i++) {
spots[i] = new GravitySpot(width/2,height/4,random(-4,4),random(-4,4),random(2,20));
}
background(0);
}

void draw() {
fill(0,0,0,10);
rect(0, 0, width, height);
fill(51,127,255,63);
for (int i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].display();
}
}

class Spot {
float x, y;
float diameter;
float vx;
float vy;

Spot(float _x, float _y, float _vx, float _vy, float _diameter) {
x = _x;
y = _y;
vx = _vx;
vy = _vy;
diameter = _diameter;
}

void move() {
x += vx;
if ((x > (width – diameter / 2)) || (x < diameter / 2)) {
vx *= -1;
}
x = constrain(x, diameter/2, width – diameter/2);

y += vy;
if ((y > (height – diameter / 2)) || (y < diameter / 2)) {
vy *= -1;
}
y = constrain(y, diameter/2, height – diameter/2);

}

void display() {
ellipse(x, y, diameter, diameter);
}
}

class GravitySpot extends Spot{
float gravity = 0.1;
GravitySpot(float _x, float _y, float _vx, float _vy, float _diameter){
super(_x, _y, _vx, _vy, _diameter);
}

void move(){
vy += gravity;
super.move();
}

void display(){
super.display();
}
}
[/code]

クラスの継承2:摩擦力を付加

  • 重力の概念に加えて、摩擦力の概念を加える
    • 摩擦 → 移動方向と反対方向にかかる力、空気抵抗など
    • 移動中は、重力に加えて常に摩擦力が働くようにする

  • 改良版、GravitySpot
    • 重力 (gravity) に加えて、摩擦力 (friction) を付加
    • x, y方向のスピードそれぞれに一定の値をかけ算する
    • frictoin ≦ 1.0;
    • frictionが1.0のときは摩擦なし
    • 値が小さくなるほど、大きな摩擦力が働く
  • 摩擦(friction)をGravitySpotのプロパティに追加

  • 設計したクラスをもとにプログラムを作成

[code language=”java”]
int numSpots = 400;

GravitySpot[] spots = new GravitySpot[numSpots];

void setup() {
size(800, 600);
noStroke();
smooth();
frameRate(60);
for (int i = 0; i < spots.length; i++) {
spots[i] = new GravitySpot(width/2,height/4,random(-20,20),random(-20,20),random(2,20));
}
background(0);
}

void draw() {
fill(0,0,0,10);
rect(0, 0, width, height);
fill(51,127,255,63);
for (int i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].display();
}
}

class Spot {
float x, y;
float diameter;
float vx;
float vy;

//コンストラクター
Spot(float _x, float _y, float _vx, float _vy, float _diameter) {
x = _x;
y = _y;
vx = _vx;
vy = _vy;
diameter = _diameter;
}

void move() {
x += vx;
if ((x > (width – diameter / 2)) || (x < diameter / 2)) {
vx *= -1;
}
x = constrain(x, diameter/2, width – diameter/2);

y += vy;
if ((y > (height – diameter / 2)) || (y < diameter / 2)) {
vy *= -1;
}
y = constrain(y, diameter/2, height – diameter/2);

}
void display() {
ellipse(x, y, diameter, diameter);
}
}

class GravitySpot extends Spot{
float gravity = 0.1;
float friction = 0.995;
GravitySpot(float _x, float _y, float _vx, float _vy, float _diameter){
super(_x, _y, _vx, _vy, _diameter);
}

void move(){
vy += gravity;
vx *= friction;
vy *= friction;
super.move();
}

void display(){
super.display();
}
}
[/code]

重力と摩擦力を付加した動き (摩擦力 = 0.995)

クラスの継承3:色を指定

  • さらに色を指定できるようにする
  • GravitySpotのプロパティーに色の情報を追加 → color col

  • 設計したクラスをもとにプログラムを作成

[code language=”java”]
int numSpots = 400;
GravitySpot[] spots = new GravitySpot[numSpots];

void setup() {
size(800, 600);
colorMode(HSB, 360, 100, 100, 100);
noStroke();
smooth();
frameRate(60);
for (int i = 0; i < spots.length; i++) {
color col = color(random(120,240),80,80,50);
spots[i] = new GravitySpot(width/2,height/4,random(-10,10),random(-10,0),random(2,20),col);
}
background(0);
}

void draw() {
fill(0,0,0,10);
rect(0, 0, width, height);
fill(51,127,255,63);
for (int i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].display();
}
}

class Spot {
float x, y;
float diameter;
float vx;
float vy;

Spot(float _x, float _y, float _vx, float _vy, float _diameter) {
x = _x;
y = _y;
vx = _vx;
vy = _vy;
diameter = _diameter;
}

void move() {
x += vx;
if ((x > (width – diameter / 2)) || (x < diameter / 2)) {
vx *= -1;
}
x = constrain(x, diameter/2, width – diameter/2);

y += vy;
if ((y > (height – diameter / 2))) {
vy *= -1;
}
y = constrain(y, -height, height – diameter/2);

}
void display() {
ellipse(x, y, diameter, diameter);
}
}

class GravitySpot extends Spot{
float gravity = 0.1;
float friction = 0.998;
color col;
GravitySpot(float _x, float _y, float _vx, float _vy, float _diameter, color _col){
super(_x, _y, _vx, _vy, _diameter);
col = _col;
}

void move(){
vy += gravity;
vx *= friction;
vy *= friction;
super.move();
}

void display(){
fill(col);
super.display();
}
}
[/code]

  • 色を指定したバージョン