地図/探索/エージェントAI

仲間を見て、障害物を避ける

判断の相手は一つとは限らない。群れにすると、各自が近所の仲間だけを見て、離れ・揃え・寄る、の三つを同時にやる。誰も全体を指揮していないのに、群れのうねりが立つ。

boids は Craig Reynolds が 1986 年に発表した群れのモデル。各個体が近傍だけを見て三つの操舵を合成する。分離(separation)は近所から離れる向き、整列(alignment)は近所の平均速度へ寄る向き、結合(cohesion)は近所の重心へ寄る向き。三本それぞれが小さな操舵力を返し、重みつきで足して一つの向きにする。振る舞いを「向きを返す関数」として揃えると、seek や壁回避も同じ足し算に乗せられ、いくつでも合成できる。ステアリング・ビヘイビアの設計はこの足し算で組む。

boids の三規則は、それぞれが小さな操舵力を返す。分離は近所から離れる向き、整列は近所の平均速度へ寄る向き、結合は近所の重心へ寄る向き。三つの力を重みつきで足し合わせて、ひとつの操舵にする。標的を追う seek も、壁を避ける力も、同じ「向きを返す関数」として扱えば合成できる。

障害物回避もこの足し算の一員。seek だけの一匹を置く。下から円の向こうの標的へ向かわせると、まっすぐ進んで円に突っ込む。標的しか見ていないので、間にあるものが目に入らない。

円を横切って、構わず標的まで行ってしまう。衝突を避けるには、進む先に何かあるかを点自身に確かめさせる。前方へ短い触角を一本伸ばす。速度の向きへ ahead だけ進んだ点が、触角の先になる。

// 速度の向きへ ahead だけ伸ばした点 = 触角の先
const sp = Math.hypot(a.vx, a.vy) || 1
const px = a.x + (a.vx / sp) * ahead
const py = a.y + (a.vy / sp) * ahead

この先端が障害物の円に入っていれば、このまま進むと当たる。入っているかは中心からの距離で分かる。od < obstacle.r なら触角が円に食い込んでいる。

入っていたら、横へ逃げる力を seek に足す。逃げる向きは、障害物の中心から触角先へ向かう向き。この向きが円の表面を押しのける方向になる。

// 中心 → 触角先 の向きへ押す = 円から離れる向き
fx += (ox / od) * maxForce * 2.2
fy += (oy / od) * maxForce * 2.2

seek の fx, fy に足し込む。標的へ行く力と、円から離れる力。二つを混ぜた合力が、避けながら向かう動きになる。下が全部乗せ。触角が円に入ると線が濃くなる。

触角の先が円に入ると線が濃くなって、横へ押す力が立つ。点は壁に当たる前に膨らんで回り込み、抜けたらまた標的へまっすぐ戻る。触角の長さ ahead を伸ばすと早めに反応して大回りになり、短くすると壁ギリギリで急ハンドルを切る。回避と seek を足し算で混ぜているだけで、避けながら向かう、という二つの向きが同時に成り立つ。