Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第14章 クラスで登場人物に個性を持たせる

第13章の点は、位置と速度をハッシュで持っていました。更新処理と描画処理が増えると、点に関するコードが draw の中へ集まりすぎます。クラスは、点が知っている値と、点ができることを一つの定義へまとめます。

14.1 一つの Dot を定義する

次のクラス定義は作品を構成する変更部分です。このあと14.2 の setup、draw、mousePressedを同じエディタへ続けて足してから実行します。

class Dot
  def initialize(x, y)
    @x = x
    @y = y
    @speed = random(0.5, 2.5)
    @size = random(16, 36)
  end

  def update
    @x += @speed
  end

  def display
    fill(255, 210, 100, 180)
    ellipse(@x, @y, @size, @size)
  end

  def outside?
    @x - @size / 2 > width
  end
end

initialize(イニシャライズ)は、Dot.new で新しいオブジェクトを作るときに呼ばれます。位置を引数で受け、速度と大きさを乱数で決めます。

outside? の末尾の疑問符は Ruby ではメソッド名の一部です。真偽値を返すメソッドに疑問符を付ける慣習があり、条件式で読みやすくなります。

14.2 配列がオブジェクトを持つ

def setup
  createCanvas(500, 300)
  @dots = []
end

def draw
  background(25, 30, 48)
  noStroke

  @dots.each do |dot|
    dot.update
    dot.display
  end

  @dots = @dots.reject do |dot|
    dot.outside?
  end
end

def mousePressed
  @dots.push(Dot.new(mouseX, mouseY))
end

配列はハッシュではなく Dot のオブジェクトを持ちます。呼び出す側は、位置がどの変数に入っているかを知る必要がありません。update で更新を、display で表示を頼みます。クラス側を draw という名前にすると、rbCanvas/p5 が自動で呼ぶトップレベルの draw と区別できない場合があるため、ここでは display と名付けます。

reject(リジェクト)は、条件に当てはまった要素を取り除いた新しい配列を返します。ここでは各 dot の outside? を呼び、画面の外へ出た点だけを取り除いています。処理を短く書く省略記法もありますが、最初は do から end までを見える形にしたほうが、何を調べているか追いやすくなります。

14.3 個性は同じクラスの初期値から生まれる

すべての点は同じ Dot クラスですが、速度と大きさが違います。個性を増やすため、色も持たせます。次の変更部分で、Dot クラス内の initialize と display をそれぞれ置き換えます。

def initialize(x, y)
  @x = x
  @y = y
  @speed = random(0.5, 2.5)
  @size = random(16, 36)
  @red = random(120, 255)
  @blue = random(80, 220)
end

def display
  fill(@red, 150, @blue, 180)
  ellipse(@x, @y, @size, @size)
end

同じクラスから作ったオブジェクトは、共通する性質と振る舞いを持ちながら、それぞれ別の値を持てます。

クリックを何度も繰り返さず、実行直後から違いを比べたい場合は、setup を次の変更部分と置き換えます。第7章で使った randomSeed が乱数の並びを固定するため、同じ初期配置をもう一度作れます。

def setup
  createCanvas(500, 300)
  randomSeed(14)
  @dots = []

  16.times do
    @dots.push(Dot.new(random(width), random(height)))
  end
end

16.times の中で Dot.new を 16 回呼び、位置もそれぞれ乱数で決めています。数を 8 や 30 へ変えると、密度だけを比べられます。

濃紺の 500×300 のキャンバスに、大きさと色の異なる半透明な点が散らばっている実行結果
図 14-1 同じ Dot クラスから作った点でも、それぞれ別の値を持つ。画面の右端から出た点は取り除かれる。

16.times を 8.times へ変えた版も、別名で保存して比べます。

濃紺の 500×300 のキャンバスに、16 個版より少ない半透明の点が離れて配置された実行結果
図 14-2 8 個で始めた版。移動中に右端を越えた点は reject で取り除かれ、余白がさらに広くなる。

数が少ない版では、一つずつの色や大きさへ目が向きます。多い版では、点の集まり全体が先に目へ入ります。どちらを残すかは、一つの点と集まりのどちらを目立たせたいかで決めます。

14.4 クラスを使わないほうが読みやすい場合

円が 2 個だけで、動きも 1 行なら、クラスは説明を増やすだけかもしれません。クラスを使う判断は、コード行数ではなく次の問いで考えます。

  • その要素に関する値が複数の場所へ散らばっているか
  • 更新、描画、判定を同じ対象の責任として読めるか
  • 同じ種類の要素を複数作るか
  • 新しい性質を足すたび、関係のない場所まで直しているか

小さな実験ではコードをコピーし、直す場所が増えてからクラスへまとめる順番でも進められます。

14.5 小作品「動きに性格を付ける」

点の性格を一語だけ選びます。たとえば「せっかち」「おくびょう」「のんびり」です。次の三つから一つを変えて実行し、そのあと必要なら二つ目を変えます。

  • @speed の範囲
  • @size の範囲
  • @red と @blue の範囲

性格を表す新しい命令はありません。速さ、大きさ、色という数値の組み合わせを、自分がどう読むかで意味が生まれます。同じクラスから作った点が全員同じである必要もありません。

クラスのコードを追いにくくなったら、第13章のハッシュ版と並べて見ます。作品が動き、次に変える行を見つけやすいほうを選びましょう。

14.6 Ruby そのものをもっと知るなら

描画から少し離れ、Ruby の仕組みを試す道もあります。Ruby 公式ドキュメントのArray やEnumerable を開くと、sample、select、reject 以外にも、並べ替える、数える、変換するといったメソッドを見つけられます。

最初は新しい名前を一つ選び、短い配列で結果を確かめます。同じ点の集まりを配列とハッシュで書き比べる、ハッシュ版とクラス版を保存して読みやすさを比べる、描画を使わず Ruby の式だけを試す、といった方法があります。

クラス版とハッシュ版のどちらで、次に変更する場所を早く見つけられたでしょうか。選んだ版を使い、次章では画面をタイトル、実行中、終了に分けます。

参考資料