第5章 条件分岐が振る舞いを生む
第4章の円は、画面の外へ出ても進み続けました。端に着いたときだけ向きを変えるには、「もし端を越えたら」という条件が要ります。if は、値を見て次の行動を選ぶ仕組みです。
5.1 右端を越えたら左へ戻す
前章のコードへ 3 行を足します。
def setup
createCanvas(480, 240)
@x = 0
@speed = 3
end
def draw
background(245)
fill(235, 90, 120)
ellipse(@x, height / 2, 60, 60)
@x += @speed
if @x > width
@x = 0
end
end
@x > width は、円の中心がキャンバスの幅より右へ進んだかを比べています。条件が成り立つときだけ、@x = 0 が実行されます。
円の中心が右端を越えた直後に左へ戻るため、円の左半分がまだ画面内に見えるところで消えます。円が完全に画面外へ出てから戻したいなら、直前のコードの draw にある if 3 行を、次の変更部分と置き換えます。
radius = 30
if @x - radius > width
@x = -radius
end
形の中心だけでなく大きさも考えると、画面の外へ出た瞬間をより正確に表せます。
5.2 戻る動きと跳ね返る動き
左へ戻す代わりに、直前のコードの draw にある if を次の変更部分と置き換え、速度の符号を反転します。
if @x > width - 30
@speed *= -1
end
@speed *= -1 は、今の速度へ -1 を掛け、その結果を同じ変数へ入れる書き方です。右端で 3 は -3 になり、円は左へ進みます。しかし左端の条件がないため、そのまま消えます。
両端で跳ね返す前に、setup の @x = 0 を @x = 30 へ変えて実行します。半径が 30 の円が、左端に収まった位置から右へ出発します。初期位置を 0 のままにすると、次に足す左端の条件を最初から満たし、その場で向きが反転し続けてしまいます。
出発位置を確認したら、今入れた if 3 行を、次の変更部分と置き換えて両端を一つの条件にまとめます。
if @x > width - 30 || @x < 30
@speed *= -1
end
|| は「または」です。右端を越えた場合、または左端を越えた場合に速度を反転します。実行して、右端で左向きに、左端で右向きに変わるところまで見ます。左端で小さく揺れるだけなら、setup が @x = 30 になっているか確かめます。エラーが出たら、if をこの節の最初の 3 行へ戻して実行します。
5.3 条件だけでは端へめり込むことがある
速度を 25 のように大きくすると、円が端を越えてから反転し、少し不自然に揺れることがあります。1 フレームで境界を大きく飛び越えるためです。
直前の if 3 行を次の変更部分と置き換え、境界で位置を戻してから速度を反転すると安定します。
if @x > width - 30
@x = width - 30
@speed *= -1
elsif @x < 30
@x = 30
@speed *= -1
end
elsif は、最初の条件が成り立たなかった場合に、別の条件を調べます。右端と左端を別々に処理できました。
条件分岐を使うと、端を越えたときに戻る、跳ねる、消える、色が変わるといった振る舞いを選べます。
5.4 状態を色で見えるようにする
進む方向に応じて色を変えると、見えない速度の符号を観察できます。次の変更部分は、draw にある fill と ellipse の 2 行と置き換えます。
if @speed > 0
fill(235, 90, 120)
else
fill(50, 130, 230)
end
ellipse(@x, height / 2, 60, 60)
else は、それまでの条件がどれも成り立たなかった場合です。右向きなら赤、左向きなら青になります。
デバッグでは、内部の値を色や文字へ変えて表示すると原因を探しやすくなります。作品として残さなくても、見えない状態を一時的に見えるようにする考え方は今後も使います。
戻る動きと跳ね返る動きを同時に見る
二つの境界処理を同じ画面へ置くと、違いを見失いにくくなります。次はそれだけで実行できる完成コードです。上段の赤い円は右端を越えると左から現れ、下段の青い円は端で向きを変えます。
def setup
createCanvas(600, 260)
@wrap_x = 540
@bounce_x = 540
@bounce_speed = 4
end
def draw
background(245)
@wrap_x += 4
if @wrap_x > width + 30
@wrap_x = -30
end
@bounce_x += @bounce_speed
if @bounce_x > width - 30
@bounce_x = width - 30
@bounce_speed *= -1
elsif @bounce_x < 30
@bounce_x = 30
@bounce_speed *= -1
end
stroke(190)
line(0, 130, width, 130)
noStroke
fill(235, 90, 120)
ellipse(@wrap_x, 70, 60, 60)
fill(50, 130, 230)
ellipse(@bounce_x, 190, 60, 60)
end
どちらも同じ速さで右へ出発します。しかし、赤い円は位置を反対側へ移し、青い円は速度の正負を変えます。図では、赤い円が左へ戻ったあと、青い円が右端で跳ね返って左へ進んでいます。
5.5 自分で選ぶ境界の反応
次のうち一つだけ選び、円の端での反応を変えてみてください。難しさを三段階に分けています。
- そのままでできる: 跳ね返らず、反対側から現れる。5.1 のコードを使える
- ヒントあり: 端に触れるたび速くする。跳ね返す
ifの中へ@speed *= 1.1を足す - 挑戦: 端に触れるたび色を変える。
setupで色の変数を用意し、端のifで二つの色を交互に入れる - 挑戦: 端でしばらく止める。止まる残り時間を覚える変数が必要になるため、今は動きの案だけメモして先へ進んでもよい
まずは「そのままでできる」案を試します。ヒントの意味がまだ分からなければ、数字を変える案へ戻ります。条件を一つ加えると、円が端で見せる動きも変わります。
5.6 跳ね返るものに性格を付ける
端へ触れたときの反応で、登場するものの性格を表せます。たとえば、跳ね返る瞬間だけ目を大きくすると、円が驚いたように見えます。この変更には、目を大きくしておく残り時間を覚える変数が必要です。コードへ加えない場合は、変化する目の形を紙に描いて残せます。端で速度を半分にすると、今度は壁を警戒しているような動きになります。
最初は円の中へ目を 2 つ足します。「速い」「慎重」「端を無視して反対側へ抜ける」から、今の動きに合うものを選びます。
5.7 もっと自然な動きを探すなら
位置と速度に加えて、速度そのものを少しずつ変える値を持たせると、落下や加速のような動きになります。この値を加速度と呼びます。ほかにも、摩擦、重力、ばね、複数のものが集まって動く群れなど、動きから広がる題材があります。
「だんだん速くなる」「止まる前に少し滑る」「壁から離れるほど戻る力が強くなる」のうち、作りたい動きを言葉や矢印で描きます。その動きをコードにしたくなったときは、「加速度」「摩擦」「ばね」「ベクトル」が調べる手掛かりになります。
戻る版と跳ね返る版から、残したい動きを一つ保存します。次章では、同じ形を繰り返して模様を作ります。
参考資料
- Ruby 公式「制御構造」 —
if、elsif、elseによる条件分岐 - rbCanvas/p5 0.5.1 API リファレンス —
widthと図形の位置・大きさに使う機能