失敗したけど捨ててしまうにはもったいないコードを投げておく場所が他に見つからなかったので、ここに供養しておきます。左右に曲がったりするコードと前方扇形を探索するコードを見ながら本を読んでいた時に思いついた物なのでそれらが混ざっていますが、コード的には分離されています。
結論としてはboidモデルにベクトルを導入しても自然な動きにはならないので、素直に角度を足し引きした方が良いと感じました。なんとなく眺めている分にはこれもいいだろうと思います。
ベクトル表現としてよりよい方法、或いは誤りがあればご教授願います。
以下書いたコード
Agt_Init{my.X = rnd()*50 my.Y = rnd() *50 my.Direction = rnd() *360 my.Speed = rnd()}
Agt_Step{
my._agtset_ = CircularSector(5, 150)
if countagtset(my._agtset_) then boidwalk() else rndwalk() end if
}
function CircularSector(_Distance_ as double,_FoV_ as double ) as agtset{dim agt_ as agt dim agtset_ as agtset dim agtset_return as agtset
MakeOneAgtSetAroundOwn(agtset_, _Distance_, SpecifyAgtType(my), False)
for each agt_ in agtset_
if abs(my.Direction - DirectionFromMe(agt_)/*=-180~180*/) <= _FoV_ then
addagt(agtset_return, agt_) end if next agt_
return agtset_return}
sub rndwalk(){ turn((int(rnd() *3)-1/*=-1,0,1*/) * 30/*=左右に曲がる角度*/) forward(my.Speed)}
// """本題のコード"""
sub boidwalk(){
dim Vektor(/*a*/3, /*b*/2) as double
dim i as integer dim j as integer for i = 0 to /*a-1*/2 for j = 0 to /*b-1*/1 Vektor(i,j) = 0 next j next i//初期化
for each agt_ in my._agtset_
//整理
Vektor(1, 0) = Vektor(1, 0) + DirectionToCos(agt_.Direction) * agt_.speed
Vektor(1, 1) = Vektor(1, 1) + DirectionToSin(agt_.Direction) * agt_.speed
//離散
Vektor(2, 0) = Vektor(2, 0) - DirectionToCos(DirectionFromMe(agt_)) * (1/DistanceFromMe(agt_))
Vektor(2, 1) = Vektor(2, 1) - DirectionToSin(DirectionFromMe(agt_ )) * (1/DistanceFromMe(agt_))
next agt_
for i = 1 to /*a-1*/2 for j = 0 to /*b-1*/1 /*平均=*/Vektor(i,j) = Vektor(i,j) / countagtset(my._agtset_) next j next i
//方向決定
Vektor(0,0)=(DirectionToCos(my.Direction) * my.Speed + Vektor(1,0) )/2 + Vektor(2,0)
Vektor(0,1)=(DirectionToSin(my.Direction) * my.Speed + Vektor(1,1) )/2 + Vektor(2,0)
my.Direction = GetDirection(0,0,Vektor(0,0),Vektor(0,1),getridespace(SpecifyAgtType(my)))
my.Speed = MeasureDistance(0,0,Vektor(0,0),Vektor(0,1),getridespace(SpecifyAgtType(my)))
forward(my.Speed)
}
function DirectionFromMe(agt_ as agt) as double{return GetDirection(my.X, my.Y, agt_.X, agt_.Y, getridespace(SpecifyAgtType(my)))}
function DistanceFromMe(agt_ as agt) as double{return MeasureDistance(my.X, my.Y, agt_.X, agt_.Y, getridespace(SpecifyAgtType(my)))}
function DirectionToCos(Direction_ as double) as double{return cos(DegreeToRad(Direction_)) }
function DirectionToSin(Direction_ as double) as double{return sin(DegreeToRad(Direction_)) }
※障害物への処理は全くされていませんが、挙動としては一度集まったものが簡単に分離するので面白味としては十分だろうと判断しています。
整列する角度が毎回同様になるのでなんらかのバグがあるような気がします。
サンプルモデルに組み込んでみました。
列に整列する様子が、鳥というよりは、違う生き物(蚊柱?)のようですね。