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の setupdrawmousePressed を同じエディタへ続けて足してから実行します。

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

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

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

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回呼び、位置もそれぞれ乱数で決めています。数を830へ変えると、密度だけを比べられます。

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

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

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

数が少ない版では、一つずつの色や大きさへ目が向きます。多い版では、個体より群れ全体の密度が先に見えます。どちらが正しいかではなく、見せたい関係に合う数を選びます。

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

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

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

小さくコピーして遊び、困ってから整理する順番でも遅くありません。次章では、個々の登場人物ではなく、作品全体がタイトル、実行中、終了という状態を持つ場合を扱います。

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

点の性格を一語だけ選びます。たとえば「せっかち」「おくびょう」「のんびり」です。次の三つから二つを変え、性格が動きに見えるか試します。

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

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

この章の小さな区切り

  • Dot.newから複数の点を作れた
  • 同じクラスの点が別々の値を持つことを画面で確かめた
  • 性格語を一つ選び、二つの数値範囲を変えた版を保存した

クラスが難しく感じたら、13章のハッシュ版を使い続けてもかまいません。作品が動いていて、また変えたい場所が分かれば先へ進めます。

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

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

最初は新しい名前を一つだけ選び、短い配列で結果を確かめます。同じ点の集まりを配列とハッシュで書き比べる、ハッシュ版とクラス版を保存して読みやすさを比べる、描画を使わずRubyの式だけを試す、といった進み方もできます。難しい書き方へ進むことより、「この処理をRubyでは何と呼ぶのだろう」と自分で探せることが次の一歩です。

参考資料