Path progress
This commit is contained in:
@@ -27,14 +27,8 @@ public class Pathfinder implements Runnable{
|
|||||||
private int[][] tiles;
|
private int[][] tiles;
|
||||||
/** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */
|
/** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */
|
||||||
private Seq<Flowfield> threadList = new Seq<>(), mainList = new Seq<>();
|
private Seq<Flowfield> threadList = new Seq<>(), mainList = new Seq<>();
|
||||||
/** Maps team ID and target to to a flowfield.*/
|
|
||||||
private ObjectMap<PathTarget, Flowfield>[] fieldMap = new ObjectMap[Team.all.length];
|
|
||||||
/** Used field maps. */
|
|
||||||
private ObjectSet<PathTarget>[] fieldMapUsed = new ObjectSet[Team.all.length];
|
|
||||||
/** handles task scheduling on the update thread. */
|
/** handles task scheduling on the update thread. */
|
||||||
private TaskQueue queue = new TaskQueue();
|
private TaskQueue queue = new TaskQueue();
|
||||||
/** Stores path target for a position. Main thread only.*/
|
|
||||||
private ObjectMap<Position, PathTarget> targetCache = new ObjectMap<>();
|
|
||||||
/** Current pathfinding thread */
|
/** Current pathfinding thread */
|
||||||
private @Nullable Thread thread;
|
private @Nullable Thread thread;
|
||||||
private IntSeq tmpArray = new IntSeq();
|
private IntSeq tmpArray = new IntSeq();
|
||||||
@@ -45,9 +39,6 @@ public class Pathfinder implements Runnable{
|
|||||||
|
|
||||||
//reset and update internal tile array
|
//reset and update internal tile array
|
||||||
tiles = new int[world.width()][world.height()];
|
tiles = new int[world.width()][world.height()];
|
||||||
fieldMap = new ObjectMap[Team.all.length];
|
|
||||||
fieldMapUsed = new ObjectSet[Team.all.length];
|
|
||||||
targetCache = new ObjectMap<>();
|
|
||||||
threadList = new Seq<>();
|
threadList = new Seq<>();
|
||||||
mainList = new Seq<>();
|
mainList = new Seq<>();
|
||||||
|
|
||||||
@@ -56,7 +47,7 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//special preset which may help speed things up; this is optional
|
//special preset which may help speed things up; this is optional
|
||||||
preloadPath(state.rules.waveTeam, FlagTarget.enemyCores);
|
//preloadPath(state.rules.waveTeam, FlagTarget.enemyCores);
|
||||||
|
|
||||||
start();
|
start();
|
||||||
});
|
});
|
||||||
@@ -68,7 +59,29 @@ public class Pathfinder implements Runnable{
|
|||||||
|
|
||||||
/** Packs a tile into its internal representation. */
|
/** Packs a tile into its internal representation. */
|
||||||
private int packTile(Tile tile){
|
private int packTile(Tile tile){
|
||||||
return PathTile.get(tile.cost, (byte)tile.getTeamID(), !tile.solid() && tile.floor().drownTime <= 0f, !tile.solid() && tile.floor().isLiquid);
|
//TODO nearGround is just the inverse of nearLiquid?
|
||||||
|
boolean nearLiquid = false, nearSolid = false, nearGround = false;
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
Tile other = tile.getNearby(i);
|
||||||
|
if(other != null){
|
||||||
|
if(other.floor().isLiquid) nearLiquid = true;
|
||||||
|
if(other.solid()) nearSolid = true;
|
||||||
|
if(!other.floor().isLiquid) nearGround = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PathTile.get(
|
||||||
|
tile.build == null ? 0 : Math.min((int)(tile.build.health / 40), 127),
|
||||||
|
tile.getTeamID(),
|
||||||
|
tile.solid(),
|
||||||
|
tile.floor().isLiquid,
|
||||||
|
tile.staticDarkness() < 2,
|
||||||
|
nearLiquid,
|
||||||
|
nearGround,
|
||||||
|
nearSolid,
|
||||||
|
tile.floor().isDeep()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts or restarts the pathfinding thread. */
|
/** Starts or restarts the pathfinding thread. */
|
||||||
@@ -104,7 +117,7 @@ public class Pathfinder implements Runnable{
|
|||||||
if(path != null){
|
if(path != null){
|
||||||
synchronized(path.targets){
|
synchronized(path.targets){
|
||||||
path.targets.clear();
|
path.targets.clear();
|
||||||
path.target.getPositions(path.team, path.targets);
|
path.getPositions(path.targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,18 +144,19 @@ public class Pathfinder implements Runnable{
|
|||||||
updateFrontier(data, maxUpdate / threadList.size);
|
updateFrontier(data, maxUpdate / threadList.size);
|
||||||
|
|
||||||
//remove flowfields that have 'timed out' so they can be garbage collected and no longer waste space
|
//remove flowfields that have 'timed out' so they can be garbage collected and no longer waste space
|
||||||
if(data.target.refreshRate() > 0 && Time.timeSinceMillis(data.lastUpdateTime) > fieldTimeout){
|
if(data.refreshRate > 0 && Time.timeSinceMillis(data.lastUpdateTime) > fieldTimeout){
|
||||||
//make sure it doesn't get removed twice
|
//make sure it doesn't get removed twice
|
||||||
data.lastUpdateTime = Time.millis();
|
data.lastUpdateTime = Time.millis();
|
||||||
|
|
||||||
Team team = data.team;
|
Team team = data.team;
|
||||||
|
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
|
//TODO ?????
|
||||||
//remove its used state
|
//remove its used state
|
||||||
if(fieldMap[team.id] != null){
|
//if(fieldMap[team.id] != null){
|
||||||
fieldMap[team.id].remove(data.target);
|
// fieldMap[team.id].remove(data.target);
|
||||||
fieldMapUsed[team.id].remove(data.target);
|
// fieldMapUsed[team.id].remove(data.target);
|
||||||
}
|
//}
|
||||||
//remove from main thread list
|
//remove from main thread list
|
||||||
mainList.remove(data);
|
mainList.remove(data);
|
||||||
});
|
});
|
||||||
@@ -167,51 +181,62 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Tile getTargetTile(Tile tile, Team team, Position target){
|
//public @Nullable Tile getTargetTile(Tile tile, Team team, Position target){
|
||||||
return getTargetTile(tile, team, getTarget(target));
|
// return getTargetTile(tile, team, getTarget(target));
|
||||||
|
// }
|
||||||
|
|
||||||
|
public @Nullable Tile getTargetTile(Tile tile, Prov<Flowfield> fieldtype, Team team, PathCost cost){
|
||||||
|
if(true){ //TODO cache this
|
||||||
|
Flowfield field = fieldtype.get();
|
||||||
|
IntSeq out = new IntSeq();
|
||||||
|
field.team = team;
|
||||||
|
field.getPositions(out);
|
||||||
|
createPath(field, cost, team, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(false){ //TODO if field exists
|
||||||
|
//TODO fetch it from the cache
|
||||||
|
//return getTargetTile(tile, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets next tile to travel to. Main thread only. */
|
/** Gets next tile to travel to. Main thread only. */
|
||||||
public @Nullable Tile getTargetTile(Tile tile, Team team, PathTarget target){
|
public @Nullable Tile getTargetTile(Tile tile, Flowfield path){
|
||||||
if(tile == null) return null;
|
if(tile == null) return null;
|
||||||
|
|
||||||
if(fieldMap[team.id] == null){
|
if(path == null){
|
||||||
fieldMap[team.id] = new ObjectMap<>();
|
|
||||||
fieldMapUsed[team.id] = new ObjectSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Flowfield data = fieldMap[team.id].get(target);
|
|
||||||
|
|
||||||
if(data == null){
|
|
||||||
//if this combination is not found, create it on request
|
//if this combination is not found, create it on request
|
||||||
if(fieldMapUsed[team.id].add(target)){
|
//TODO do above task
|
||||||
|
//if(fieldMapUsed[team.id].add(target)){
|
||||||
//grab targets since this is run on main thread
|
//grab targets since this is run on main thread
|
||||||
IntSeq targets = target.getPositions(team, new IntSeq());
|
// IntSeq targets = target.getPositions(team, new IntSeq());
|
||||||
queue.post(() -> createPath(team, target, targets));
|
// queue.post(() -> createPath(team, target, targets));
|
||||||
}
|
//}
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if refresh rate is positive, queue a refresh
|
//if refresh rate is positive, queue a refresh
|
||||||
if(target.refreshRate() > 0 && Time.timeSinceMillis(data.lastUpdateTime) > target.refreshRate()){
|
if(path.refreshRate > 0 && Time.timeSinceMillis(path.lastUpdateTime) > path.refreshRate){
|
||||||
data.lastUpdateTime = Time.millis();
|
path.lastUpdateTime = Time.millis();
|
||||||
|
|
||||||
tmpArray.clear();
|
tmpArray.clear();
|
||||||
data.target.getPositions(data.team, tmpArray);
|
path.getPositions(tmpArray);
|
||||||
|
|
||||||
synchronized(data.targets){
|
synchronized(path.targets){
|
||||||
//make sure the position actually changed
|
//make sure the position actually changed
|
||||||
if(!(data.targets.size == 1 && tmpArray.size == 1 && data.targets.first() == tmpArray.first())){
|
if(!(path.targets.size == 1 && tmpArray.size == 1 && path.targets.first() == tmpArray.first())){
|
||||||
data.targets.clear();
|
path.targets.clear();
|
||||||
data.target.getPositions(data.team, data.targets);
|
path.getPositions(path.targets);
|
||||||
|
|
||||||
//queue an update
|
//queue an update
|
||||||
queue.post(() -> updateTargets(data));
|
queue.post(() -> updateTargets(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int[][] values = data.weights;
|
int[][] values = path.weights;
|
||||||
int value = values[tile.x][tile.y];
|
int value = values[tile.x][tile.y];
|
||||||
|
|
||||||
Tile current = null;
|
Tile current = null;
|
||||||
@@ -234,16 +259,6 @@ public class Pathfinder implements Runnable{
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PathTarget getTarget(Position position){
|
|
||||||
return targetCache.get(position, () -> new PositionTarget(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return whether a tile can be passed through by this team. Pathfinding thread only. */
|
|
||||||
private boolean passable(int x, int y, Team team){
|
|
||||||
int tile = tiles[x][y];
|
|
||||||
return PathTile.passable(tile) || (PathTile.team(tile) != team.id && PathTile.team(tile) != (int)Team.derelict.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the frontier, increments the search and sets up all flow sources.
|
* Clears the frontier, increments the search and sets up all flow sources.
|
||||||
* This only occurs for active teams.
|
* This only occurs for active teams.
|
||||||
@@ -259,10 +274,8 @@ public class Pathfinder implements Runnable{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//assign impassability to the tile
|
//update cost of the tile TODO maybe only update the cost when it's not passable
|
||||||
if(!passable(x, y, path.team)){
|
path.weights[x][y] = path.cost.getCost(path.team, tiles[x][y]);
|
||||||
path.weights[x][y] = impassable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear frontier to prevent contamination
|
//clear frontier to prevent contamination
|
||||||
path.frontier.clear();
|
path.frontier.clear();
|
||||||
@@ -289,26 +302,30 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preloadPath(Team team, PathTarget target){
|
private void preloadPath(Flowfield path, PathCost cost, Team team){
|
||||||
updateFrontier(createPath(team, target, target.getPositions(team, new IntSeq())), -1);
|
IntSeq out = new IntSeq();
|
||||||
|
path.team = team;
|
||||||
|
path.getPositions(out);
|
||||||
|
updateFrontier(createPath(path, cost, team, out), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created a new flowfield that aims to get to a certain target for a certain team.
|
* Created a new flowfield that aims to get to a certain target for a certain team.
|
||||||
* Pathfinding thread only.
|
* Pathfinding thread only.
|
||||||
*/
|
*/
|
||||||
private Flowfield createPath(Team team, PathTarget target, IntSeq targets){
|
private Flowfield createPath(Flowfield path, PathCost cost, Team team, IntSeq targets){
|
||||||
Flowfield path = new Flowfield(team, target, world.width(), world.height());
|
|
||||||
path.lastUpdateTime = Time.millis();
|
path.lastUpdateTime = Time.millis();
|
||||||
|
path.setup(team, cost, tiles.length, tiles[0].length);
|
||||||
|
|
||||||
threadList.add(path);
|
threadList.add(path);
|
||||||
|
|
||||||
//add to main thread's list of paths
|
//add to main thread's list of paths
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
mainList.add(path);
|
mainList.add(path);
|
||||||
if(fieldMap[team.id] != null){
|
//TODO
|
||||||
fieldMap[team.id].put(target, path);
|
//if(fieldMap[team.id] != null){
|
||||||
}
|
// fieldMap[team.id].put(target, path);
|
||||||
|
//}
|
||||||
});
|
});
|
||||||
|
|
||||||
//grab targets from passed array
|
//grab targets from passed array
|
||||||
@@ -350,15 +367,15 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(cost != impassable){
|
if(cost != impassable){
|
||||||
|
//TODO this is probably slow.
|
||||||
for(Point2 point : Geometry.d4){
|
for(Point2 point : Geometry.d4){
|
||||||
|
|
||||||
int dx = tile.x + point.x, dy = tile.y + point.y;
|
int dx = tile.x + point.x, dy = tile.y + point.y;
|
||||||
Tile other = world.tile(dx, dy);
|
int otherCost = path.cost.getCost(path.team, tiles[dx][dy]);
|
||||||
|
|
||||||
if(other != null && (path.weights[dx][dy] > cost + other.cost || path.searches[dx][dy] < path.search) && passable(dx, dy, path.team)){
|
if((path.weights[dx][dy] > cost + otherCost || path.searches[dx][dy] < path.search) && otherCost != impassable){
|
||||||
if(other.cost < 0) throw new IllegalArgumentException("Tile cost cannot be negative! " + other);
|
|
||||||
path.frontier.addFirst(Point2.pack(dx, dy));
|
path.frontier.addFirst(Point2.pack(dx, dy));
|
||||||
path.weights[dx][dy] = cost + other.cost;
|
path.weights[dx][dy] = cost + otherCost;
|
||||||
path.searches[dx][dy] = (short)path.search;
|
path.searches[dx][dy] = (short)path.search;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,9 +383,24 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A path target defines a set of targets for a path. */
|
public static final PathCost
|
||||||
public enum FlagTarget implements PathTarget{
|
|
||||||
enemyCores((team, out) -> {
|
groundCost = (team, tile) -> (PathTile.team(tile) == team.id || PathTile.team(tile) == 0) && PathTile.solid(tile) ? impassable : 1 +
|
||||||
|
PathTile.health(tile) * 5 +
|
||||||
|
(PathTile.nearSolid(tile) ? 2 : 0) +
|
||||||
|
(PathTile.nearLiquid(tile) ? 6 : 0) +
|
||||||
|
(PathTile.deep(tile) ? 70 : 0),
|
||||||
|
|
||||||
|
legsCost = (team, tile) -> PathTile.legSolid(tile) ? impassable : 1 +
|
||||||
|
(PathTile.solid(tile) ? 5 : 0),
|
||||||
|
|
||||||
|
waterCost = (team, tile) -> PathTile.solid(tile) || !PathTile.liquid(tile) ? impassable : 2 + //TODO cannot go through blocks
|
||||||
|
(PathTile.nearGround(tile) || PathTile.nearSolid(tile) ? 14 : 0) +
|
||||||
|
(PathTile.deep(tile) ? -1 : 0);
|
||||||
|
|
||||||
|
public static class EnemyCoreField extends Flowfield{
|
||||||
|
@Override
|
||||||
|
protected void getPositions(IntSeq out){
|
||||||
for(Tile other : indexer.getEnemy(team, BlockFlag.core)){
|
for(Tile other : indexer.getEnemy(team, BlockFlag.core)){
|
||||||
out.add(other.pos());
|
out.add(other.pos());
|
||||||
}
|
}
|
||||||
@@ -379,50 +411,31 @@ public class Pathfinder implements Runnable{
|
|||||||
out.add(other.pos());
|
out.add(other.pos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
rallyPoints((team, out) -> {
|
|
||||||
for(Tile other : indexer.getAllied(team, BlockFlag.rally)){
|
|
||||||
out.add(other.pos());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public static final FlagTarget[] all = values();
|
|
||||||
|
|
||||||
private final Cons2<Team, IntSeq> targeter;
|
|
||||||
|
|
||||||
FlagTarget(Cons2<Team, IntSeq> targeter){
|
|
||||||
this.targeter = targeter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IntSeq getPositions(Team team, IntSeq out){
|
|
||||||
targeter.get(team, out);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int refreshRate(){
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PositionTarget implements PathTarget{
|
public static class RallyField extends Flowfield{
|
||||||
|
@Override
|
||||||
|
protected void getPositions(IntSeq out){
|
||||||
|
for(Tile other : indexer.getAllied(team, BlockFlag.rally)){
|
||||||
|
out.add(other.pos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PositionTarget extends Flowfield{
|
||||||
public final Position position;
|
public final Position position;
|
||||||
|
|
||||||
public PositionTarget(Position position){
|
public PositionTarget(Position position){
|
||||||
this.position = position;
|
this.position = position;
|
||||||
|
this.refreshRate = 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IntSeq getPositions(Team team, IntSeq out){
|
public void getPositions(IntSeq out){
|
||||||
out.add(Point2.pack(world.toTile(position.getX()), world.toTile(position.getY())));
|
out.add(Point2.pack(world.toTile(position.getX()), world.toTile(position.getY())));
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int refreshRate(){
|
|
||||||
return 900;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -434,6 +447,8 @@ public class Pathfinder implements Runnable{
|
|||||||
protected int refreshRate;
|
protected int refreshRate;
|
||||||
/** Team this path is for. */
|
/** Team this path is for. */
|
||||||
protected Team team;
|
protected Team team;
|
||||||
|
/** Function for calculating path cost. */
|
||||||
|
protected PathCost cost;
|
||||||
|
|
||||||
/** costs of getting to a specific tile */
|
/** costs of getting to a specific tile */
|
||||||
int[][] weights;
|
int[][] weights;
|
||||||
@@ -447,34 +462,47 @@ public class Pathfinder implements Runnable{
|
|||||||
int search = 1;
|
int search = 1;
|
||||||
/** last updated time */
|
/** last updated time */
|
||||||
long lastUpdateTime;
|
long lastUpdateTime;
|
||||||
|
/** whether this flow field is ready to be used */
|
||||||
|
boolean initialized;
|
||||||
|
|
||||||
void setup(Team team, int width, int height){
|
void setup(Team team, PathCost cost, int width, int height){
|
||||||
this.team = team;
|
this.team = team;
|
||||||
|
this.cost = cost;
|
||||||
|
|
||||||
this.weights = new int[width][height];
|
this.weights = new int[width][height];
|
||||||
this.searches = new int[width][height];
|
this.searches = new int[width][height];
|
||||||
this.frontier.ensureCapacity((width + height) * 3);
|
this.frontier.ensureCapacity((width + height) * 3);
|
||||||
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets targets to pathfind towards. This must run on the main thread. */
|
/** Gets targets to pathfind towards. This must run on the main thread. */
|
||||||
protected abstract IntSeq getPositions(IntSeq out);
|
protected abstract void getPositions(IntSeq out);
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the cost of a tile at a position. */
|
interface PathCost{
|
||||||
protected abstract int getCost(int pathTile);
|
int getCost(Team traversing, int tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds a copy of tile data for a specific tile position. */
|
/** Holds a copy of tile data for a specific tile position. */
|
||||||
@Struct
|
@Struct
|
||||||
class PathTileStruct{
|
class PathTileStruct{
|
||||||
//base traversal cost (could be a byte..)
|
//scaled block health
|
||||||
short cost;
|
@StructField(8) int health;
|
||||||
//team of block, if applicable (0 by default)
|
//team of block, if applicable (0 by default)
|
||||||
byte team;
|
@StructField(8) int team;
|
||||||
//general solid state
|
//general solid state
|
||||||
boolean solid;
|
boolean solid;
|
||||||
//whether this block is a liquid that boats can move on
|
//whether this block is a liquid that boats can move on
|
||||||
boolean water;
|
boolean liquid;
|
||||||
//whether this block is solid for leg units that can move over some solid blocks
|
//whether this block is solid for leg units that can move over some solid blocks
|
||||||
boolean legSolid;
|
boolean legSolid;
|
||||||
|
//whether this block is near liquids
|
||||||
|
boolean nearLiquid;
|
||||||
|
//whether this block is near a solid floor tile
|
||||||
|
boolean nearGround;
|
||||||
|
//whether this block is near a solid object
|
||||||
|
boolean nearSolid;
|
||||||
|
//whether this block is deep / drownable
|
||||||
|
boolean deep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
|||||||
|
|
||||||
/** Extra data for very specific blocks. */
|
/** Extra data for very specific blocks. */
|
||||||
public byte data;
|
public byte data;
|
||||||
/** Tile traversal cost. */
|
|
||||||
public short cost = 1;
|
|
||||||
/** Tile entity, usually null. */
|
/** Tile entity, usually null. */
|
||||||
public @Nullable Building build;
|
public @Nullable Building build;
|
||||||
public short x, y;
|
public short x, y;
|
||||||
@@ -442,42 +440,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
|||||||
return block.solid && block.fillsTile && !block.synthetic() ? data : 0;
|
return block.solid && block.fillsTile && !block.synthetic() ? data : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO remove this method?
|
||||||
public void updateOcclusion(){
|
public void updateOcclusion(){
|
||||||
cost = 1;
|
|
||||||
boolean occluded = false;
|
|
||||||
|
|
||||||
//check for occlusion
|
|
||||||
for(int i = 0; i < 8; i++){
|
|
||||||
Point2 point = Geometry.d8[i];
|
|
||||||
Tile tile = world.tile(x + point.x, y + point.y);
|
|
||||||
if(tile != null && tile.floor.isLiquid){
|
|
||||||
cost += 4;
|
|
||||||
}
|
|
||||||
if(tile != null && tile.solid()){
|
|
||||||
occluded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(occluded){
|
|
||||||
cost += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(block.synthetic() && solid()){
|
|
||||||
cost += Mathf.clamp(block.health / 6f, 0, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(floor.isLiquid){
|
|
||||||
cost += 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(floor.drownTime > 0){
|
|
||||||
cost += 70;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cost < 0){
|
|
||||||
cost = Byte.MAX_VALUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void preChanged(){
|
protected void preChanged(){
|
||||||
|
|||||||
Reference in New Issue
Block a user