『navigation_astar』 デモプロジェクトを読む #1
(注)解説記事ではなくただの私的メモです。
godot公式がリンクしてる2D用のデモプロジェクトを読んで勉強。
こちら(github)▶︎https://github.com/godotengine/godot-demo-projects/tree/master/2d
このなかから今回は「navigation_astar」というのを見てみました。
DL場所 ▶︎ github /Godot Asset Library
わからないところは公式のリファレンスとかyoutube動画、あとはchatGPTに聞いたりして確認してます。
↓こういう感じのやつ
●ファイル
●シーン
メインgame.tscnのみ。
●スクリプト
【character.gd】と【pathfind_astar.gd】
【character.gd】
〈メソッド〉
_ready
_process
_unhandled_input
_move_to
_change_state
【処理概要】
①クリックで移動目標地点を決定/ ②タイルマップを使って経路を計算 /③キャラクターが目標地点に向かって移動/ ④移動が完了すると停止
〈メモ〉
_ready
シーンツリーにノードが追加され、すべての子ノードがロードされたあとに一度だけ実行される。_init( )よりも後、_process( ) や _physics_process( ) よりも前に実行。
_process
スクリプトがアクティブである間に毎フレーム呼び出されるコールバック関数。ゲームオブジェクトの更新やリアルタイム動作に使われる。
enum State { IDLE, FOLLOW }
・列挙型enumを定義。キャラクターの状態 IDLE(待機) FOLLOW(移動)。
@onready
・godot4以降に導入されたアノテーション(コードの動作を変更したり、補助的な情報を与えたりするもの)。@onreadyをつけた変数は、ノードが準備完了(_ready()が実行されるタイミング)になったときに初期化される。
・godot3以前は「onready」が使われてて、4以降でプロジェクトを実行するとエラーになるので、昔のプロジェクトを実行するときは「@」を付け加える。
_click_position クリックした目的地
_path 移動経路
_next_point 現在の移動先
_unhandled_input(event) クリック時の処理
_move_to(local_position) 移動処理
「Steering Behavior」というゲームアルゴリズムが使われている。キャラクターが環境に適応しながら滑らかに移動するためのアルゴリズム。単純な直線運動じゃなくリアルな動きを表現できる。
Steering Behaiviorの特徴「物理的な慣性を考慮・ターゲットに向かって自然に移動・障害物を避ける/追跡する/回避するなどの動作」
1 目標地点に向かう理想の速度 desired_velocityを計算
var desired_velocity = (local_position - position).normalized() * speed
・(local_position - position) 現在位置から目標位置への方向ベクトル
・.normalized() ベクトルを単位ベクトル(長さ1)にする
・ * speed 目標の速度(speed = 200.0)を掛ける
2 現在の速度 _velocityとの差分(ステアリング)を求める
var steering = desired_velocity - _velocity
・_velocity はいまの移動速度
・desired_velocity - _velocityで「どのくらい方向を修正すべきか(=ステアリング)を求める
・いきなり目標速度にするのではなく、徐々に変化させるための計算
3 ステアリングを考慮して _velocity を更新
_velocity += steering / MASS
・MASS(質量)を調整することで、急激な加速や方向転換を防ぐ
・キャラクターの動きがスムーズになり、慣性が生まれる
4 位置を更新
position += _velocity * get_process_delta_time()
・_velocityにget_process_delta_time( ) (フレームごとの時間差)を掛けてフレームレートに依存しない移動を実現
5 キャラクターの向きを更新
rotation = _velocity.angle()
・移動方向にキャラクターの向きを合わせる
6 目標地点に到達したか確認
return position.distance_to(local_position) < ARRIVE_DISTANCE
・目標地点に十分近づいたら移動をとめる
_change_state(new_state) 状態の変更
【pathfind_astar.gd】
〈メソッド〉
_ready
_draw
round_local_position
is_point_walkable
clear_path
find_path
【処理概要】
① AStarGrid2D初期化、障害物設定/ ②経路計算/③キャラクターが通る道を視覚的に描画(航跡エフェクト)/④クリックで新しい経路を計算しキャラクターを移動
〈メモ〉
・character.gd(キャラクターの移動制御)と連携して、経路の計算をするスクリプト。
・AStarGrid2Dというgodot4で実装されたクラスを使用。
・AStarGrid2DはA*アルゴリズム(→wiki)というグラフ探索アルゴリズムを使用した、グリッドベースの経路探索を行うためのクラス。
・2Dタイルマップやグリッドベースのゲームで、最適なルート計算をするのに便利。
・NavigationAgent2Dとの違い
・グリッド移動が必要なら AStarGrid2D
・より自由な移動なら NavigationAganet2D
【処理詳細】
1 enum Tile{ OBSTACLE, START_POINT, END_POINT }
TileMap上のタイル識別に使用
Tile.OBSTACLE 障害物
Tile.START_POINT 経路の開始地点
Tile.END_POINT 経路の終点
2 定数の定義
3 変数初期化
4 _ready() astar(経路探索)の初期化
5 _draw() 経路を描画
_pathに探索済みの経路があれば線(draw_line)と円(draw_circle)を描画。経路を視覚的に確認できるようにする。
6 round_localposition( )
local_positonをタイルの中心に丸める(ローカル座標を最も近いグリッド位置にスナップする)
タイル単位で正確な移動ができるようにする
→キャラクターやオブジェクトの座標をマス目に揃えることで、綺麗に配置できる。
7 is_point_walkable( ) 指定位置が歩行可能かを判定
クリックした位置が経路探索エリア内 (is_in_boundsv()) であり、かつ
not _astar.is_point_solid(map_position)(通行可能)なら true を返す
8 clear_path( ) 経路をクリア
_path をクリア
タイルマップから 開始地点 (_start_point) と 終点 (_end_point) を削除
queue_redraw() で _draw() を再実行し、経路の描画を消す
9 find_path(): astarで経路探索
clear_path() で既存の経路を削除
開始地点 (_start_point) と 終点 (_end_point) を設定
astarを使って _path に経路を計算
_path が 空でなければ
開始地点と終点を TileMap に表示
queue_redraw() → _draw() を呼び出し 経路を描画
_path を duplicate() でコピーして返す(参照ではなく新しい配列を返す)
解説動画(あとで見る)
●AStarGrid2D
●Steering Behavior
Steering Behaviorの種類
このプロジェクトでは「Arrive(到達)」を実装してるけど、ほかに種類があるらしい。
Seek(追従) 目標地点に向かって一直線に進む
Flee(逃走) 目標地点から遠ざかる
Arrive(到達) 目標地点に近づくにつれて減速する
Pursue(予測追従) 相手の未来の位置を予測して追いかける
Evade(予測回避) 相手の未来の位置を予測して逃げる
Wander(ランダム移動) ランダムな方向に移動し続ける
Obstacle Avoidance(障害物回避) 障害物を避けながら進む