Skip to content

Commit

Permalink
#49: Add proper pathfinding taking VBL into account
Browse files Browse the repository at this point in the history
 - Cleaned up code a bit, Tweaked heuristic
 - Currently avoids any cell that has any VBL in it... to be tweaked
later

Task-Url: #49

Signed-off-by: Jamz <[email protected]>
  • Loading branch information
JamzTheMan committed Mar 24, 2018
1 parent 1ac44e1 commit f208e9c
Show file tree
Hide file tree
Showing 7 changed files with 469 additions and 169 deletions.
10 changes: 7 additions & 3 deletions src/main/java/net/rptools/maptool/client/MapTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.Configurator;

import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.plaf.UIDefaultsLookup;
Expand Down Expand Up @@ -1494,11 +1496,13 @@ public static void main(String[] args) {
boolean listMacros = getCommandLineOption(cmdOptions, "macros", args);

// Jamz: Just a little console log formatter for system.out to hyperlink messages to source.
if (debug)
if (debug) {
Configurator.setRootLevel(Level.DEBUG);
DebugStream.activate();
else
} else {
DebugStream.deactivate();

}

// List out passed in arguments
for (String arg : args) {
log.info("argument passed via command line: " + arg);
Expand Down
23 changes: 17 additions & 6 deletions src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@

import javax.swing.SwingWorker;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.oracle.tools.packager.Log;

import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
Expand All @@ -52,6 +57,8 @@
import net.rptools.maptool.model.Zone.Filter;

public class ZoneView implements ModelChangeListener {
private static final Logger log = LogManager.getLogger(ZoneView.class);

private final Zone zone;

// VISION
Expand Down Expand Up @@ -86,12 +93,16 @@ public boolean isUsingVision() {
return zone.getVisionType() != Zone.VisionType.OFF;
}

public synchronized AreaTree getTopology() {
return getTopology(true);
// Returns the current combined VBL (base VBL + TokenVBL)
public synchronized AreaTree getTopologyTree() {
return getTopologyTree(true);
}

public synchronized AreaTree getTopology(boolean useTokenVBL) {
// topologyTree is "cached" and should only regenerate when topologyTree is null which should happen on flush calls
public synchronized AreaTree getTopologyTree(boolean useTokenVBL) {
if (tokenTopolgy == null && useTokenVBL) {
log.debug("ZoneView topologyTree is null, generating...");

tokenTopolgy = new Area(zone.getTopology());
List<Token> vblTokens = MapTool.getFrame().getCurrentZoneRenderer().getZone().getTokensWithVBL();

Expand Down Expand Up @@ -177,7 +188,7 @@ private Area calculateLightSourceArea(LightSource lightSource, Token lightSource
if (sight.getMultiplier() != 1 && lightSource.getLumens() >= 0) {
lightSourceArea.transform(AffineTransform.getScaleInstance(sight.getMultiplier(), sight.getMultiplier()));
}
Area visibleArea = FogUtil.calculateVisibility(p.x, p.y, lightSourceArea, getTopology());
Area visibleArea = FogUtil.calculateVisibility(p.x, p.y, lightSourceArea, getTopologyTree());

if (visibleArea == null) {
return null;
Expand Down Expand Up @@ -255,7 +266,7 @@ public Area getVisibleArea(Token token) {
if (tokenVisibleArea == null) {
Point p = FogUtil.calculateVisionCenter(token, zone);
Area visibleArea = sight.getVisionShape(token, zone);
tokenVisibleArea = FogUtil.calculateVisibility(p.x, p.y, visibleArea, getTopology());
tokenVisibleArea = FogUtil.calculateVisibility(p.x, p.y, visibleArea, getTopologyTree());

tokenVisibleAreaCache.put(token.getId(), tokenVisibleArea);
}
Expand Down Expand Up @@ -421,7 +432,7 @@ public List<DrawableLight> getLights(LightSource.Type type) {
if (lightSource.getType() == type) {
// This needs to be cached somehow
Area lightSourceArea = lightSource.getArea(token, zone, Direction.CENTER);
Area visibleArea = FogUtil.calculateVisibility(p.x, p.y, lightSourceArea, getTopology());
Area visibleArea = FogUtil.calculateVisibility(p.x, p.y, lightSourceArea, getTopologyTree());
if (visibleArea == null) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
public class AreaTree {
private static final Logger log = LogManager.getLogger(AreaTree.class);
private AreaOcean theOcean;

private Area theArea; // in case we want to return the original area undigested

public AreaTree(Area area) {
digest(area);
}
Expand All @@ -36,10 +37,16 @@ AreaOcean getOcean() {
return theOcean;
}

public Area getArea() {
return theArea;
}
private void digest(Area area) {
if (area == null) {
return;
}

theArea = area;

List<AreaOcean> oceanList = new ArrayList<AreaOcean>();
List<AreaIsland> islandList = new ArrayList<AreaIsland>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@

import net.rptools.maptool.model.CellPoint;

public class AStarCellPoint extends CellPoint {
public class AStarCellPoint extends CellPoint implements Comparable<AStarCellPoint> {
AStarCellPoint parent;
double hScore;
double gScore;
double h;
double g;
double f;

public AStarCellPoint() {
super(0, 0);
Expand All @@ -28,6 +29,11 @@ public AStarCellPoint(CellPoint p) {
}

public double cost() {
return hScore + gScore;
return h + g;
}

@Override
public int compareTo(AStarCellPoint other) {
return Double.compare(f, other.f);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
*/
package net.rptools.maptool.client.walker.astar;

import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.rptools.maptool.client.walker.WalkerMetric;
import net.rptools.maptool.model.CellPoint;
Expand All @@ -27,6 +32,8 @@ public class AStarSquareEuclideanWalker extends AbstractAStarWalker {
private final WalkerMetric metric;

private final int[][] neighborMap;
double normal_cost = 10; // Can vary this later for some reason?
double diagonal_cost = normal_cost;

public AStarSquareEuclideanWalker(Zone zone, WalkerMetric metric) {
super(zone);
Expand All @@ -38,8 +45,11 @@ public AStarSquareEuclideanWalker(Zone zone, WalkerMetric metric) {
case NO_DIAGONALS:
neighborMap = new int[][] { NORTH, EAST, SOUTH, WEST };
break;
case ONE_ONE_ONE:
case ONE_TWO_ONE:
diagonal_cost = normal_cost * 1.5; // 1.4 would be closer math wise but in game terms you count every other square so 1.5
neighborMap = new int[][] { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST, NORTH, EAST, SOUTH, WEST };
break;
case ONE_ONE_ONE:
case MANHATTAN:
// promote straight directions to avoid 'only-diagonals' effect
neighborMap = new int[][] { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
Expand All @@ -51,63 +61,81 @@ public AStarSquareEuclideanWalker(Zone zone, WalkerMetric metric) {
}
}

@Override
protected List<AStarCellPoint> getNeighbors(AStarCellPoint node, Set<AStarCellPoint> closedSet) {
List<AStarCellPoint> neighbors = new ArrayList<AStarCellPoint>();
int[][] neighborMap = getNeighborMap(node.x, node.y);

// Find all the neighbors.
for (int[] i : neighborMap) {
AStarCellPoint neighbor = new AStarCellPoint(node.x + i[0], node.y + i[1]);

if (closedSet.contains(neighbor))
continue;

Rectangle cellBounds = zone.getGrid().getBounds(neighbor);

// VBL Check
if (vbl.intersects(cellBounds))
continue;

// Add the cell we're coming from
neighbor.parent = node;

// Simple check if it's a diagonal neighbor
if (Arrays.equals(i, NORTH_EAST) || Arrays.equals(i, SOUTH_EAST) || Arrays.equals(i, SOUTH_WEST) || Arrays.equals(i, NORTH_WEST))
neighbor.g = node.g + diagonal_cost;
else
neighbor.g = node.g + normal_cost;

neighbors.add(neighbor);
// showDebugInfo(cellBounds, neighbor);
}

return neighbors;
}

@Override
public int[][] getNeighborMap(int x, int y) {
return neighborMap;
}

@Override
protected double gScore(CellPoint p1, CellPoint p2) {
double delta_x = Math.abs(p1.x - p2.x);
double delta_y = Math.abs(p1.y - p2.y);

// if(delta_x > delta_y)
// return 14*delta_y + 10*(delta_x-delta_y);
// else
// return 14*delta_x + 10*(delta_y-delta_x);

return Math.min(delta_x, delta_y) * Math.sqrt(2) + Math.abs(delta_x - delta_y);

// return metricDistance(p1, p2);
return metricDistance(p1, p2);
}

@Override
protected double hScore(CellPoint p1, CellPoint p2) {
double delta_x = Math.abs(p1.x - p2.x);
double delta_y = Math.abs(p1.y - p2.y);

// if(delta_x > delta_y)
// return 14*delta_y + 10*(delta_x-delta_y);
// else
// return 14*delta_x + 10*(delta_y-delta_x);

return Math.min(delta_x, delta_y) * Math.sqrt(2) + Math.abs(delta_x - delta_y);

// return metricDistance(p1, p2);
return metricDistance(p1, p2);
}

private double metricDistance(CellPoint p1, CellPoint p2) {
int xDist = p2.x - p1.x;
int yDist = p2.y - p1.y;
private double metricDistance(CellPoint node, CellPoint goal) {
int xDist = node.x - goal.x;
int yDist = node.y - goal.y;

final double distance;

switch (metric) {
// case ONE_ONE_ONE:
// distance = Math.max(Math.abs(a),Math.abs(b));
// break;
case MANHATTAN:
case NO_DIAGONALS:
distance = Math.abs(xDist) + Math.abs(yDist);
break;
default:
case ONE_TWO_ONE:
distance = Math.sqrt(xDist * xDist + yDist * yDist);
// distance = Math.sqrt(xDist * xDist + yDist * yDist);
xDist = Math.abs(node.x - goal.x);
yDist = Math.abs(node.y - goal.y);
if (xDist > yDist)
distance = 14 * yDist + 10 * (xDist - yDist);
else
distance = 14 * xDist + 10 * (yDist - xDist);
break;
case ONE_ONE_ONE:
distance = Math.sqrt(xDist * xDist + yDist * yDist);
distance = Math.max(Math.abs(xDist), Math.abs(yDist));
break;
}

return distance;
}

Expand Down
Loading

0 comments on commit f208e9c

Please sign in to comment.