yoppa.org


メディア芸術の基礎 2018 – 東京工科大学

第8回: クラスを継承する – Processing オブジェクト指向プログラミング入門2

前回に引き続き、Processingにおけるオブジェクト指向プログラミング(OOP)の方法について解説していきます。今回はOOPの重要な概念の一つである「継承 (インヘリタンス) 」について考えていきます。継承とは、既存クラスの機能構造を共有する新たなクラス(サブクラス)を派生させることです。サブクラスからは親となるクラスのプロパティやメソッドをそのまま引き継ぐことが可能です。この継承の仕組みを効果的に活用することで、既存のクラスを再利用しながらそこに新たな機能を加えていくということが可能となります。

次回までにやってくること

次回からは、新たな内容に入ります。これまではProcessingを用いて主に視覚的な表現を扱ってきました。次回からは、Sonic Piという開発環境を用いて音や音楽を扱います。

次回までに以下のサイトからSonic Piの最新版を使用しているOSにあわせてダウンロードし、インストールしておいてください。

スライド資料

サンプルプログラム

上下左右に動きまわる円 (基本テンプレート)

// Spotクラスを宣言
Spot spot;

void setup() {
  size(800, 600, P2D);
  noStroke();
  frameRate(60);
  //位置ベクトルをランダムに生成
  PVector loc = new PVector(width/2.0, height/2.0);
  //速度ベクトルをランダムに生成
  PVector vec = new PVector(random(-4, 4), random(-4, 4));
  //インスタンス化して配列に格納
  spot = new Spot(loc, vec, random(5, 30));
  //背景を黒に
  background(0);
}

void draw() {
  // 画面をフェードさせる
  blendMode(BLEND);
  fill(0, 0, 0, 10);
  rect(0, 0, width, height);
  // 色を加算合成に
  blendMode(ADD);
  // 円の色を設定
  fill(31, 127, 255, 127);
  // Spotクラスのmove()メソッドを呼び出す
  spot.move();
  // Spotクラスのdraw()メソッドを呼び出す
  spot.draw();
}

// Spotクラス
class Spot {
  // プロパティ
  PVector location; //位置 (ベクトル!)
  PVector velocity;   //速度 (ベクトル!)
  float diameter;   //直径

  // コンストラクター
  Spot(PVector _location, PVector _velocity, float _diameter) {
    location = _location;
    diameter = _diameter;
    velocity = _velocity;
  }
  // 移動
  void move() {
    //位置ベクトル + 速度ベクトル = 次フレーム位置ベクトル
    location.add(velocity);
    //左右の壁でバウンドさせる
    if (location.x < diameter / 2 || location.x > width - diameter / 2) {
      location.x = constrain(location.x, diameter/2, width - diameter / 2);
      velocity.x *= -1;
    }
    //上下の壁でバウンドさせる
    if (location.y < diameter / 2 || location.y > height - diameter / 2) {
      location.y = constrain(location.y, diameter/2, height - diameter / 2);
      velocity.y *= -1;
    }
  }
  // 描画
  void draw() {
    ellipse(location.x, location.y, diameter, diameter);
  }
}

クラスの配列 – 大量の物体を同時に動かす

// 物体の数
int numSpots = 400;
// Spotクラスを配列として宣言
Spot[] spots = new Spot[numSpots];

void setup() {
  size(800, 600, P2D);
  noStroke();
  frameRate(60);
  // 配列の数だけSpotクラスをインスタンス化
  for (int i = 0; i < spots.length; i++) {
    //位置ベクトルをランダムに生成
    PVector loc = new PVector(width/2.0, height/2.0);
    //速度ベクトルをランダムに生成
    PVector vec = new PVector(random(-4, 4), random(-4, 4));
    //インスタンス化して配列に格納
    spots[i] = new Spot(loc, vec, random(5, 30));
  }
  background(0);
}

void draw() {
  // 画面をフェードさせる
  blendMode(BLEND);
  fill(0, 0, 0, 10);
  rect(0, 0, width, height);
  // 色を加算合成に
  blendMode(ADD);
  // 円の色を設定
  fill(31, 127, 255, 63);
  for (int i = 0; i < spots.length; i++) {
    // Spotクラスのmove()メソッドを呼び出す
    spots[i].move();
    // Spotクラスのdraw()メソッドを呼び出す
    spots[i].draw();
  }
}

// Spotクラス
class Spot {
  // プロパティ
  PVector location; //位置 (ベクトル!)
  PVector velocity;   //速度 (ベクトル!)
  float diameter;   //直径

  // コンストラクター
  Spot(PVector _location, PVector _velocity, float _diameter) {
    location = _location;
    diameter = _diameter;
    velocity = _velocity;
  }
  // 移動
  void move() {
    //位置ベクトル + 速度ベクトル = 次フレーム位置ベクトル
    location.add(velocity);
    //左右の壁でバウンドさせる
    if (location.x < diameter / 2 || location.x > width - diameter / 2) {
      location.x = constrain(location.x, diameter/2, width - diameter / 2);
      velocity.x *= -1;
    }
    //上下の壁でバウンドさせる
    if (location.y < diameter / 2 || location.y > height - diameter / 2) {
      location.y = constrain(location.y, diameter/2, height - diameter / 2);
      velocity.y *= -1;
    }
  }
  // 描画
  void draw() {
    ellipse(location.x, location.y, diameter, diameter);
  }
}

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

// 物体の数
int numSpots = 400;
// Spotクラスを配列として宣言
GravitySpot[] spots = new GravitySpot[numSpots];

void setup() {
  size(800, 600, P2D);
  noStroke();
  frameRate(60);
  // 配列の数だけSpotクラスをインスタンス化
  for (int i = 0; i < spots.length; i++) {
    //位置ベクトルをランダムに生成
    PVector loc = new PVector(width/2.0, height/2.0);
    //速度ベクトルをランダムに生成
    PVector vec = new PVector(random(-4, 4), random(-4, 4), 1.0);
    //重力を0.1に設定
    float gravity = 0.1;
    //インスタンス化して配列に格納
    spots[i] = new GravitySpot(loc, vec, random(5, 30), gravity);
  }
  background(0);
}

void draw() {
  // 画面をフェードさせる
  blendMode(BLEND);
  fill(0, 0, 0, 10);
  rect(0, 0, width, height);
  // 色を加算合成に
  blendMode(ADD);
  // 円の色を設定
  fill(31, 127, 255, 63);
  for (int i = 0; i < spots.length; i++) {
    // Spotクラスのmove()メソッドを呼び出す
    spots[i].move();
    // Spotクラスのdraw()メソッドを呼び出す
    spots[i].draw();
  }
}

// Spotクラス
class Spot {
  // プロパティ
  PVector location; //位置 (ベクトル!)
  PVector velocity;   //速度 (ベクトル!)
  float diameter;   //直径

  // コンストラクター
  Spot(PVector _location, PVector _velocity, float _diameter) {
    location = _location;
    diameter = _diameter;
    velocity = _velocity;
  }
  // 移動
  void move() {
    //位置ベクトル + 速度ベクトル = 次フレーム位置ベクトル
    location.add(velocity);
    //左右の壁でバウンドさせる
    if (location.x < diameter / 2 || location.x > width - diameter / 2) {
      location.x = constrain(location.x, diameter/2, width - diameter / 2);
      velocity.x *= -1;
    }
    //上下の壁でバウンドさせる
    if (location.y < diameter / 2 || location.y > height - diameter / 2) {
      location.y = constrain(location.y, diameter/2, height - diameter / 2);
      velocity.y *= -1;
    }
  }
  // 描画
  void draw() {
    ellipse(location.x, location.y, diameter, diameter);
  }
}

//Spotを継承した、GravitySpot(重力を付加)
class GravitySpot extends Spot {
  float gravity; //重力

  //コンストラクター
  GravitySpot(PVector _location, PVector _velocity, float _diameter, float _gravity) {
    //Superクラス(Spotクラス)をインスタンス化
    super(_location, _velocity, _diameter);
    //重力を設定
    gravity = _gravity;
  }

  void move() {
    //速度に重力を付加
    velocity.y += gravity;
    //スーパークラスのmove()を呼び出し
    super.move();
  }

  void draw() {
    //スーパークラスのdraw()を呼び出し
    super.draw();
  }
}

クラスの継承 – 重力と摩擦力を付加

// 物体の数
int numSpots = 400;
// Spotクラスを配列として宣言
GravitySpot[] spots = new GravitySpot[numSpots];

void setup() {
  size(800, 600);
  noStroke();
  frameRate(60);
  // 配列の数だけSpotクラスをインスタンス化
  for (int i = 0; i < spots.length; i++) {
    //位置ベクトルをランダムに生成
    PVector loc = new PVector(width/2.0, height/2.0);
    //速度ベクトルをランダムに生成
    PVector vec = new PVector(random(-4, 4), random(-4, 4), 1.0);
    //円の大きさを5から30に
    float diameter = random(5, 30);
    //重力を0.1に設定
    float gravity = 0.1;
    //摩擦力を0.998に
    float friction = 0.998;
    //インスタンス化して配列に格納
    spots[i] = new GravitySpot(loc, vec, diameter, gravity, friction);
  }
  background(0);
}

void draw() {
  // 画面をフェードさせる
  blendMode(BLEND);
  fill(0, 0, 0, 10);
  rect(0, 0, width, height);
  // 色を加算合成に
  blendMode(ADD);
  // 円の色を設定
  fill(31, 127, 255, 63);
  for (int i = 0; i < spots.length; i++) {
    // Spotクラスのmove()メソッドを呼び出す
    spots[i].move();
    // Spotクラスのdraw()メソッドを呼び出す
    spots[i].draw();
  }
}

// Spotクラス
class Spot {
  // プロパティ
  PVector location; //位置 (ベクトル!)
  PVector velocity;   //速度 (ベクトル!)
  float diameter;   //直径

  // コンストラクター
  Spot(PVector _location, PVector _velocity, float _diameter) {
    location = _location;
    diameter = _diameter;
    velocity = _velocity;
  }
  // 移動
  void move() {
    //位置ベクトル + 速度ベクトル = 次フレーム位置ベクトル
    location.add(velocity);
    //左右の壁でバウンドさせる
    if (location.x < diameter / 2 || location.x > width - diameter / 2) {
      location.x = constrain(location.x, diameter/2, width - diameter / 2);
      velocity.x *= -1;
    }
    //上下の壁でバウンドさせる
    if (location.y < diameter / 2 || location.y > height - diameter / 2) {
      location.y = constrain(location.y, diameter/2, height - diameter / 2);
      velocity.y *= -1;
    }
  }
  // 描画
  void draw() {
    ellipse(location.x, location.y, diameter, diameter);
  }
}

//Spotを継承した、GravitySpot(重力と摩擦を付加)
class GravitySpot extends Spot {
  float gravity; //重力
  float friction; //摩擦力

  //コンストラクター
  GravitySpot(PVector _location,
    PVector _velocity,
    float _diameter,
    float _gravity,
    float _friction) {
    //Superクラス(Spotクラス)をインスタンス化
    super(_location, _velocity, _diameter);
    //重力を設定
    gravity = _gravity;
    //摩擦力を設定
    friction = _friction;
  }

  void move() {
    //速度に摩擦力を掛ける
    velocity.mult(friction);
    //速度に重力を付加
    velocity.y += gravity;
    //スーパークラスのmove()を呼び出し
    super.move();
  }

  void draw() {
    //スーパークラスのdraw()を呼び出し
    super.draw();
  }
}