mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-07-04 15:27:30 +07:00
Added extremely basic path-finding algorithm
Added extremely basic path-finding algorithm Added accessor to Zone.flags
This commit is contained in:
@ -164,6 +164,7 @@ project(":core") {
|
||||
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
|
||||
compile "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
compile "com.badlogicgames.gdx:gdx-ai:1.8.+"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -3,11 +3,14 @@ package gdx.diablo.map;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.assets.AssetDescriptor;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Bits;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
@ -543,6 +546,11 @@ public class Map implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public GraphPath<MapUtils.Point2> path(Vector3 src, Vector3 dst) {
|
||||
//return new MapGraph(this).path(src, dst);
|
||||
return MapUtils.path(this, src, dst, new DefaultGraphPath<MapUtils.Point2>());
|
||||
}
|
||||
|
||||
static class Zone {
|
||||
static final Array<Entity> EMPTY_ARRAY = new Array<>(0);
|
||||
|
||||
@ -662,6 +670,14 @@ public class Map implements Disposable {
|
||||
return presets[(tx - this.tx) / gridSizeX][(ty - this.ty) / gridSizeY];
|
||||
}
|
||||
|
||||
public int flags(int x, int y) {
|
||||
x -= this.x;
|
||||
if (x < 0 || x > width ) return 0xFF;
|
||||
y -= this.y;
|
||||
if (y < 0 || y > height) return 0xFF;
|
||||
return flags[x][y] & 0xFF;
|
||||
}
|
||||
|
||||
void load(DT1s dt1s) {
|
||||
Preconditions.checkState(tiles == null, "tiles have already been loaded");
|
||||
tiles = new Tile[Map.MAX_LAYERS][][];
|
||||
|
@ -1,6 +1,7 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
@ -137,6 +138,22 @@ public class MapRenderer {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vector3 getCursor() {
|
||||
Vector3 coords = new Vector3();
|
||||
coords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
||||
camera.unproject(coords);
|
||||
float adjustX = (int) coords.x;
|
||||
float adjustY = (int) coords.y - Tile.SUBTILE_HEIGHT50;
|
||||
|
||||
float selectX = ( adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
float selectY = (-adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
if (selectX < 0) selectX--;
|
||||
if (selectY < 0) selectY--;
|
||||
coords.x = (int) selectX;
|
||||
coords.y = (int) selectY;
|
||||
return coords;
|
||||
}
|
||||
|
||||
public void setMap(Map map) {
|
||||
if (this.map != map) {
|
||||
this.map = map;
|
||||
@ -852,6 +869,88 @@ public class MapRenderer {
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
public void renderDebugPath(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
shapes.setColor(Color.TAN);
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
if (Math.abs(dst.y - src.y) < Math.abs(dst.x - src.x)) {
|
||||
if (src.x > dst.x) {
|
||||
plotLineLow(shapes, dst, src);
|
||||
} else {
|
||||
plotLineLow(shapes, src, dst);
|
||||
}
|
||||
} else {
|
||||
if (src.y > dst.y) {
|
||||
plotLineHigh(shapes, dst, src);
|
||||
} else {
|
||||
plotLineHigh(shapes, src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
private void plotLineLow(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
float dx = dst.x - src.x;
|
||||
float dy = dst.y - src.y;
|
||||
int yi = 1;
|
||||
if (dy < 0) {
|
||||
yi = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
float D = 2*dy - dx;
|
||||
float y = src.y;
|
||||
for (float x = src.x; x <= dst.x; x++) {
|
||||
float px = +((int) x * Tile.SUBTILE_WIDTH50) - ((int) y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -((int) x * Tile.SUBTILE_HEIGHT50) - ((int) y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
if (D > 0) {
|
||||
y = y + yi;
|
||||
D = D - 2*dx;
|
||||
}
|
||||
|
||||
D = D + 2*dy;
|
||||
}
|
||||
}
|
||||
|
||||
private void plotLineHigh(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
float dx = dst.x - src.x;
|
||||
float dy = dst.y - src.y;
|
||||
int xi = 1;
|
||||
if (dx < 0) {
|
||||
xi = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
float D = 2*dx - dy;
|
||||
float x = src.x;
|
||||
for (float y = src.y; y <= dst.y; y++) {
|
||||
float px = +((int) x * Tile.SUBTILE_WIDTH50) - ((int) y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -((int) x * Tile.SUBTILE_HEIGHT50) - ((int) y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
if (D > 0) {
|
||||
x = x + xi;
|
||||
D = D - 2*dy;
|
||||
}
|
||||
|
||||
D = D + 2*dx;
|
||||
}
|
||||
}
|
||||
|
||||
public void renderDebugPath2(ShapeRenderer shapes, GraphPath<MapUtils.Point2> path) {
|
||||
shapes.setColor(Color.TAN);
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
final int size = path.getCount();
|
||||
for (int i = 0; i < size; i++) {
|
||||
MapUtils.Point2 point = path.get(i);
|
||||
float px = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
}
|
||||
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
private static void drawDiamond(ShapeRenderer shapes, float x, float y, int width, int height) {
|
||||
int hw = width >>> 1;
|
||||
int hh = height >>> 1;
|
||||
@ -860,4 +959,11 @@ public class MapRenderer {
|
||||
shapes.line(x + width, y + hh , x + hw , y );
|
||||
shapes.line(x + hw , y , x , y + hh );
|
||||
}
|
||||
|
||||
private static void drawDiamondSolid(ShapeRenderer shapes, float x, float y, int width, int height) {
|
||||
int hw = width >>> 1;
|
||||
int hh = height >>> 1;
|
||||
shapes.triangle(x, y + hh, x + hw, y + height, x + width, y + hh);
|
||||
shapes.triangle(x, y + hh, x + hw, y , x + width, y + hh);
|
||||
}
|
||||
}
|
||||
|
192
core/src/gdx/diablo/map/MapUtils.java
Normal file
192
core/src/gdx/diablo/map/MapUtils.java
Normal file
@ -0,0 +1,192 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class MapUtils {
|
||||
|
||||
private MapUtils() {}
|
||||
|
||||
public static GraphPath<Point2> path(Map map, Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
Point2 srcP = new Point2(src);
|
||||
Point2 dstP = new Point2(dst);
|
||||
Array<Point2> coords = new Array<>();
|
||||
Array<Point2> children = new Array<>(8);
|
||||
coords.add(dstP);
|
||||
boolean found = false;
|
||||
do {
|
||||
for (Point2 point : coords) {
|
||||
found = expand(map, srcP, point, coords, children);
|
||||
coords.addAll(children);
|
||||
if (found) break;
|
||||
}
|
||||
} while (!found);
|
||||
|
||||
if (!found) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Point2 next = null;
|
||||
Point2 last = coords.removeIndex(coords.size - 1);
|
||||
while (true) {
|
||||
for (Point2 coord : coords) {
|
||||
if (last.adjacent(coord)) {
|
||||
if (next == null || coord.cost < next.cost) {
|
||||
next = coord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.add(next);
|
||||
last = next;
|
||||
next = null;
|
||||
if (dstP.x == last.x && dstP.y == last.y) break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private static boolean expand(Map map, Point2 dst, Point2 src, Array<Point2> coords, Array<Point2> children) {
|
||||
children.clear();
|
||||
if (check(map, dst, src, src.x - 1, src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x - 1, src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x - 1, src.y + 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y + 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y + 1, coords, children)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean check(Map map, Point2 dst, Point2 src, int x, int y, Array<Point2> coords, Array<Point2> children) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone != null) {
|
||||
if (zone.flags(x, y) == 0) {
|
||||
float cost = src.cost;
|
||||
cost += (x != src.x && y != src.y) ? 1.414213562373095f : 1;
|
||||
if (!contains(coords, x, y, cost)) {
|
||||
Point2 point = new Point2(x, y, cost);
|
||||
children.add(point);
|
||||
if (dst.x == x && dst.y == y) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean contains(Array<Point2> coords, int x, int y, float cost) {
|
||||
for (Point2 point : new Array.ArrayIterator<>(coords)) {
|
||||
if (point.x == x && point.y == y && point.cost <= cost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class Point2 {
|
||||
int x;
|
||||
int y;
|
||||
float cost;
|
||||
|
||||
Point2(int x, int y, float cost) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
Point2(Vector3 src) {
|
||||
x = (int) src.x;
|
||||
y = (int) src.y;
|
||||
}
|
||||
|
||||
boolean adjacent(Point2 other) {
|
||||
return Vector2.dst2(x, y, other.x, other.y) < 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static Array<Vector3> path(Map map, Vector3 src, Vector3 dst) {
|
||||
ObjectSet<Vector3> open = new ObjectSet<>();
|
||||
ObjectSet<Vector3> closed = new ObjectSet<>();
|
||||
open.add(src);
|
||||
|
||||
int x, y;
|
||||
while (!open.isEmpty()) {
|
||||
Node cur = null;
|
||||
if (cur.data.equals(dst)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
x = (int) cur.data.x;
|
||||
y = (int) cur.data.y;
|
||||
|
||||
Array<Node> neighbors = getNeighbors(map, cur, x, y);
|
||||
for (Node neighbor : neighbors) {
|
||||
float score = cur.cost + neighbor.cost;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Array<Node> getNeighbors(Map map, Node n, int x, int y) {
|
||||
Array<Node> neighbors = new Array<>(8);
|
||||
addIfValid(neighbors, map, n, x - 1, y - 1);
|
||||
addIfValid(neighbors, map, n, x - 1, y );
|
||||
addIfValid(neighbors, map, n, x - 1, y + 1);
|
||||
addIfValid(neighbors, map, n, x , y - 1);
|
||||
addIfValid(neighbors, map, n, x , y );
|
||||
addIfValid(neighbors, map, n, x , y + 1);
|
||||
addIfValid(neighbors, map, n, x + 1, y - 1);
|
||||
addIfValid(neighbors, map, n, x + 1, y );
|
||||
addIfValid(neighbors, map, n, x + 1, y + 1);
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
private static boolean addIfValid(Array<Node> arr, Map map, Node n, int x, int y) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone != null) {
|
||||
if (zone.flags(x, y) == 0) {
|
||||
Node node = new Node();
|
||||
node.prev = n;
|
||||
node.data = new Vector3(x, y, 0);
|
||||
if (x != node.data.x && y != node.data.y) {
|
||||
node.cost = 1.414213562373095f;
|
||||
} else {
|
||||
node.cost = 1;
|
||||
}
|
||||
|
||||
arr.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class Node {
|
||||
Node prev;
|
||||
Vector3 data;
|
||||
float cost;
|
||||
float score;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof Node)) return false;
|
||||
return data.equals(((Node) obj).data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return data.hashCode();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -6,9 +6,11 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.InputAdapter;
|
||||
import com.badlogic.gdx.InputMultiplexer;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
@ -16,6 +18,7 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
|
||||
@ -39,6 +42,7 @@ import gdx.diablo.loader.COFLoader;
|
||||
import gdx.diablo.loader.DC6Loader;
|
||||
import gdx.diablo.loader.DCCLoader;
|
||||
import gdx.diablo.loader.TXTLoader;
|
||||
import gdx.diablo.map.DT1.Tile;
|
||||
import gdx.diablo.mpq.MPQFileHandleResolver;
|
||||
|
||||
public class MapViewer extends ApplicationAdapter {
|
||||
@ -70,6 +74,10 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
int x, y;
|
||||
|
||||
Vector3 src;
|
||||
Vector3 dst;
|
||||
GraphPath<MapUtils.Point2> path;
|
||||
|
||||
boolean drawCrosshair;
|
||||
boolean drawGrid;
|
||||
boolean drawFlags;
|
||||
@ -126,6 +134,50 @@ public class MapViewer extends ApplicationAdapter {
|
||||
mapRenderer.resize();
|
||||
|
||||
InputMultiplexer multiplexer = new InputMultiplexer();
|
||||
multiplexer.addProcessor(new InputAdapter() {
|
||||
@Override
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
|
||||
switch (button) {
|
||||
case Input.Buttons.LEFT:
|
||||
src = mapRenderer.getCursor();
|
||||
dst = null;
|
||||
break;
|
||||
case Input.Buttons.RIGHT:
|
||||
src = dst = null;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDragged(int screenX, int screenY, int button) {
|
||||
if (src != null) {
|
||||
dst = mapRenderer.getCursor();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
|
||||
switch (button) {
|
||||
case Input.Buttons.LEFT:
|
||||
dst = mapRenderer.getCursor();
|
||||
System.out.println("src = " + src);
|
||||
System.out.println("dst = " + dst);
|
||||
|
||||
//float srcX = +(src.x * Tile.SUBTILE_WIDTH50) - (src.y * Tile.SUBTILE_WIDTH50);
|
||||
//float srcY = -(src.x * Tile.SUBTILE_HEIGHT50) - (src.y * Tile.SUBTILE_HEIGHT50);
|
||||
//float dstX = +(dst.x * Tile.SUBTILE_WIDTH50) - (dst.y * Tile.SUBTILE_WIDTH50);
|
||||
//float dstY = -(dst.x * Tile.SUBTILE_HEIGHT50) - (dst.y * Tile.SUBTILE_HEIGHT50);
|
||||
//System.out.println(new Vector2(dstX, dstY).dst(srcX, srcY));
|
||||
System.out.println(src.dst(dst));
|
||||
|
||||
path = map.path(src, dst);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
multiplexer.addProcessor(new InputAdapter() {
|
||||
private final float ZOOM_AMOUNT = 0.1f;
|
||||
|
||||
@ -321,6 +373,19 @@ public class MapViewer extends ApplicationAdapter {
|
||||
shapes.setAutoShapeType(true);
|
||||
shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
mapRenderer.renderDebug(shapes);
|
||||
if (src != null && dst != null) {
|
||||
//mapRenderer.renderDebugPath(shapes, src, dst);
|
||||
if (path != null) mapRenderer.renderDebugPath2(shapes, path);
|
||||
float srcX = +(src.x * Tile.SUBTILE_WIDTH50) - (src.y * Tile.SUBTILE_WIDTH50);
|
||||
float srcY = -(src.x * Tile.SUBTILE_HEIGHT50) - (src.y * Tile.SUBTILE_HEIGHT50);
|
||||
float dstX = +(dst.x * Tile.SUBTILE_WIDTH50) - (dst.y * Tile.SUBTILE_WIDTH50);
|
||||
float dstY = -(dst.x * Tile.SUBTILE_HEIGHT50) - (dst.y * Tile.SUBTILE_HEIGHT50);
|
||||
shapes.setColor(Color.WHITE);
|
||||
shapes.circle(srcX, srcY, 32);
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
shapes.setColor(Color.ORANGE);
|
||||
shapes.rectLine(srcX, srcY, dstX, dstY, 1);
|
||||
}
|
||||
shapes.end();
|
||||
|
||||
final int width = Gdx.graphics.getWidth();
|
||||
|
Reference in New Issue
Block a user