第18回 – class 1 オブジェクト指向プログラミング


さて、前回でメソッドを学びました。
メソッドは処理をまとめて、柔軟に処理を行うために引数を使って変数に代入し、返り値を使って処理した結果をメインに戻します。

今回からはclassという機能を使っていきます。
classを使えば、所謂オブジェクト指向プログラミングが可能になるのですが、ここではオブジェクト指向とはなんぞや、というよりも、classを使うことで今までやってきた作業がこんなに楽になる、という例をお示しします。

跳ね返るボール

今まで学習してきた、if文、for loop、配列を使って、複数の、壁にぶつかって跳ね返る円を実装してみたいと思います。


int num = 5;
float[] x = new float[num];
float[] y = new float[num];
float[] addX = new float[num];
float[] addY = new float[num];


void setup() {

  size(800, 800);
  background(0);

  for (int i = 0; i<x.length; i++) {
    x[i] = random(width);
    y[i] = random(height);
    addX[i] = random(3);
    addY[i] = random(3);
  }
}

void draw() {
  background(0);
  for (int i = 0; i<x.length; i++) {

    ellipse(x[i], y[i], 25, 25);
    x[i] += addX[i];
    y[i] += addY[i];
    if (x[i] > width | x[i] < 0) {
      addX[i] *= -1;
    }

    if (y[i] > height | y[i] < 0) {
      addY[i] *= -1;
    }
  }
}

まず、これがclassの機能を使わずに作った、5個の円が移動して、壁にぶつかると跳ね返る、という簡単なプログラムです。
num = 5の部分を10にすると10個になります。実行中でなければ、そこを変える事で数は自由に増減出来ます。

簡単な、といいながら、そして実際そんなに難しい事をしていない筈なのに、とても複雑に見えます。
これは、沢山の変数が出てきて、しかもそれぞれに何をやっているかが不明瞭だからです。
パッと見て、これがどんなプログラムか言い当てるのは難しいでしょう。
しかも、実際に作品として作るプログラムはこれよりももっと複雑になっていきます。円が壁に跳ね返るだけのプログラムでは面白くないですからね。

そこで、この複雑さを解消するために、classという機能を使います。
まずは何も説明せずにclassを使って実装したバージョンをお見せします。

Ball[] balls = new Ball[5];

void setup() {

  size(800, 800);
  background(0);

  for (int i = 0; i<balls.length; i++) {
    float x = random(width);
    float y = random(height);
    float addX = random(3);
    float addY = random(3);
    balls[i] = new Ball(x, y, addX, addY, 25);
  }
}


void draw() {
  background(0);
  for (int i = 0; i<balls.length; i++) {
    balls[i].disp();
    balls[i].move();
  }
}


class Ball {

  float x, y, addX, addY, size;

  Ball(float _x, float _y, float _addX, float _addY, float _size) {
    x = _x;
    y = _y;
    addX = _addX;
    addY = _addY;
    size = _size;
  }

  void disp() {
    fill(255);
    ellipse(x, y, size, size);
  }

  void move() {

    x += addX;
    y += addY;
    if (x > width | x < 0) {
      addX *= -1;
    }
    if (y > height | y < 0) {
      addY *= -1;
    }
  }
}

class Ballという新しいブロックが作られていますが、drawの中やsetupの中、そして使用しているグローバル変数(setupの前に宣言する変数)の数がぐっと減って、しかもdrawの中で何が行われているか、簡単に把握できるようになりました。
balls[i].disp()は、円を表示させているのだし、balls[i].move()は、円を移動させているのです。

そして、例えばこのプログラムからballs[i].move()の行を消すと、ボールは動かなくなります。
この形式であれば、新しい機能を足しても、draw(){ }のループの中は複雑になりすぎずに済みそうです。
コード全体で見れば量は多くなってしまいましたが、classの中の仕組みを知れば、とても簡単に読めるようになった事、そして書けるようになったことが解るはずです。
class自体の構造は次回以降説明していきます。
今日はここまで!