From affc3e82b711116be314762c89b29a0116e39c0c Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Wed, 15 Aug 2001 22:06:21 +0000 Subject: [PATCH] Fixed up path-finding, path-following, and tile coordinate drawing. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@260 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/cast/CharacterSprite.java | 12 +++- .../com/threerings/media/sprite/Sprite.java | 58 +++++++++++++++---- .../media/sprite/SpriteManager.java | 29 +++++----- .../threerings/miso/client/IsoSceneView.java | 16 +++-- .../miso/client/IsoSceneViewModel.java | 15 ++++- .../miso/client/util/AStarPathUtil.java | 35 ++++++----- .../miso/viewer/ViewerSceneViewPanel.java | 9 +-- 7 files changed, 123 insertions(+), 51 deletions(-) diff --git a/src/java/com/threerings/cast/CharacterSprite.java b/src/java/com/threerings/cast/CharacterSprite.java index 6d5884e22..7463a4340 100644 --- a/src/java/com/threerings/cast/CharacterSprite.java +++ b/src/java/com/threerings/cast/CharacterSprite.java @@ -1,5 +1,5 @@ // -// $Id: CharacterSprite.java,v 1.5 2001/08/15 02:30:27 shaper Exp $ +// $Id: CharacterSprite.java,v 1.6 2001/08/15 22:06:21 shaper Exp $ package com.threerings.miso.scene; @@ -52,8 +52,6 @@ public class AmbulatorySprite extends Sprite implements Traverser // bail if we're at the end of the path if (_dest == null) { - // stop any walking animation - setAnimationDelay(ANIM_NONE); return; } @@ -64,6 +62,14 @@ public class AmbulatorySprite extends Sprite implements Traverser setAnimationDelay(0); } + public void stop () + { + super.stop(); + + // stop any walking animation + setAnimationDelay(ANIM_NONE); + } + public boolean canTraverse (Tile tile) { // by default, passability is solely the province of the tile diff --git a/src/java/com/threerings/media/sprite/Sprite.java b/src/java/com/threerings/media/sprite/Sprite.java index 2364e8672..9bb773076 100644 --- a/src/java/com/threerings/media/sprite/Sprite.java +++ b/src/java/com/threerings/media/sprite/Sprite.java @@ -1,5 +1,5 @@ // -// $Id: Sprite.java,v 1.10 2001/08/14 23:35:22 mdb Exp $ +// $Id: Sprite.java,v 1.11 2001/08/15 22:06:21 shaper Exp $ package com.threerings.media.sprite; @@ -80,7 +80,26 @@ public class Sprite public void paint (Graphics2D gfx) { gfx.drawImage(_frame, _drawx, _drawy, null); -// Log.info("Sprite painting image [sprite=" + this + "]."); + } + + /** + * Paint the sprite's path, if any, to the specified graphics context. + * + * @param gfx the graphics context. + */ + public void paintPath (Graphics2D gfx) + { + if (_fullpath == null) return; + + gfx.setColor(Color.red); + Point prev = null; + int size = _fullpath.size(); + for (int ii = 0; ii < size; ii++) { + PathNode n = (PathNode)_fullpath.getNode(ii); + if (prev == null) prev = n.loc; + gfx.drawLine(prev.x, prev.y, n.loc.x, n.loc.y); + prev = n.loc; + } } /** @@ -122,6 +141,19 @@ public class Sprite invalidate(); } + /** + * Stop the sprite from any movement along a path it may be + * engaged in. + */ + public void stop () + { + // TODO: make sure we come to a stop on a full coordinate, + // even in the case where we aborted a path walk mid-traversal. + _dest = null; + _path = null; + _fullpath = null; + } + /** * Set the sprite's active path and start moving it along its * merry way. If the sprite is already moving along a previous @@ -133,12 +165,20 @@ public class Sprite public void move (Path path) { // make sure following the path is a sensible thing to do - if (path == null || path.size() < 2) return; + if (path == null || path.size() < 2) { + // halt movement if we're walking since, regardless of its + // reasonableness, we've been asked to follow a new path + stop(); + return; + } // save an enumeration of the path nodes _path = path.elements(); - // skip the first node since it's our starting position. + // and the full path for potential rendering + _fullpath = path; + + // skip the first node since it's our starting position. // perhaps someday we'll do something with this. _path.nextElement(); @@ -156,7 +196,7 @@ public class Sprite // if no more nodes remain, clear out our path and bail if (_dest == null) { - _path = null; + stop(); return; } @@ -188,11 +228,6 @@ public class Sprite Rectangle dirty = new Rectangle( _drawx, _drawy, _frame.getWidth(null), _frame.getHeight(null)); -// Log.info("Sprite invalidate [x=" + x + ", y=" + y + -// ", dx=" + dirty.x + ", dy=" + dirty.y + -// ", dwidth=" + dirty.width + -// ", dheight=" + dirty.height + "]."); - _spritemgr.addDirtyRect(dirty); } @@ -311,6 +346,9 @@ public class Sprite /** The number of ticks since the last image animation. */ protected int _numTicks; + /** When moving, the full path the sprite is traversing. */ + protected Path _fullpath; + /** The sprite manager. */ protected SpriteManager _spritemgr; } diff --git a/src/java/com/threerings/media/sprite/SpriteManager.java b/src/java/com/threerings/media/sprite/SpriteManager.java index 9c1802a35..6851d3f44 100644 --- a/src/java/com/threerings/media/sprite/SpriteManager.java +++ b/src/java/com/threerings/media/sprite/SpriteManager.java @@ -1,5 +1,5 @@ // -// $Id: SpriteManager.java,v 1.6 2001/08/14 22:54:45 mdb Exp $ +// $Id: SpriteManager.java,v 1.7 2001/08/15 22:06:21 shaper Exp $ package com.threerings.media.sprite; @@ -61,19 +61,6 @@ public class SpriteManager return dirty; } - /** - * Start a sprite moving along a particular path. The sprite will - * continue to be moved along the path until the final destination - * is reached, or until the sprite is brought to a halt by some - * has-yet-to-be-determined means. - * - * @param sprite the sprite to move. - * @param path the path to move the sprite along. - */ - public void moveSprite (Sprite sprite, Path path) - { - } - /** * Render the sprites residing within the given polygon to the * given graphics context. @@ -96,6 +83,20 @@ public class SpriteManager } } + /** + * Render the sprite paths to the given graphics context. + * + * @param gfx the graphics context. + */ + public void renderSpritePaths (Graphics2D gfx) + { + int size = _sprites.size(); + for (int ii = 0; ii < size; ii++) { + Sprite sprite = (Sprite)_sprites.get(ii); + sprite.paintPath(gfx); + } + } + /** * Call tick() on all sprite objects to give them a * chance to move themselves about, change their display image, diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index 7bd682ebf..ceda1f031 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.46 2001/08/15 03:13:06 shaper Exp $ +// $Id: IsoSceneView.java,v 1.47 2001/08/15 22:06:21 shaper Exp $ package com.threerings.miso.scene; @@ -87,6 +87,11 @@ public class IsoSceneView implements EditableSceneView clearDirtyRegions(); } + // draw sprite paths + if (_model.showPaths) { + _spritemgr.renderSpritePaths(gfx); + } + // draw marks at each location if (_model.showLocs) { paintLocations(gfx); @@ -170,7 +175,8 @@ public class IsoSceneView implements EditableSceneView // paint the tile coordinate if desired if (_model.showCoords) { - paintCoords(gfx, xx, yy, poly.xpoints[0], poly.ypoints[0]); + paintCoords(gfx, xx, yy, poly.xpoints[0], + poly.ypoints[0] - _model.tilehhei); } // bail early if we know we've drawn all dirty tiles @@ -567,6 +573,9 @@ public class IsoSceneView implements EditableSceneView return null; } + // TODO: make more visually appealing path segments from start + // to second tile, and penultimate to ultimate tile. + // construct path with starting screen position Path path = new Path(sprite.x, sprite.y); @@ -589,9 +598,6 @@ public class IsoSceneView implements EditableSceneView path.addNode(nspos.x + _model.tilehwid, nspos.y + _model.tilehhei, dir); -// Log.info("Adding node [tx=" + n.x + ", ty=" + n.y + -// ", dir=" + dir + "]."); - prev = n; } diff --git a/src/java/com/threerings/miso/client/IsoSceneViewModel.java b/src/java/com/threerings/miso/client/IsoSceneViewModel.java index 335c77cf8..df26ec8c2 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.7 2001/08/15 01:08:49 mdb Exp $ +// $Id: IsoSceneViewModel.java,v 1.8 2001/08/15 22:06:21 shaper Exp $ package com.threerings.miso.scene; @@ -65,6 +65,9 @@ public class IsoSceneModel /** Whether locations in the scene should be drawn. */ public boolean showLocs; + /** Whether sprite paths should be drawn. */ + public boolean showPaths; + /** * Construct an IsoSceneModel with reasonable default values. */ @@ -126,6 +129,16 @@ public class IsoSceneModel showCoords = show; } + /** + * Set whether sprite paths should be drawn. + * + * @param show whether to show paths. + */ + public void setShowSpritePaths (boolean show) + { + showPaths = show; + } + /** * Set the dimensions of the tiles that comprise the base layer of * the isometric view and therefore drive the view geometry as a diff --git a/src/java/com/threerings/miso/client/util/AStarPathUtil.java b/src/java/com/threerings/miso/client/util/AStarPathUtil.java index 102e7a0b2..0d1933053 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.1 2001/08/15 02:30:27 shaper Exp $ +// $Id: AStarPathUtil.java,v 1.2 2001/08/15 22:06:21 shaper Exp $ package com.threerings.miso.scene.util; @@ -109,22 +109,27 @@ public class AStarPathUtil // skip node if it's impassable // TODO: fix hard-coded consideration of only the base layer - if (!info.trav.canTraverse(info.tiles[x][y][0])) return; + if (!info.trav.canTraverse(info.tiles[x][y][0])) { + return; + } // calculate the new cost for this node - int newg = n.g + 1; // getCost() is always 1? + int newg = n.g + 1; // cost to go node-to-node is always 1 for now // retrieve the node corresponding to this location AStarNode np = getNode(info, 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 - // TODO: shouldn't <= below be >=? if ((info.open.contains(np) || info.closed.contains(np)) && np.g <= newg) { return; } + // remove the node from the open list since we're about to + // modify its score which determines its placement in the list + info.open.remove(np); + // update the node's information np.parent = n; np.g = newg; @@ -134,7 +139,7 @@ public class AStarPathUtil // remove it from the closed list if it's present info.closed.remove(np); - // add it to the open list in case it's not already there + // add it to the open list for further consideration info.open.add(np); } @@ -181,7 +186,7 @@ public class AStarPathUtil */ protected static int getDistanceEstimate (int ax, int ay, int bx, int by) { - return (int)MathUtil.distance(ax, ay, bx, by); + return Math.max(Math.abs(bx - ax), Math.abs(by - ay)); } } @@ -264,14 +269,16 @@ class AStarNode implements Comparable { int bf = ((AStarNode)o).f; - if (f == bf){ - return 0; - } + // 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 object hashcode since it will return a + // consistent, though arbitrary, ordering for the objects. + if (f == bf) { + return (this == o) ? 0 : (hashCode() - o.hashCode()); + } - if (f < bf) { - return -1; - } - - return 1; + return f - bf; } } diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java index ee7af4999..ad85d3b8b 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerSceneViewPanel.java @@ -1,5 +1,5 @@ // -// $Id: ViewerSceneViewPanel.java,v 1.10 2001/08/15 02:30:28 shaper Exp $ +// $Id: ViewerSceneViewPanel.java,v 1.11 2001/08/15 22:06:21 shaper Exp $ package com.threerings.miso.viewer; @@ -41,6 +41,9 @@ public class ViewerSceneViewPanel extends SceneViewPanel // load up the initial scene prepareStartingScene(); + _smodel.setShowCoordinates(true); + _smodel.setShowSpritePaths(true); + PerformanceMonitor.register(this, "paint", 1000); } @@ -92,9 +95,7 @@ public class ViewerSceneViewPanel extends SceneViewPanel // get the path from here to there Path path = _view.getPath(_sprite, x, y); - if (path != null) { - _sprite.move(path); - } + _sprite.move(path); // hackily highlight the tile that was clicked on for happy testing ((EditableSceneView)_view).setHighlightedFull(x, y);