ターゲットへ障害物へ移動するには、ターゲットを避けた経路を計算し、
その経路に辿って動く必要があります。
前回作ったグラフが、その経路の指標となるものですが、
経路は別のものとして作ります。
加えて、経路を辿る行動を実装します。
実際に障害物を避けてターゲットへ移動する動きを実装するのは、
おそらく次くらいになると思います。
・経路クラス
class Path
{
std::list m_Path;
//たどるのに便利
std::list::iterator m_PathItr;
public:
Path(){}
//次のターゲットに移る
void SetNext(){ ++m_PathItr; }
//経路が終了していないか
bool ifFinish(){ return (m_PathItr == m_Path.end()); }
//ターゲットの座標を取得
Vec2D GetCurrentTarget(){ return *m_PathItr; }
//アクセサ
void SetPath(std::list& path)
{
m_Path = path;
m_PathItr = m_Path.begin();
}
};
つぎに、”経路を計算する”クラスを簡単に作ります。
あくまで試験的なもので、実際にターゲットへの経路を計算する機能はつけません。
class PathFinder
{
//各ユニットが独自のものをもつ
Unit* m_pUnit;
//グラフへのポインタ
Graph* m_pGraph;
public:
PathFinder(Unit* unit, Graph* graph)
:m_pUnit(unit), m_pGraph(graph)
{}
//成功=true、失敗=false
bool GetShortestPath(Vec2D target,
std::list& path/*これに経路を記録*/);
};
bool PathFinder::GetShortestPath(Vec2D target,
std::list& path)
{
path.push_back( Vec2D(100,400) );
path.push_back( Vec2D(200,300) );
path.push_back( Vec2D(300,400) );
path.push_back( target );
return true;
}
次に、経路を辿る行動を実装します。
行動ですから、MotionManagerの関数です。
//経路探索において、中継点と十分近づいたと判断する数値
const double FOLLOW_PATH_MIN_DIST = 4.0;
Vec2D MotionManager::FollowPath()
{
if(m_Path->ifFinish()) return Vec2D();
Vec2D dist = m_Path->GetCurrentTarget() - m_pUnit->Pos();
if(dist.LengthSQ() SetNext();
}
if(!m_Path->ifFinish())
//中継点へ向かう
return Go(m_Path->GetCurrentTarget());
else
return Vec2D();
}
あとは、クリックした際に、直接そこへ向かっていたのを、
経路を計算して、その経路を辿るようにします。
これは、ステートマシーンを弄る必要があります。
bool STATE_Global::HandleMesssage(Unit* owner, Message& message)
{
switch(message.m_Order)
{
case GO_AHEAD:
//座標を得る
Vec2D* target = (Vec2D*)message.m_Info;
//ターゲットを設定
owner->getMotionManager()->SetTarget(*target);
//ターゲットまでの経路を求める
std::list path;
owner->getPathFinder()->GetShortestPath(*target, path);
owner->getMotionManager()->SetPath(path);
//ステートを変更
owner->ChangeState(new STATE_GoAhead);
return true;
}
return false;
}
次に、移動する関数を、経路を辿って移動するようにします。
これは簡単で、さっきの”FollowPath”の行動をOnにするだけです。
void STATE_GoAhead::Enter(Unit* owner)
{
// owner->getMotionManager()->flag_Go.ON();
owner->getMotionManager()->flag_FollowPath.ON();
//ユニットの行動を止める。
owner->Stop();
}
ゲーム画面:
[youtube][/youtube]