第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へ変えると、密度だけを比べられます。
16.timesを8.timesへ変えた版も、別名で保存して比べます。
数が少ない版では、一つずつの色や大きさへ目が向きます。多い版では、個体より群れ全体の密度が先に見えます。どちらが正しいかではなく、見せたい関係に合う数を選びます。
14.4 クラスを使わないほうが読みやすい場合
円が 2 個だけで、動きも 1 行なら、クラスは説明を増やすだけかもしれません。クラスを使う判断は、コード行数ではなく次の問いで考えます。
- その要素に関する値が複数の場所へ散らばっているか
- 更新、描画、判定を同じ対象の責任として読めるか
- 同じ種類の要素を複数作るか
- 新しい性質を足すたび、関係のない場所まで直しているか
小さくコピーして遊び、困ってから整理する順番でも遅くありません。次章では、個々の登場人物ではなく、作品全体がタイトル、実行中、終了という状態を持つ場合を扱います。
14.5 小作品「動きに性格を付ける」
点の性格を一語だけ選びます。たとえば「せっかち」「おくびょう」「のんびり」です。次の三つから二つを変え、性格が動きに見えるか試します。
@speedの範囲@sizeの範囲@redと@blueの範囲
性格を表す新しい命令はありません。速さ、大きさ、色という数値の組み合わせを、自分がどう読むかで意味が生まれます。同じクラスから作った点が全員同じである必要もありません。
この章の小さな区切り
Dot.newから複数の点を作れた- 同じクラスの点が別々の値を持つことを画面で確かめた
- 性格語を一つ選び、二つの数値範囲を変えた版を保存した
クラスが難しく感じたら、13章のハッシュ版を使い続けてもかまいません。作品が動いていて、また変えたい場所が分かれば先へ進めます。
14.6 Rubyそのものをもっと知るなら
描画から少し離れ、Rubyの仕組みを試す道もあります。Ruby公式ドキュメントでArrayやEnumerableを開くと、sample、select、reject以外にも、並べ替える、数える、変換するといったメソッドを見つけられます。
最初は新しい名前を一つだけ選び、短い配列で結果を確かめます。同じ点の集まりを配列とハッシュで書き比べる、ハッシュ版とクラス版を保存して読みやすさを比べる、描画を使わずRubyの式だけを試す、といった進み方もできます。難しい書き方へ進むことより、「この処理をRubyでは何と呼ぶのだろう」と自分で探せることが次の一歩です。