なのでSlick2Dを使ってゲームを作っています。(他のゲームと同様に) TiledMap とエンティティがあり、A* を使用する方法が必要です。説明が見つからないので使い方がよくわかりません。
Slick を使用していない人のために説明すると、私が使用する AStarPathFinding クラスと TiledMap クラスが既に含まれています。
なのでSlick2Dを使ってゲームを作っています。(他のゲームと同様に) TiledMap とエンティティがあり、A* を使用する方法が必要です。説明が見つからないので使い方がよくわかりません。
Slick を使用していない人のために説明すると、私が使用する AStarPathFinding クラスと TiledMap クラスが既に含まれています。
これは、Slick2D での A スター パス検索がどのように機能するかの簡単な例です。TileBasedMap
実際のゲームでは、ゲームが使用するマップ構造のアクセシビリティを実際に検索する、より現実的なインターフェースの実装がおそらくあるでしょう。マップの地形などに基づいて異なるコストを返すこともできます。
import org.newdawn.slick.util.pathfinding.AStarPathFinder;
import org.newdawn.slick.util.pathfinding.Mover;
import org.newdawn.slick.util.pathfinding.Path;
import org.newdawn.slick.util.pathfinding.PathFindingContext;
import org.newdawn.slick.util.pathfinding.TileBasedMap;
public class AStarTest {
private static final int MAX_PATH_LENGTH = 100;
private static final int START_X = 1;
private static final int START_Y = 1;
private static final int GOAL_X = 1;
private static final int GOAL_Y = 6;
public static void main(String[] args) {
SimpleMap map = new SimpleMap();
AStarPathFinder pathFinder = new AStarPathFinder(map, MAX_PATH_LENGTH, false);
Path path = pathFinder.findPath(null, START_X, START_Y, GOAL_X, GOAL_Y);
int length = path.getLength();
System.out.println("Found path of length: " + length + ".");
for(int i = 0; i < length; i++) {
System.out.println("Move to: " + path.getX(i) + "," + path.getY(i) + ".");
}
}
}
class SimpleMap implements TileBasedMap {
private static final int WIDTH = 10;
private static final int HEIGHT = 10;
private static final int[][] MAP = {
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,1,1,1,1},
{1,0,1,1,1,0,1,1,1,1},
{1,0,1,1,1,0,0,0,1,1},
{1,0,0,0,1,1,1,0,1,1},
{1,1,1,0,1,1,1,0,0,0},
{1,0,1,0,0,0,0,0,1,0},
{1,0,1,1,1,1,1,1,1,0},
{1,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,0}
};
@Override
public boolean blocked(PathFindingContext ctx, int x, int y) {
return MAP[y][x] != 0;
}
@Override
public float getCost(PathFindingContext ctx, int x, int y) {
return 1.0f;
}
@Override
public int getHeightInTiles() {
return HEIGHT;
}
@Override
public int getWidthInTiles() {
return WIDTH;
}
@Override
public void pathFinderVisited(int x, int y) {}
}
あなたのゲームでは、パス検索文字クラスにインターフェイスを実装させて、呼び出しMover
の代わりにユーザー データ オブジェクトとして渡すことができるようにすることもできます。これにより、およびメソッドから を介してそのオブジェクトを使用できるようになります。そうすれば、ブロックや障害物などを無視するいくつかのムーバーを作成できます (水の中やブロックしている壁の上を移動できる空飛ぶキャラクターや水陸両用車を想像してください)。null
findPath
blocked
cost
ctx.getMover()
編集TiledMap
クラス
を使用していることに具体的に言及したことに気付きました。このクラスはTileBasedMap
インターフェースを実装しておらず、Slick2D の A-star 実装で直接使用することはできません。(タイル マップには、既定では、パス検索を実行するときに重要なブロックの概念がありません。) したがって、タイルがブロックされているかどうか、およびコストがどれくらいかについて、独自の基準を使用して、これを自分で実装する必要があります。それらを横断します。
編集2
タイルがブロックされているという概念を定義するには、いくつかの方法があります。比較的簡単な方法をいくつか以下に示します。
タイル マップ形式では、複数のレイヤーを指定できます。1 つのレイヤーをブロッキング タイル専用にして、次のTileBasedMap
ように実装することができます。
class LayerBasedMap implements TileBasedMap {
private TiledMap map;
private int blockingLayerId;
public LayerBasedMap(TiledMap map, int blockingLayerId) {
this.map = map;
this.blockingLayerId = blockingLayerId;
}
@Override
public boolean blocked(PathFindingContext ctx, int x, int y) {
return map.getTileId(x, y, blockingLayerId) != 0;
}
@Override
public float getCost(PathFindingContext ctx, int x, int y) {
return 1.0f;
}
@Override
public int getHeightInTiles() {
return map.getHeight();
}
@Override
public int getWidthInTiles() {
return map.getWidth();
}
@Override
public void pathFinderVisited(int arg0, int arg1) {}
}
タイル マップ形式では、各タイル タイプにオプションでユーザー定義のプロパティを設定できます。blocking
ブロックしているはずのタイルにプロパティを簡単に追加し、TileBasedMap
実装でそれを確認できます。例えば:
class PropertyBasedMap implements TileBasedMap {
private TiledMap map;
private String blockingPropertyName;
public PropertyBasedMap(TiledMap map, String blockingPropertyName) {
this.map = map;
this.blockingPropertyName = blockingPropertyName;
}
@Override
public boolean blocked(PathFindingContext ctx, int x, int y) {
// NOTE: Using getTileProperty like this is slow. You should instead cache the results.
// For example, set up a HashSet<Integer> that contains all of the blocking tile ids.
return map.getTileProperty(map.getTileId(x, y, 0), blockingPropertyName, "false").equals("true");
}
@Override
public float getCost(PathFindingContext ctx, int x, int y) {
return 1.0f;
}
@Override
public int getHeightInTiles() {
return map.getHeight();
}
@Override
public int getWidthInTiles() {
return map.getWidth();
}
@Override
public void pathFinderVisited(int arg0, int arg1) {}
}
他にも多くのオプションがあります。たとえば、レイヤ ID をブロッキングとして設定する代わりに、レイヤ自体のプロパティを設定して、それがブロッキング レイヤであるかどうかを示すことができます。
さらに、上記の例はすべて、ブロッキング タイルと非ブロッキングタイルを考慮しているだけです。もちろん、マップ上にブロック オブジェクトと非ブロック オブジェクトがある場合もあります。また、他のプレイヤーや NPC などがブロックしている可能性もあります。これらすべてを何らかの方法で処理する必要があります。ただし、これで開始できます。