501.オーバーライドの応用

super()を使った親メソッドの呼び出しと、多段継承の実践例です。

p5.js oop
Learning OOP Object Oriented Programming

OOPの応用編!オーバーライドとsuperの活用方法を学びます。

クラス構造

AbstractShape
├── Circle (基本的な円)
└── AbstractNewShape (拡張ベース)
    ├── ColoredCircle (色付き円)
    └── Rect (色・サイズ変更する四角)

super()の使い方

class AbstractNewShape extends AbstractShape {
  constructor(c = 0, size = 10) {
    super();  // 親のconstructorを呼ぶ
    this.c = c;
    this.size = size;
  }

  update() {
    super.update();  // 親のupdateを呼ぶ
    this.c = (this.c + 1) % 360;  // 追加の処理
  }
}

init()メソッドのオーバーライド

class Rect extends AbstractNewShape {
  init() {
    this.b = 0;  // 追加のプロパティ
  }
}

学んだこと

  • super(): 親クラスのメソッドを呼び出す
  • オーバーライド: 親のメソッドを上書きする
  • 多段継承: 複数階層の継承
  • 機能の追加と拡張のバランス

これでOOP学習シリーズは完了です!


← 最初から復習する 101.変数ベースの単一キャラ

View Source Code

let W, H, PW, PH;
const PADDING_RATIO = 0.2;
const MAX_SPEED = 10;

let objs = [];

const MAX = 100;

class AbstractShape {
  constructor() {
    this.pos = {
      x: random(width),
      y: random(height),
    };
    this.speed = {
      x: (Math.random() - 0.5) * MAX_SPEED,
      y: (Math.random() - 0.5) * MAX_SPEED,
    };
    this.acceleration = 0.1;
    
    this.t = 0
    
    this.init()
  }
  
  init() {
  }

  update() {
    this.t++;
    
    this.pos.x += this.speed.x;
    this.pos.y += this.speed.y;

    if (this.pos.x < 0 + PW) {
      this.speed.x += this.acceleration;
    } else if (this.pos.x > W - PW) {
      this.speed.x -= this.acceleration;
    }

    if (this.pos.y < 0 + PH) {
      this.speed.y += this.acceleration;
    } else if (this.pos.y > H - PH) {
      this.speed.y -= this.acceleration;
    }
  }

  display() {
    // implement in subclass
  }
}

class AbstractNewShape extends AbstractShape {
  constructor(c = 0, size = 10) {
    super();
    this.c = c;    
    this.size = size
  }

  update() {
    super.update();
    this.c = (this.c + 1) % 360;
  }
}

class Circle extends AbstractShape {
  display() {
    stroke(0);
    fill(0);
    ellipse(this.pos.x, this.pos.y, 10, 10);
    // text(["1:", Math.floor(this.pos.x), Math.floor(this.pos.y)], this.pos.x + 10, this.pos.y + 10);
  }
}

class ColoredCircle extends AbstractNewShape {
  display() {
    push();
    {
      colorMode(HSB);
      stroke(this.c, 100, 100);
      fill(this.c, 100, 100);
      ellipse(this.pos.x, this.pos.y, 10, 10);
      // text(["1c:", Math.floor(this.pos.x), Math.floor(this.pos.y)], this.pos.x + 10, this.pos.y + 10);
    }
    pop();
  }
}

class Rect extends AbstractNewShape {
  init() {
    this.b = 0
  }
  
  update() {
    super.update()
    this.b = cos(radians(this.t)) * 32 + 68
  }
  
  display() {
    push();
    {
      colorMode(HSB);
      stroke(this.c, 100, this.b);
      fill(this.c, 100, this.b);
    rectMode(CENTER);
    rect(this.pos.x, this.pos.y, this.size, this.size);
    // text(["2:", Math.floor(this.pos.x), Math.floor(this.pos.y)], this.pos.x + 20, this.pos.y + 20);
    }
    pop()
  }
}

// main

function setup() {
  createCanvas((W = windowWidth), (H = windowHeight));
  PW = W * PADDING_RATIO;
  PH = H * PADDING_RATIO;

  for (let i = 0; i < MAX; i++) {
    const shapeType = Math.floor(Math.random() * 3);
    switch (shapeType) {
      case 0:
        objs.push(new Circle());
        break;
      case 1:
        objs.push(new ColoredCircle(Math.floor(Math.random() * 360)));
        break;
      case 2:
        objs.push(
          new Rect(
            Math.floor(Math.random() * 360),
            Math.floor(Math.random() * 100 + 10)
          )
        );
        break;
    }
  }
}

function draw() {
  background(255);

  for (let i = 0; i < objs.length; i++) {
    const obj = objs[i];
    obj.update();
  }

  for (let i = 0; i < objs.length; i++) {
    const obj = objs[i];
    obj.display();
  }
}