第13章 配列が一つを群れに変える
円が一つなら、@x と @y で位置を覚えられます。100 個になると、@x1 から @x100 を作る方法は変更しにくくなります。配列は、同じ役割を持つ複数の値を順序付きでまとめます。
13.1 位置を一つの配列へ集める
def setup
createCanvas(500, 300)
@x_positions = [80, 160, 260, 390]
end
def draw
background(245)
fill(235, 90, 120)
@x_positions.each do |x|
ellipse(x, height / 2, 50, 50)
end
end
each(イーチ)は配列の要素を一つずつブロックへ渡します。配列へ値を足すと、同じ描画コードから円を増やせます。
13.2 x と y を組にするハッシュ
各要素が位置と速度を持つなら、値の意味を名前で表せるハッシュを使えます。
def setup
createCanvas(500, 300)
@dots = [
{ :x => 80, :y => 90, :speed => 1.2 },
{ :x => 160, :y => 170, :speed => 2.0 },
{ :x => 300, :y => 130, :speed => 0.8 }
]
end
各ハッシュには :x、:y、:speed というキーがあります。=> は、左側のキーと右側の値を結び付ける記号です。0.5.1 では、行を分けた省略記法が構文エラーになる組み合わせを実機で確認したため、この書き方へ揃えています。更新と描画を同じ反復で行います。次の draw は変更部分で、直前の setup の end より後ろへ足します。
def draw
background(25, 30, 48)
noStroke
@dots.each do |dot|
dot[:x] += dot[:speed]
dot[:x] = -20 if dot[:x] > width + 20
fill(255, 210, 100, 180)
ellipse(dot[:x], dot[:y], 24, 24)
end
end
3 つの点は同じ更新規則を持ちますが、初期位置と速度が違います。
13.3 push で実行中に増やす
クリックした場所へ点を追加します。次のイベントメソッドは変更部分で、draw の end より後ろへ足します。
def mousePressed
@dots.push({ :x => mouseX, :y => mouseY, :speed => random(0.5, 2.5) })
end
push(プッシュ)は配列の末尾へ要素を加えます。クリックのたび、現在位置と乱数の速度を持つ新しい点が生まれます。
rbCanvas/p5 0.5.1 では、push( の直後で改行すると、内容が正しくても unexpected token tSEMI という構文エラーになる場合があります。この例では、push へ渡すハッシュを同じ行に書いて避けています。
要素が増え続けると、描画処理も増え続けます。「記録を蓄積する」作品では増え続けること自体が表現になります。長く操作する作品では、上限を決めるか、古い要素を削除すると処理量を保てます。
13.4 select で残すものを選ぶ
画面の右端を越えた点を取り除きます。13.2では、右端を越えた点を左端へ戻す次の行があります。次のコードが、まず削除する変更部分です。
dot[:x] = -20 if dot[:x] > width + 20
折り返しを残したままでは、右端を越えた点がすぐ -20 へ戻り、取り除く対象がなくなります。削除したあと、次の変更部分を draw にある @dots.each の反復が終わった直後、draw 最後の end より前へ足します。
@dots = @dots.select do |dot|
dot[:x] <= width + 20
end
select(セレクト)は、ブロックの条件が成り立つ要素だけを集めた新しい配列を返します。ここでは「残す条件」を書いています。
描画中の配列から同時に要素を削除すると、反復の順番が分かりにくくなることがあります。更新が終わったあとで select し直すと、処理の段階が分かれます。
確認するときは、13.2 の三つの点をそのまま動かします。点が右端から完全に出ると配列から取り除かれ、左端からは戻りません。クリックで追加した点も同じ条件で取り除かれます。
13.5 色の候補から一つ選ぶ
配列には、位置だけでなく、作品で使う色の組み合わせも入れられます。
def setup
createCanvas(480, 320)
background(245)
noStroke
palette = [
[190, 45, 70],
[240, 150, 60],
[45, 105, 145],
[90, 55, 120]
]
6.times do |row|
9.times do |column|
chosen_color = palette.sample
fill(chosen_color[0], chosen_color[1], chosen_color[2])
ellipse(30 + column * 53, 28 + row * 53, 38, 38)
end
end
end
palette(パレット)は、絵に使う色をまとめた配列です。その中の各色も、赤、緑、青の 3 要素を持つ配列です。sample(サンプル)は、配列から要素を一つ選んで返す Ruby のメソッドです。chosen_color[0] は最初の赤、chosen_color[1] は次の緑、chosen_color[2] は最後の青を取り出します。角括弧の番号は 0 から始まります。
すべてを自由な乱数色にせず、先に選んだ 4 色からだけ使うことで、偶然が起きても作品全体の関係を保てます。色を一つ入れ替える、特定の行だけ候補を減らす、円を別の形へ変える、の順で敷き詰め模様を育てられます。
13.6 配列のハッシュからクラスへ移る境目
ハッシュは、少数の性質を持つ要素に向いています。点が「更新する」「描く」「端に出たか調べる」という複数の処理を持ち始めると、毎回ハッシュを渡すコードが散らばります。
点ごとのデータと更新・描画の処理を一緒に置きたくなったら、クラスを使えます。次章では、今の点をクラスへ移し、配列とハッシュで書いた版との違いを比べます。
13.7 小作品「記憶の一色」
13.5 の paletteにある四色から一色だけを、自分が覚えている場所や物の色へ置き換えます。「夕方の帰り道」「古いかばん」のように、その色へ短い名前を付け、記憶に近づくよう数字を少しずつ変えます。
実行するたび並びは変わりますが、候補にした 4 色だけが使われます。色を一つ入れ替えれば、次の実行からすべての模様へ反映されます。HTML に保存されるのは、色の候補と並べ方を決めるコードです。開き直すと sample が色を選び直すため、同じ並びにはなりません。今の並びも残したいときは、再実行する前に画面を画像として保存します。編集を続けるための HTML と、見返すための画像を両方残せます。
最初はクリックによる追加を省き、13.1 の四つの円だけを表示してもかまいません。今日残したい並びが決まったら、第14章で点ごとの動きと色をクラスへまとめます。
参考資料
- Ruby リファレンスマニュアル「Array」 —
push、sampleなど配列のメソッド - Ruby リファレンスマニュアル「Enumerable」 —
selectなど、要素を順に調べるメソッド - Ruby リファレンスマニュアル「Hash」 — 名前と値を組にして持つ方法