Transform Path class to interface

This is necessary to introduce a MovementPath, which is a special Path implementation that contains only non-ignore MoveSegments specialized to include also a target coordinates. Thanks to that, the PathFinder can create a path with consecutive directions as well as the coordinates that can be iterated in order to find, if no other Entity is blocking the path (`contains()` method in MovementPath).
This commit is contained in:
2021-04-04 23:55:14 +02:00
parent 7c777dca01
commit a11773e60c
8 changed files with 147 additions and 87 deletions

View File

@@ -7,6 +7,7 @@ import com.bartlomiejpluta.base.api.map.layer.base.Layer;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.api.move.Movable;
import com.bartlomiejpluta.base.util.path.BasePath;
import com.bartlomiejpluta.base.util.path.Path; import com.bartlomiejpluta.base.util.path.Path;
import org.joml.Vector2fc; import org.joml.Vector2fc;
import org.joml.Vector2i; import org.joml.Vector2i;
@@ -16,10 +17,10 @@ import java.util.function.Consumer;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
public class BulletAnimationRunner implements AnimationRunner { public class BulletAnimationRunner implements AnimationRunner {
private static final Path<Animation> UP = new Path<Animation>().move(Direction.UP); private static final Path<Animation> UP = new BasePath<Animation>().move(Direction.UP);
private static final Path<Animation> DOWN = new Path<Animation>().move(Direction.DOWN); private static final Path<Animation> DOWN = new BasePath<Animation>().move(Direction.DOWN);
private static final Path<Animation> LEFT = new Path<Animation>().move(Direction.LEFT); private static final Path<Animation> LEFT = new BasePath<Animation>().move(Direction.LEFT);
private static final Path<Animation> RIGHT = new Path<Animation>().move(Direction.RIGHT); private static final Path<Animation> RIGHT = new BasePath<Animation>().move(Direction.RIGHT);
private final String animationUid; private final String animationUid;

View File

@@ -0,0 +1,44 @@
package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
public class BasePath<T extends Movable> implements Path<T> {
@Getter
private final List<PathSegment<T>> path = new ArrayList<>();
public Path<T> add(PathSegment<T> segment) {
path.add(segment);
return this;
}
public Path<T> addFirst(PathSegment<T> segment) {
path.add(0, segment);
return this;
}
public Path<T> move(Direction direction) {
path.add(new MoveSegment<>(direction));
return this;
}
public Path<T> move(Direction direction, boolean ignore) {
path.add(new MoveSegment<>(direction, ignore));
return this;
}
public Path<T> wait(float seconds) {
path.add(new WaitSegment<>(seconds));
return this;
}
public Path<T> run(Runnable runnable) {
path.add(new RunSegment<>(runnable));
return this;
}
}

View File

@@ -0,0 +1,47 @@
package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable;
import java.util.ArrayList;
import java.util.List;
public class MovementPath<T extends Movable> implements Path<T> {
private final List<PositionableMoveSegment<T>> path = new ArrayList<>();
@Override
public List<? extends PathSegment<T>> getPath() {
return path;
}
public MovementPath<T> add(Direction direction, int x, int y) {
path.add(new PositionableMoveSegment<>(direction, x, y));
return this;
}
public MovementPath<T> addFirst(Direction direction, int x, int y) {
path.add(0, new PositionableMoveSegment<>(direction, x, y));
return this;
}
public boolean contains(int x, int y) {
for (var segment : path) {
if (segment.x == x && segment.y == y) {
return true;
}
}
return false;
}
private static class PositionableMoveSegment<T extends Movable> extends MoveSegment<T> {
final int x;
final int y;
PositionableMoveSegment(Direction direction, int x, int y) {
super(direction);
this.x = x;
this.y = y;
}
}
}

View File

@@ -2,47 +2,48 @@ package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.ai.NPC; import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import lombok.Getter;
public class NPCPath extends Path<NPC> { import java.util.ArrayList;
import java.util.List;
public NPCPath turn(Direction direction) { public class NPCPath<T extends NPC> implements Path<T> {
@Getter
private final List<PathSegment<T>> path = new ArrayList<>();
public NPCPath<T> add(PathSegment<T> segment) {
path.add(segment);
return this;
}
public NPCPath<T> addFirst(PathSegment<T> segment) {
path.add(0, segment);
return this;
}
public NPCPath<T> move(Direction direction) {
path.add(new MoveSegment<>(direction));
return this;
}
public NPCPath<T> move(Direction direction, boolean ignore) {
path.add(new MoveSegment<>(direction, ignore));
return this;
}
public NPCPath<T> turn(Direction direction) {
path.add(new TurnSegment<>(direction)); path.add(new TurnSegment<>(direction));
return this; return this;
} }
@Override public NPCPath<T> wait(float seconds) {
public NPCPath add(PathSegment<NPC> segment) { path.add(new WaitSegment<>(seconds));
super.add(segment);
return this; return this;
} }
@Override public NPCPath<T> run(Runnable runnable) {
public NPCPath addFirst(PathSegment<NPC> segment) { path.add(new RunSegment<>(runnable));
super.addFirst(segment);
return this;
}
@Override
public NPCPath move(Direction direction) {
super.move(direction);
return this;
}
@Override
public NPCPath move(Direction direction, boolean ignore) {
super.move(direction, ignore);
return this;
}
@Override
public NPCPath wait(float seconds) {
super.wait(seconds);
return this;
}
@Override
public NPCPath run(Runnable runnable) {
super.run(runnable);
return this; return this;
} }
} }

View File

@@ -1,45 +1,9 @@
package com.bartlomiejpluta.base.util.path; package com.bartlomiejpluta.base.util.path;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.api.move.Movable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Path<T extends Movable> { public interface Path<T extends Movable> {
protected final List<PathSegment<T>> path = new ArrayList<>(); List<? extends PathSegment<T>> getPath();
public List<PathSegment<T>> getPath() {
return path;
}
public Path<T> add(PathSegment<T> segment) {
path.add(segment);
return this;
}
public Path<T> addFirst(PathSegment<T> segment) {
path.add(0, segment);
return this;
}
public Path<T> move(Direction direction) {
path.add(new MoveSegment<>(direction));
return this;
}
public Path<T> move(Direction direction, boolean ignore) {
path.add(new MoveSegment<>(direction, ignore));
return this;
}
public Path<T> wait(float seconds) {
path.add(new WaitSegment<>(seconds));
return this;
}
public Path<T> run(Runnable runnable) {
path.add(new RunSegment<>(runnable));
return this;
}
} }

View File

@@ -10,7 +10,7 @@ import static java.util.Collections.emptyList;
public class PathExecutor<T extends Movable> { public class PathExecutor<T extends Movable> {
private final T movable; private final T movable;
private List<PathSegment<T>> path = emptyList(); private List<? extends PathSegment<T>> path = emptyList();
private Integer repeat; private Integer repeat;
private int current = 0; private int current = 0;

View File

@@ -3,8 +3,7 @@ package com.bartlomiejpluta.base.util.pathfinder;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.api.move.Movable;
import com.bartlomiejpluta.base.util.path.MoveSegment; import com.bartlomiejpluta.base.util.path.MovementPath;
import com.bartlomiejpluta.base.util.path.Path;
import org.joml.Vector2i; import org.joml.Vector2i;
import org.joml.Vector2ic; import org.joml.Vector2ic;
@@ -43,23 +42,27 @@ public class AstarPathFinder implements PathFinder {
} }
@Override @Override
public <T extends Movable> Path<T> findPath(ObjectLayer layer, T start, Vector2ic end) { public <T extends Movable> MovementPath<T> findPath(ObjectLayer layer, T start, Vector2ic end) {
return astar(layer, start.getCoordinates(), end, this::recreatePath); return astar(layer, start.getCoordinates(), end, this::recreatePath);
} }
private <T extends Movable> Path<T> recreatePath(Node node) { private <T extends Movable> MovementPath<T> recreatePath(Node node) {
if (node == null) { if (node == null) {
return new Path<>(); return new MovementPath<>();
} }
var path = new Path<T>(); var path = new MovementPath<T>();
var current = node; var current = node;
while (current.parent != null) { while (current.parent != null) {
path.addFirst(new MoveSegment<>(Direction.ofVector( var currentX = current.position.x();
current.position.x() - current.parent.position.x(), var currentY = current.position.y();
current.position.y() - current.parent.position.y()
))); path.addFirst(Direction.ofVector(
currentX - current.parent.position.x(),
currentY - current.parent.position.y()
), currentX, currentY);
current = current.parent; current = current.parent;
} }

View File

@@ -2,13 +2,13 @@ package com.bartlomiejpluta.base.util.pathfinder;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.api.move.Movable;
import com.bartlomiejpluta.base.util.path.Path; import com.bartlomiejpluta.base.util.path.MovementPath;
import org.joml.Vector2ic; import org.joml.Vector2ic;
import java.util.LinkedList; import java.util.LinkedList;
public interface PathFinder { public interface PathFinder {
<T extends Movable> Path<T> findPath(ObjectLayer layer, T start, Vector2ic end); <T extends Movable> MovementPath<T> findPath(ObjectLayer layer, T start, Vector2ic end);
LinkedList<Vector2ic> findSequence(ObjectLayer layer, Vector2ic start, Vector2ic end); LinkedList<Vector2ic> findSequence(ObjectLayer layer, Vector2ic start, Vector2ic end);
} }