diff --git a/src/java/com/threerings/miso/client/DisplayMisoScene.java b/src/java/com/threerings/miso/client/DisplayMisoScene.java index 711fdb3ed..2acfb30b6 100644 --- a/src/java/com/threerings/miso/client/DisplayMisoScene.java +++ b/src/java/com/threerings/miso/client/DisplayMisoScene.java @@ -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; import com.threerings.media.tile.Tile; + +import com.threerings.miso.client.util.AStarPathUtil; import com.threerings.miso.data.MisoScene; 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 * 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 @@ -32,10 +35,11 @@ public interface DisplayMisoScene extends MisoScene /** * Returns true if the supplied traverser can traverse the specified * tile coordinate. The traverser is whatever object is passed along - * to the path finder when a path is being computed. Scene - * implementations which support custom traversal based on the type of - * the traverser will want to reflect the traverser's class and act - * acordingly. + * to the path finder when a path is being computed. + * + *
Scene implementations which support custom traversal based on
+ * 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);
}
diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java
index a61f61eab..c87f8137a 100644
--- a/src/java/com/threerings/miso/client/IsoSceneView.java
+++ b/src/java/com/threerings/miso/client/IsoSceneView.java
@@ -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;
@@ -515,10 +515,12 @@ public class IsoSceneView implements SceneView
_model, sprite.getX(), sprite.getY(), 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
List points = AStarPathUtil.getPath(
- _scene, _model.scenewid, _model.scenehei,
- sprite, src.x, src.y, dest.x, dest.y);
+ _scene, sprite, longestPath, src.x, src.y, dest.x, dest.y);
// construct a path object to guide the sprite on its merry way
return (points == null) ? null :
diff --git a/src/java/com/threerings/miso/client/IsoSceneViewModel.java b/src/java/com/threerings/miso/client/IsoSceneViewModel.java
index 2bb1130d7..04e33cf28 100644
--- a/src/java/com/threerings/miso/client/IsoSceneViewModel.java
+++ b/src/java/com/threerings/miso/client/IsoSceneViewModel.java
@@ -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;
@@ -30,15 +30,12 @@ public class IsoSceneViewModel
/** Number of fine coordinates on each axis within a tile. */
public int finegran;
- /** Scene dimensions in tile count. */
- public int scenewid, scenehei;
-
/** Size of the view in tile count. */
public int scenevwid, scenevhei;
/** 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. */
- public boolean bounded = true;
+ public boolean bounded = false;
/** The bounds of the view in screen pixel coordinates. */
public Rectangle bounds;
@@ -46,21 +43,12 @@ public class IsoSceneViewModel
/** The position in pixels at which tile (0, 0) is drawn. */
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. */
public float tilelen;
- /** The y-intercept of the x-axis line. */
- public int bX;
-
/** The slope of the x- and y-axis lines. */
public float slopeX, slopeY;
- /** The x-axis line. */
- public Point[] lineX;
-
/** The length between fine coordinates in pixels. */
public float finelen;
@@ -78,12 +66,6 @@ public class 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
scenevwid = MisoConfig.config.getValue(
SCENE_VWIDTH_KEY, DEF_SCENE_VWIDTH);
@@ -122,8 +104,6 @@ public class IsoSceneViewModel
int svwid, int svhei, int offy)
{
// keep track of this stuff
- this.scenewid = scenewid;
- this.scenehei = scenehei;
this.tilewid = tilewid;
this.tilehei = tilehei;
this.finegran = finegran;
@@ -137,13 +117,14 @@ public class IsoSceneViewModel
}
/**
- * Returns whether the given tile coordinate is a valid coordinate
- * within the scene.
+ * Returns whether the given tile coordinate is a valid coordinate in
+ * our coordinate system (which allows tile coordinates from 0 to
+ * 2^15-1).
*/
public boolean isCoordinateValid (int x, int y)
{
- return (x >= 0 && x < scenewid &&
- y >= 0 && y < scenehei);
+ return (x >= 0 && x < Short.MAX_VALUE &&
+ y >= 0 && y < Short.MAX_VALUE);
}
/**
@@ -174,26 +155,6 @@ public class IsoSceneViewModel
// pre-calculate tile-related data
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
finelen = tilelen / (float)finegran;
@@ -220,9 +181,6 @@ public class IsoSceneViewModel
tilelen = (float) Math.sqrt(
(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
slopeX = (float)tilehei / (float)tilewid;
slopeY = -slopeX;
diff --git a/src/java/com/threerings/miso/client/util/AStarPathUtil.java b/src/java/com/threerings/miso/client/util/AStarPathUtil.java
index 50c3561a7..839c64124 100644
--- a/src/java/com/threerings/miso/client/util/AStarPathUtil.java
+++ b/src/java/com/threerings/miso/client/util/AStarPathUtil.java
@@ -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;
@@ -11,7 +11,6 @@ import com.samskivert.util.HashIntMap;
import com.threerings.media.util.MathUtil;
import com.threerings.miso.Log;
-import com.threerings.miso.client.DisplayMisoScene;
import com.threerings.miso.tile.BaseTile;
/**
@@ -25,6 +24,19 @@ import com.threerings.miso.tile.BaseTile;
*/
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 Point objects representing a path
* from coordinates (ax, by) to (bx, by),
@@ -32,10 +44,9 @@ public class AStarPathUtil
* scene's base tile layer. Assumes the starting and destination nodes
* are traversable by the specified traverser.
*
- * @param scene the scene in which a path is to be computed.
- * @param tilewid the scene width in tiles.
- * @param tilehei the scene height in tiles.
+ * @param tpred lets us know what tiles are traversible.
* @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 ay the starting y-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.
*/
- public static List getPath (
- DisplayMisoScene scene, int tilewid, int tilehei, Object trav,
- int ax, int ay, int bx, int by)
+ public static List getPath (TraversalPred tpred, Object trav,
+ int longest, 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
- AStarNode s = info.getNode(ax, ay);
+ Node s = info.getNode(ax, ay);
s.g = 0;
s.h = getDistanceEstimate(ax, ay, bx, by);
s.f = s.g + s.h;
@@ -62,7 +72,7 @@ public class AStarPathUtil
while (info.open.size() > 0) {
// pop the best node so far from open
- AStarNode n = (AStarNode)info.open.first();
+ Node n = (Node)info.open.first();
info.open.remove(n);
// if node is a goal node
@@ -99,30 +109,24 @@ public class AStarPathUtil
* @param y the y-coordinate for the destination step.
*/
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
if (!info.isStepValid(n.x, n.y, x, y)) {
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
int newg = n.g + cost;
- // make sure the cost is reasonable (so we don't go crazy computing
- // offscreen costs)
+ // make sure the cost is reasonable
if (newg > info.maxcost) {
// Log.info("Rejected costly step.");
return;
}
// 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
// actual cost is less than the just-calculated cost
@@ -157,9 +161,9 @@ public class AStarPathUtil
*
* @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();
while (cur != null) {
@@ -187,176 +191,155 @@ public class AStarPathUtil
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. */
public static final int ADJACENT_COST = 10;
/** The cost to move diagonally. */
- public static final int DIAGONAL_COST = (int) Math.sqrt(
- (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;
+ public static final int DIAGONAL_COST = (int)Math.sqrt(
+ (ADJACENT_COST * ADJACENT_COST) * 2);
}