2023-08-28
PathFinding.dartパッケージを使うとマップないの 2 点間の道順を計算することができます。 これは Flame の機能ではありませんが、ゲームでよく使われると思うので紹介します。 (タップした場所まで障害物を避けつつ移動する場合など)
Grid
でマップを準備して、AStarFinder
かJumpPointFinder
でパスを計算します。
まずpubspec.yaml
にpathfinding
パッケージを追加します。
pathfinding: ^3.0.1
あとはコードを書いていきます。
横 10 マス、縦 10 マスのマップ(_cells
)を作ります。初期値は全部道である 0 で埋めています。
static const _rows = 20;
static const _cols = 10;
final _cells = List<List<int>>.generate(
_rows,
(_) => List<int>.generate(_cols, (_) => 0),
);
final _path = <Vector2>[];
ランダムで壁を作るために 1 にします。 また壁以外の点からランダムでスタート、ゴールを選びます。
for (var i = 0; i < _rows; i++) {
for (var j = 0; j < _cols; j++) {
if (_random.nextInt(10) == 0) {
_cells[i][j] = 1;
}
}
}
Vector2? start;
Vector2? goal;
while (start == null || goal == null) {
final i = _random.nextInt(_rows);
final j = _random.nextInt(_cols);
if (_cells[i][j] == 0) {
if (start == null) {
start = Vector2(j.toDouble(), i.toDouble());
} else {
goal = Vector2(j.toDouble(), i.toDouble());
}
}
}
次が pathfinding の本番です。 用意したマップ、スタート、ゴールからパスを見つけます。
final grid = Grid(_cols, _rows, _cells);
final finder = AStarFinder();
final found = finder.findPath(
start.x.toInt(),
start.y.toInt(),
goal.x.toInt(),
goal.y.toInt(),
grid,
);
for (final point in found) {
_path.add(Vector2(point[0], point[1]));
}
最後に render で画面に表示します。 道は白、壁はグレー、スタートは緑、ゴールは赤、パスを青で描画します。
void render(Canvas canvas) {
super.render(canvas);
final cellSize = Vector2.all(20);
for (var i = 0; i < _rows; i++) {
for (var j = 0; j < _cols; j++) {
canvas.drawRect(
Rect.fromLTWH(
(j + 1) * cellSize.x,
(i + 1) * cellSize.y,
cellSize.x,
cellSize.y,
),
Paint()..color = _cells[i][j] == 0 ? Colors.white : Colors.grey,
);
}
}
for (var i = 0; i < _path.length; i++) {
final point = _path[i];
final color = i == 0
? Colors.green
: i == _path.length - 1
? Colors.red
: Colors.blue;
canvas.drawRect(
Rect.fromLTWH(
(point.x + 1) * cellSize.x,
(point.y + 1) * cellSize.y,
cellSize.x,
cellSize.y,
),
Paint()..color = color,
);
}
}
このようにしてパスファインディングを実装できます。
© 2023 tnantoka