Exorcised scene width and height; make models unbounded by default;
cleaned up AStarPathUtil. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2407 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
//
|
//
|
||||||
// $Id: DisplayMisoScene.java,v 1.11 2003/04/01 02:17:58 mdb Exp $
|
// $Id: DisplayMisoScene.java,v 1.12 2003/04/12 02:14:52 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.miso.client;
|
package com.threerings.miso.client;
|
||||||
|
|
||||||
import com.threerings.media.tile.Tile;
|
import com.threerings.media.tile.Tile;
|
||||||
|
|
||||||
|
import com.threerings.miso.client.util.AStarPathUtil;
|
||||||
import com.threerings.miso.data.MisoScene;
|
import com.threerings.miso.data.MisoScene;
|
||||||
import com.threerings.miso.tile.BaseTile;
|
import com.threerings.miso.tile.BaseTile;
|
||||||
|
|
||||||
@@ -11,7 +13,8 @@ import com.threerings.miso.tile.BaseTile;
|
|||||||
* Extends the {@link MisoScene} with functionality needed only by
|
* Extends the {@link MisoScene} with functionality needed only by
|
||||||
* entities that plan to display a miso scene.
|
* entities that plan to display a miso scene.
|
||||||
*/
|
*/
|
||||||
public interface DisplayMisoScene extends MisoScene
|
public interface DisplayMisoScene
|
||||||
|
extends MisoScene, AStarPathUtil.TraversalPred
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This will be called before the scene is displayed to give it a
|
* This will be called before the scene is displayed to give it a
|
||||||
@@ -32,10 +35,11 @@ public interface DisplayMisoScene extends MisoScene
|
|||||||
/**
|
/**
|
||||||
* Returns true if the supplied traverser can traverse the specified
|
* Returns true if the supplied traverser can traverse the specified
|
||||||
* tile coordinate. The traverser is whatever object is passed along
|
* tile coordinate. The traverser is whatever object is passed along
|
||||||
* to the path finder when a path is being computed. Scene
|
* to the path finder when a path is being computed.
|
||||||
* implementations which support custom traversal based on the type of
|
*
|
||||||
* the traverser will want to reflect the traverser's class and act
|
* <p> Scene implementations which support custom traversal based on
|
||||||
* acordingly.
|
* the type of the traverser will want to reflect the traverser's
|
||||||
|
* class and act acordingly.
|
||||||
*/
|
*/
|
||||||
public boolean canTraverse (Object traverser, int x, int y);
|
public boolean canTraverse (Object traverser, int x, int y);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: IsoSceneView.java,v 1.136 2003/04/07 21:43:00 mdb Exp $
|
// $Id: IsoSceneView.java,v 1.137 2003/04/12 02:14:52 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.miso.client;
|
package com.threerings.miso.client;
|
||||||
|
|
||||||
@@ -515,10 +515,12 @@ public class IsoSceneView implements SceneView
|
|||||||
_model, sprite.getX(), sprite.getY(), new Point());
|
_model, sprite.getX(), sprite.getY(), new Point());
|
||||||
Point dest = IsoUtil.screenToTile(_model, x, y, new Point());
|
Point dest = IsoUtil.screenToTile(_model, x, y, new Point());
|
||||||
|
|
||||||
|
// TODO: compute this value from the screen size or something
|
||||||
|
int longestPath = 50;
|
||||||
|
|
||||||
// get a reasonable tile path through the scene
|
// get a reasonable tile path through the scene
|
||||||
List points = AStarPathUtil.getPath(
|
List points = AStarPathUtil.getPath(
|
||||||
_scene, _model.scenewid, _model.scenehei,
|
_scene, sprite, longestPath, src.x, src.y, dest.x, dest.y);
|
||||||
sprite, src.x, src.y, dest.x, dest.y);
|
|
||||||
|
|
||||||
// construct a path object to guide the sprite on its merry way
|
// construct a path object to guide the sprite on its merry way
|
||||||
return (points == null) ? null :
|
return (points == null) ? null :
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: IsoSceneViewModel.java,v 1.28 2003/01/31 23:10:45 mdb Exp $
|
// $Id: IsoSceneViewModel.java,v 1.29 2003/04/12 02:14:52 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.miso.client;
|
package com.threerings.miso.client;
|
||||||
|
|
||||||
@@ -30,15 +30,12 @@ public class IsoSceneViewModel
|
|||||||
/** Number of fine coordinates on each axis within a tile. */
|
/** Number of fine coordinates on each axis within a tile. */
|
||||||
public int finegran;
|
public int finegran;
|
||||||
|
|
||||||
/** Scene dimensions in tile count. */
|
|
||||||
public int scenewid, scenehei;
|
|
||||||
|
|
||||||
/** Size of the view in tile count. */
|
/** Size of the view in tile count. */
|
||||||
public int scenevwid, scenevhei;
|
public int scenevwid, scenevhei;
|
||||||
|
|
||||||
/** Whether or not this view can extend beyond the bounds defined by
|
/** Whether or not this view can extend beyond the bounds defined by
|
||||||
* the view width and height. True if it cannot, false if it can. */
|
* the view width and height. True if it cannot, false if it can. */
|
||||||
public boolean bounded = true;
|
public boolean bounded = false;
|
||||||
|
|
||||||
/** The bounds of the view in screen pixel coordinates. */
|
/** The bounds of the view in screen pixel coordinates. */
|
||||||
public Rectangle bounds;
|
public Rectangle bounds;
|
||||||
@@ -46,21 +43,12 @@ public class IsoSceneViewModel
|
|||||||
/** The position in pixels at which tile (0, 0) is drawn. */
|
/** The position in pixels at which tile (0, 0) is drawn. */
|
||||||
public Point origin;
|
public Point origin;
|
||||||
|
|
||||||
/** The total number of tile rows to render the full view. */
|
|
||||||
public int tilerows;
|
|
||||||
|
|
||||||
/** The length of a tile edge in pixels. */
|
/** The length of a tile edge in pixels. */
|
||||||
public float tilelen;
|
public float tilelen;
|
||||||
|
|
||||||
/** The y-intercept of the x-axis line. */
|
|
||||||
public int bX;
|
|
||||||
|
|
||||||
/** The slope of the x- and y-axis lines. */
|
/** The slope of the x- and y-axis lines. */
|
||||||
public float slopeX, slopeY;
|
public float slopeX, slopeY;
|
||||||
|
|
||||||
/** The x-axis line. */
|
|
||||||
public Point[] lineX;
|
|
||||||
|
|
||||||
/** The length between fine coordinates in pixels. */
|
/** The length between fine coordinates in pixels. */
|
||||||
public float finelen;
|
public float finelen;
|
||||||
|
|
||||||
@@ -78,12 +66,6 @@ public class IsoSceneViewModel
|
|||||||
*/
|
*/
|
||||||
public IsoSceneViewModel ()
|
public IsoSceneViewModel ()
|
||||||
{
|
{
|
||||||
// set the scene tile dimensions
|
|
||||||
scenewid = MisoConfig.config.getValue(
|
|
||||||
SCENE_WIDTH_KEY, DEF_SCENE_WIDTH);
|
|
||||||
scenehei = MisoConfig.config.getValue(
|
|
||||||
SCENE_HEIGHT_KEY, DEF_SCENE_HEIGHT);
|
|
||||||
|
|
||||||
// and the view dimensions
|
// and the view dimensions
|
||||||
scenevwid = MisoConfig.config.getValue(
|
scenevwid = MisoConfig.config.getValue(
|
||||||
SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH);
|
SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH);
|
||||||
@@ -122,8 +104,6 @@ public class IsoSceneViewModel
|
|||||||
int svwid, int svhei, int offy)
|
int svwid, int svhei, int offy)
|
||||||
{
|
{
|
||||||
// keep track of this stuff
|
// keep track of this stuff
|
||||||
this.scenewid = scenewid;
|
|
||||||
this.scenehei = scenehei;
|
|
||||||
this.tilewid = tilewid;
|
this.tilewid = tilewid;
|
||||||
this.tilehei = tilehei;
|
this.tilehei = tilehei;
|
||||||
this.finegran = finegran;
|
this.finegran = finegran;
|
||||||
@@ -137,13 +117,14 @@ public class IsoSceneViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given tile coordinate is a valid coordinate
|
* Returns whether the given tile coordinate is a valid coordinate in
|
||||||
* within the scene.
|
* our coordinate system (which allows tile coordinates from 0 to
|
||||||
|
* 2^15-1).
|
||||||
*/
|
*/
|
||||||
public boolean isCoordinateValid (int x, int y)
|
public boolean isCoordinateValid (int x, int y)
|
||||||
{
|
{
|
||||||
return (x >= 0 && x < scenewid &&
|
return (x >= 0 && x < Short.MAX_VALUE &&
|
||||||
y >= 0 && y < scenehei);
|
y >= 0 && y < Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,26 +155,6 @@ public class IsoSceneViewModel
|
|||||||
// pre-calculate tile-related data
|
// pre-calculate tile-related data
|
||||||
precalculateTiles();
|
precalculateTiles();
|
||||||
|
|
||||||
// calculate scene-based x-axis line for conversion from
|
|
||||||
// screen to tile coordinates
|
|
||||||
|
|
||||||
// create the x- and y-axis lines
|
|
||||||
lineX = new Point[2];
|
|
||||||
for (int ii = 0; ii < 2; ii++) {
|
|
||||||
lineX[ii] = new Point();
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the starting point
|
|
||||||
lineX[0].setLocation(origin.x, origin.y);
|
|
||||||
bX = (int)-(slopeX * origin.x);
|
|
||||||
|
|
||||||
// determine the ending point
|
|
||||||
lineX[1].x = lineX[0].x + (tilehwid * scenewid);
|
|
||||||
lineX[1].y = lineX[0].y + (int)((slopeX * lineX[1].x) + bX);
|
|
||||||
|
|
||||||
// calculate tile-based x-axis line for conversion from
|
|
||||||
// tile-based pixel to fine coordinates
|
|
||||||
|
|
||||||
// calculate the edge length separating each fine coordinate
|
// calculate the edge length separating each fine coordinate
|
||||||
finelen = tilelen / (float)finegran;
|
finelen = tilelen / (float)finegran;
|
||||||
|
|
||||||
@@ -220,9 +181,6 @@ public class IsoSceneViewModel
|
|||||||
tilelen = (float) Math.sqrt(
|
tilelen = (float) Math.sqrt(
|
||||||
(tilehwid * tilehwid) + (tilehhei * tilehhei));
|
(tilehwid * tilehwid) + (tilehhei * tilehhei));
|
||||||
|
|
||||||
// calculate the number of tile rows to render
|
|
||||||
tilerows = (scenewid * scenehei) - 1;
|
|
||||||
|
|
||||||
// calculate the slope of the x- and y-axis lines
|
// calculate the slope of the x- and y-axis lines
|
||||||
slopeX = (float)tilehei / (float)tilewid;
|
slopeX = (float)tilehei / (float)tilewid;
|
||||||
slopeY = -slopeX;
|
slopeY = -slopeX;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: AStarPathUtil.java,v 1.26 2003/04/07 23:53:41 mdb Exp $
|
// $Id: AStarPathUtil.java,v 1.27 2003/04/12 02:14:52 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.miso.client.util;
|
package com.threerings.miso.client.util;
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ import com.samskivert.util.HashIntMap;
|
|||||||
import com.threerings.media.util.MathUtil;
|
import com.threerings.media.util.MathUtil;
|
||||||
|
|
||||||
import com.threerings.miso.Log;
|
import com.threerings.miso.Log;
|
||||||
import com.threerings.miso.client.DisplayMisoScene;
|
|
||||||
import com.threerings.miso.tile.BaseTile;
|
import com.threerings.miso.tile.BaseTile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +24,19 @@ import com.threerings.miso.tile.BaseTile;
|
|||||||
*/
|
*/
|
||||||
public class AStarPathUtil
|
public class AStarPathUtil
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Provides traversibility information when computing paths.
|
||||||
|
*/
|
||||||
|
public static interface TraversalPred
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Requests to know if the specified traverser (which was provided
|
||||||
|
* in the call to {@link #getPath}) can traverse the specified
|
||||||
|
* tile coordinate.
|
||||||
|
*/
|
||||||
|
public boolean canTraverse (Object traverser, int x, int y);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of <code>Point</code> objects representing a path
|
* Return a list of <code>Point</code> objects representing a path
|
||||||
* from coordinates <code>(ax, by)</code> to <code>(bx, by)</code>,
|
* from coordinates <code>(ax, by)</code> to <code>(bx, by)</code>,
|
||||||
@@ -32,10 +44,9 @@ public class AStarPathUtil
|
|||||||
* scene's base tile layer. Assumes the starting and destination nodes
|
* scene's base tile layer. Assumes the starting and destination nodes
|
||||||
* are traversable by the specified traverser.
|
* are traversable by the specified traverser.
|
||||||
*
|
*
|
||||||
* @param scene the scene in which a path is to be computed.
|
* @param tpred lets us know what tiles are traversible.
|
||||||
* @param tilewid the scene width in tiles.
|
|
||||||
* @param tilehei the scene height in tiles.
|
|
||||||
* @param trav the traverser to follow the path.
|
* @param trav the traverser to follow the path.
|
||||||
|
* @param longest the longest allowable path in tile traversals.
|
||||||
* @param ax the starting x-position in tile coordinates.
|
* @param ax the starting x-position in tile coordinates.
|
||||||
* @param ay the starting y-position in tile coordinates.
|
* @param ay the starting y-position in tile coordinates.
|
||||||
* @param bx the ending x-position in tile coordinates.
|
* @param bx the ending x-position in tile coordinates.
|
||||||
@@ -43,14 +54,13 @@ public class AStarPathUtil
|
|||||||
*
|
*
|
||||||
* @return the list of points in the path.
|
* @return the list of points in the path.
|
||||||
*/
|
*/
|
||||||
public static List getPath (
|
public static List getPath (TraversalPred tpred, Object trav,
|
||||||
DisplayMisoScene scene, int tilewid, int tilehei, Object trav,
|
int longest, int ax, int ay, int bx, int by)
|
||||||
int ax, int ay, int bx, int by)
|
|
||||||
{
|
{
|
||||||
AStarInfo info = new AStarInfo(scene, tilewid, tilehei, trav, bx, by);
|
Info info = new Info(tpred, trav, longest, bx, by);
|
||||||
|
|
||||||
// set up the starting node
|
// set up the starting node
|
||||||
AStarNode s = info.getNode(ax, ay);
|
Node s = info.getNode(ax, ay);
|
||||||
s.g = 0;
|
s.g = 0;
|
||||||
s.h = getDistanceEstimate(ax, ay, bx, by);
|
s.h = getDistanceEstimate(ax, ay, bx, by);
|
||||||
s.f = s.g + s.h;
|
s.f = s.g + s.h;
|
||||||
@@ -62,7 +72,7 @@ public class AStarPathUtil
|
|||||||
while (info.open.size() > 0) {
|
while (info.open.size() > 0) {
|
||||||
|
|
||||||
// pop the best node so far from open
|
// pop the best node so far from open
|
||||||
AStarNode n = (AStarNode)info.open.first();
|
Node n = (Node)info.open.first();
|
||||||
info.open.remove(n);
|
info.open.remove(n);
|
||||||
|
|
||||||
// if node is a goal node
|
// if node is a goal node
|
||||||
@@ -99,30 +109,24 @@ public class AStarPathUtil
|
|||||||
* @param y the y-coordinate for the destination step.
|
* @param y the y-coordinate for the destination step.
|
||||||
*/
|
*/
|
||||||
protected static void considerStep (
|
protected static void considerStep (
|
||||||
AStarInfo info, AStarNode n, int x, int y, int cost)
|
Info info, Node n, int x, int y, int cost)
|
||||||
{
|
{
|
||||||
// skip node if it's outside the map bounds or otherwise impassable
|
// skip node if it's outside the map bounds or otherwise impassable
|
||||||
if (!info.isStepValid(n.x, n.y, x, y)) {
|
if (!info.isStepValid(n.x, n.y, x, y)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's offscreen, bang up the cost considerably
|
|
||||||
if (!info.isCoordinateValid(x, y)) {
|
|
||||||
cost += OFFSCREEN_COST;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate the new cost for this node
|
// calculate the new cost for this node
|
||||||
int newg = n.g + cost;
|
int newg = n.g + cost;
|
||||||
|
|
||||||
// make sure the cost is reasonable (so we don't go crazy computing
|
// make sure the cost is reasonable
|
||||||
// offscreen costs)
|
|
||||||
if (newg > info.maxcost) {
|
if (newg > info.maxcost) {
|
||||||
// Log.info("Rejected costly step.");
|
// Log.info("Rejected costly step.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the node corresponding to this location
|
// retrieve the node corresponding to this location
|
||||||
AStarNode np = info.getNode(x, y);
|
Node np = info.getNode(x, y);
|
||||||
|
|
||||||
// skip if it's already in the open or closed list or if its
|
// skip if it's already in the open or closed list or if its
|
||||||
// actual cost is less than the just-calculated cost
|
// actual cost is less than the just-calculated cost
|
||||||
@@ -157,9 +161,9 @@ public class AStarPathUtil
|
|||||||
*
|
*
|
||||||
* @return the list detailing the path.
|
* @return the list detailing the path.
|
||||||
*/
|
*/
|
||||||
protected static List getNodePath (AStarNode n)
|
protected static List getNodePath (Node n)
|
||||||
{
|
{
|
||||||
AStarNode cur = n;
|
Node cur = n;
|
||||||
ArrayList path = new ArrayList();
|
ArrayList path = new ArrayList();
|
||||||
|
|
||||||
while (cur != null) {
|
while (cur != null) {
|
||||||
@@ -187,176 +191,155 @@ public class AStarPathUtil
|
|||||||
return (int) (ADJACENT_COST * Math.sqrt(xsq * xsq + ysq * ysq));
|
return (int) (ADJACENT_COST * Math.sqrt(xsq * xsq + ysq * ysq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A holding class to contain the wealth of information referenced
|
||||||
|
* while performing an A* search for a path through a tile array.
|
||||||
|
*/
|
||||||
|
protected static class Info
|
||||||
|
{
|
||||||
|
/** Knows whether or not tiles are traversable. */
|
||||||
|
public TraversalPred tpred;
|
||||||
|
|
||||||
|
/** The tile array dimensions. */
|
||||||
|
public int tilewid, tilehei;
|
||||||
|
|
||||||
|
/** The traverser moving along the path. */
|
||||||
|
public Object trav;
|
||||||
|
|
||||||
|
/** The set of open nodes being searched. */
|
||||||
|
public SortedSet open;
|
||||||
|
|
||||||
|
/** The set of closed nodes being searched. */
|
||||||
|
public ArrayList closed;
|
||||||
|
|
||||||
|
/** The destination coordinates in the tile array. */
|
||||||
|
public int destx, desty;
|
||||||
|
|
||||||
|
/** The maximum cost of any path that we'll consider. */
|
||||||
|
public int maxcost;
|
||||||
|
|
||||||
|
public Info (TraversalPred tpred, Object trav,
|
||||||
|
int longest, int destx, int desty)
|
||||||
|
{
|
||||||
|
// save off references
|
||||||
|
this.tpred = tpred;
|
||||||
|
this.trav = trav;
|
||||||
|
this.destx = destx;
|
||||||
|
this.desty = desty;
|
||||||
|
|
||||||
|
// compute our maximum path cost
|
||||||
|
this.maxcost = longest * ADJACENT_COST;
|
||||||
|
|
||||||
|
// construct the open and closed lists
|
||||||
|
open = new TreeSet();
|
||||||
|
closed = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether moving from the given source to destination
|
||||||
|
* coordinates is a valid move.
|
||||||
|
*/
|
||||||
|
protected boolean isStepValid (int sx, int sy, int dx, int dy)
|
||||||
|
{
|
||||||
|
// not traversable if the destination itself fails test
|
||||||
|
if (!isTraversable(dx, dy)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the step is diagonal, make sure the corners don't impede
|
||||||
|
// our progress
|
||||||
|
if ((Math.abs(dx - sx) == 1) && (Math.abs(dy - sy) == 1)) {
|
||||||
|
return isTraversable(dx, sy) && isTraversable(sx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-diagonals are always traversable
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given coordinate is valid and traversable.
|
||||||
|
*/
|
||||||
|
protected boolean isTraversable (int x, int y)
|
||||||
|
{
|
||||||
|
return tpred.canTraverse(trav, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create the node for the specified point.
|
||||||
|
*/
|
||||||
|
public Node getNode (int x, int y)
|
||||||
|
{
|
||||||
|
// note: this _could_ break for unusual values of x and y.
|
||||||
|
// perhaps use a IntTuple as a key? Bleah.
|
||||||
|
int key = (x << 16) | (y & 0xffff);
|
||||||
|
Node node = (Node) _nodes.get(key);
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(x, y);
|
||||||
|
_nodes.put(key, node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The nodes being considered in the path. */
|
||||||
|
protected HashIntMap _nodes = new HashIntMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that represents a single traversable node in the tile array
|
||||||
|
* along with its current A*-specific search information.
|
||||||
|
*/
|
||||||
|
protected static class Node implements Comparable
|
||||||
|
{
|
||||||
|
/** The node coordinates. */
|
||||||
|
public int x, y;
|
||||||
|
|
||||||
|
/** The actual cheapest cost of arriving here from the start. */
|
||||||
|
public int g;
|
||||||
|
|
||||||
|
/** The heuristic estimate of the cost to the goal from here. */
|
||||||
|
public int h;
|
||||||
|
|
||||||
|
/** The score assigned to this node. */
|
||||||
|
public int f;
|
||||||
|
|
||||||
|
/** The node from which we reached this node. */
|
||||||
|
public Node parent;
|
||||||
|
|
||||||
|
/** The node's monotonically-increasing unique identifier. */
|
||||||
|
public int id;
|
||||||
|
|
||||||
|
public Node (int x, int y)
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
id = _nextid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo (Object o)
|
||||||
|
{
|
||||||
|
int bf = ((Node)o).f;
|
||||||
|
|
||||||
|
// since the set contract is fulfilled using the equality results
|
||||||
|
// returned here, and we'd like to allow multiple nodes with
|
||||||
|
// equivalent scores in our set, we explicitly define object
|
||||||
|
// equivalence as the result of object.equals(), else we use the
|
||||||
|
// unique node id since it will return a consistent ordering for
|
||||||
|
// the objects.
|
||||||
|
if (f == bf) {
|
||||||
|
return (this == o) ? 0 : (id - ((Node)o).id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return f - bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The next unique node id. */
|
||||||
|
protected static int _nextid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** The standard cost to move between nodes. */
|
/** The standard cost to move between nodes. */
|
||||||
public static final int ADJACENT_COST = 10;
|
public static final int ADJACENT_COST = 10;
|
||||||
|
|
||||||
/** The cost to move diagonally. */
|
/** The cost to move diagonally. */
|
||||||
public static final int DIAGONAL_COST = (int) Math.sqrt(
|
public static final int DIAGONAL_COST = (int)Math.sqrt(
|
||||||
(ADJACENT_COST * ADJACENT_COST) * 2);
|
(ADJACENT_COST * ADJACENT_COST) * 2);
|
||||||
|
|
||||||
/** A big old additional cost incurred for offscreen movement. */
|
|
||||||
public static final int OFFSCREEN_COST = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A holding class to contain the wealth of information referenced
|
|
||||||
* while performing an A* search for a path through a tile array.
|
|
||||||
*/
|
|
||||||
class AStarInfo
|
|
||||||
{
|
|
||||||
/** The scene whose base tile layer is being traversed. */
|
|
||||||
public DisplayMisoScene scene;
|
|
||||||
|
|
||||||
/** The tile array dimensions. */
|
|
||||||
public int tilewid, tilehei;
|
|
||||||
|
|
||||||
/** The traverser moving along the path. */
|
|
||||||
public Object trav;
|
|
||||||
|
|
||||||
/** The set of open nodes being searched. */
|
|
||||||
public SortedSet open;
|
|
||||||
|
|
||||||
/** The set of closed nodes being searched. */
|
|
||||||
public ArrayList closed;
|
|
||||||
|
|
||||||
/** The destination coordinates in the tile array. */
|
|
||||||
public int destx, desty;
|
|
||||||
|
|
||||||
/** The maximum cost of any path that we'll consider. */
|
|
||||||
public int maxcost;
|
|
||||||
|
|
||||||
public AStarInfo (
|
|
||||||
DisplayMisoScene scene, int tilewid, int tilehei, Object trav,
|
|
||||||
int destx, int desty)
|
|
||||||
{
|
|
||||||
// save off references
|
|
||||||
this.scene = scene;
|
|
||||||
this.tilewid = tilewid;
|
|
||||||
this.tilehei = tilehei;
|
|
||||||
this.trav = trav;
|
|
||||||
this.destx = destx;
|
|
||||||
this.desty = desty;
|
|
||||||
|
|
||||||
// compute the maximum cost as the maximum onscreen path plus
|
|
||||||
// the maximum offscreen cost
|
|
||||||
this.maxcost = ((tilewid + tilehei) * AStarPathUtil.ADJACENT_COST) +
|
|
||||||
MAX_OFFSCREEN * AStarPathUtil.OFFSCREEN_COST;
|
|
||||||
|
|
||||||
// construct the open and closed lists
|
|
||||||
open = new TreeSet();
|
|
||||||
closed = new ArrayList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the given coordinate is valid based on the
|
|
||||||
* dimensions of the map being traversed.
|
|
||||||
*/
|
|
||||||
protected boolean isCoordinateValid (int x, int y)
|
|
||||||
{
|
|
||||||
return (x >= 0 && y >= 0 && x < tilewid && y < tilehei &&
|
|
||||||
(scene.getBaseTile(x, y) != null));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether moving from the given source to destination
|
|
||||||
* coordinates is a valid move.
|
|
||||||
*/
|
|
||||||
protected boolean isStepValid (int sx, int sy, int dx, int dy)
|
|
||||||
{
|
|
||||||
// not traversable if the destination itself fails test
|
|
||||||
if (!isTraversable(dx, dy)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the step is diagonal, make sure the corners don't impede
|
|
||||||
// our progress
|
|
||||||
if ((Math.abs(dx - sx) == 1) && (Math.abs(dy - sy) == 1)) {
|
|
||||||
return isTraversable(dx, sy) && isTraversable(sx, dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// non-diagonals are always traversable
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the given coordinate is valid and traversable.
|
|
||||||
*/
|
|
||||||
protected boolean isTraversable (int x, int y)
|
|
||||||
{
|
|
||||||
return scene.canTraverse(trav, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or create the node for the specified point.
|
|
||||||
*/
|
|
||||||
public AStarNode getNode (int x, int y)
|
|
||||||
{
|
|
||||||
// note: this _could_ break for unusual values of x and y.
|
|
||||||
// perhaps use a IntTuple as a key? Bleah.
|
|
||||||
int key = (x << 16) | (y & 0xffff);
|
|
||||||
AStarNode node = (AStarNode) _nodes.get(key);
|
|
||||||
if (node == null) {
|
|
||||||
node = new AStarNode(x, y);
|
|
||||||
_nodes.put(key, node);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The nodes being considered in the path. */
|
|
||||||
protected HashIntMap _nodes = new HashIntMap();
|
|
||||||
|
|
||||||
/** The maximum number of offscreen points we'll consider. */
|
|
||||||
protected static final int MAX_OFFSCREEN = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents a single traversable node in the tile array
|
|
||||||
* along with its current A*-specific search information.
|
|
||||||
*/
|
|
||||||
class AStarNode implements Comparable
|
|
||||||
{
|
|
||||||
/** The node coordinates. */
|
|
||||||
public int x, y;
|
|
||||||
|
|
||||||
/** The actual cheapest cost of arriving here from the start. */
|
|
||||||
public int g;
|
|
||||||
|
|
||||||
/** The heuristic estimate of the cost to the goal from here. */
|
|
||||||
public int h;
|
|
||||||
|
|
||||||
/** The score assigned to this node. */
|
|
||||||
public int f;
|
|
||||||
|
|
||||||
/** The node from which we reached this node. */
|
|
||||||
public AStarNode parent;
|
|
||||||
|
|
||||||
/** The node's monotonically-increasing unique identifier. */
|
|
||||||
public int id;
|
|
||||||
|
|
||||||
public AStarNode (int x, int y)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
id = _nextid++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo (Object o)
|
|
||||||
{
|
|
||||||
int bf = ((AStarNode)o).f;
|
|
||||||
|
|
||||||
// since the set contract is fulfilled using the equality results
|
|
||||||
// returned here, and we'd like to allow multiple nodes with
|
|
||||||
// equivalent scores in our set, we explicitly define object
|
|
||||||
// equivalence as the result of object.equals(), else we use the
|
|
||||||
// unique node id since it will return a consistent ordering for
|
|
||||||
// the objects.
|
|
||||||
if (f == bf) {
|
|
||||||
return (this == o) ? 0 : (id - ((AStarNode)o).id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return f - bf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The next unique node id. */
|
|
||||||
protected static int _nextid = 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user