Port Paths to AS from java. Also, port (with modifications) AStarPathUtil -> AStarPathSearch which is no longer a singleton and has fewer hidden dependencies (e.g. the restriction on the "longest" arg to getPath). Also, make MisoScenePanel actually create paths now that we have them.

git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@982 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Mike Thomas
2010-08-13 20:28:48 +00:00
parent d8cda89ab3
commit 3b0b6038dc
13 changed files with 1213 additions and 23 deletions
@@ -37,7 +37,7 @@ import flash.events.MouseEvent;
import mx.core.ClassFactory;
import as3isolib.display.primitive.IsoBox;
import as3isolib.core.IsoDisplayObject;
import as3isolib.geom.Pt;
import as3isolib.geom.IsoMath;
import as3isolib.display.scene.IsoScene;
@@ -59,6 +59,11 @@ import com.threerings.media.tile.Colorizer;
import com.threerings.media.tile.NoSuchTileSetError;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tile.TileUtil;
import com.threerings.media.util.AStarPathSearch;
import com.threerings.media.util.AStarPathSearch_Stepper;
import com.threerings.media.util.LineSegmentPath;
import com.threerings.media.util.Path;
import com.threerings.media.util.TraversalPred;
import com.threerings.miso.client.MisoMetricsTransformation;
import com.threerings.miso.client.PrioritizedSceneLayoutRenderer;
import com.threerings.miso.data.MisoSceneModel;
@@ -69,7 +74,7 @@ import com.threerings.miso.util.ObjectSet;
import com.threerings.miso.util.MisoSceneMetrics;
public class MisoScenePanel extends Sprite
implements PlaceView
implements PlaceView, TraversalPred
{
private var log :Log = Log.getLog(MisoScenePanel);
@@ -84,6 +89,8 @@ public class MisoScenePanel extends Sprite
_isoView = new IsoView();
_isoView.setSize(DEF_WIDTH, DEF_HEIGHT);
_vbounds = new Rectangle(0, 0,
_isoView.size.x, _isoView.size.y);
_isoView.addEventListener(MouseEvent.CLICK, onClick);
@@ -279,6 +286,7 @@ public class MisoScenePanel extends Sprite
// First, we add in our new blocks...
for each (var newBlock :SceneBlock in _readyBlocks.toArray()) {
newBlock.render();
newBlock.addToCovered(_covered);
_blocks.put(newBlock.getKey(), newBlock);
}
_readyBlocks = Sets.newSetOf(SceneBlock);
@@ -310,7 +318,7 @@ public class MisoScenePanel extends Sprite
}
}
trace("Scene Block Resolution took: " + (getTimer() - _resStartTime) + "ms");
log.info("Scene Block Resolution took: " + (getTimer() - _resStartTime) + "ms");
// Let's setup some prefetching...
blocks.forEach(function(blockKey :int) :void {
@@ -363,8 +371,10 @@ public class MisoScenePanel extends Sprite
public function canTraverse (traverser :Object, tx :int, ty :int) :Boolean
{
var block :SceneBlock = _blocks.get(SceneBlock.getBlockKey(tx, ty));
return (block == null) ? canTraverseUnresolved(traverser, tx, ty) :
block.canTraverse(traverser, tx, ty);
var baseTraversable :Boolean = (block == null) ? canTraverseUnresolved(traverser, tx, ty) :
block.canTraverseBase(traverser, tx, ty);
return baseTraversable && !_covered.contains(StringUtil.toCoordsString(tx, ty));
}
/**
@@ -384,10 +394,37 @@ public class MisoScenePanel extends Sprite
* sprite in a straight line to its final destination. This is generally only useful if the
* the path goes "off screen".
*/
public function getPath (sprite :Sprite, x :int, y :int, loose :Boolean) :Object // TODO Path
public function getPath (sprite :IsoDisplayObject, x :int, y :int, loose :Boolean) :Path
{
// TODO Path
return null;
// sanity check
if (sprite == null) {
throw new Error("Can't get path for null sprite [x=" + x + ", y=" + y + ".");
}
// compute our longest path from the screen size
var longestPath :int = 3 * (width / _metrics.tilewid);
// get a reasonable tile path through the scene
var start :int = getTimer();
var search :AStarPathSearch = new AStarPathSearch(this, new AStarPathSearch_Stepper());
var points :Array = search.getPath(sprite, longestPath, int(Math.round(sprite.x)),
int(Math.round(sprite.y)), x, y, loose);
// Replace the starting point with the Number values rather than the rounded version...
points[0] = new Point(sprite.x, sprite.y);
var duration :int = getTimer() - start;
// sanity check the number of nodes searched so that we can keep an eye out for bogosity
if (duration > 500) {
log.warning("Considered a lot of nodes for path from " +
StringUtil.toCoordsString(sprite.x, sprite.y) + " to " +
StringUtil.toCoordsString(x, y) +
" [duration=" + duration + "].");
}
// construct a path object to guide the sprite on its merry way
return (points == null) ? null : LineSegmentPath.createWithList(points);
}
protected var _model :MisoSceneModel;
@@ -433,6 +470,10 @@ public class MisoScenePanel extends Sprite
/** If any block happens to resolve should we currently skip calling completion. */
protected var _skipComplete :Boolean
protected var _vbounds :Rectangle;
protected var _covered :Set = Sets.newSetOf(String);
protected const DEF_WIDTH :int = 985;
protected const DEF_HEIGHT :int = 560;
+42 -13
View File
@@ -8,7 +8,10 @@ import as3isolib.display.IsoView;
import com.threerings.util.Log;
import com.threerings.util.MathUtil;
import com.threerings.util.Set;
import com.threerings.util.StringUtil;
import com.threerings.media.tile.BaseTile;
import com.threerings.media.tile.Colorizer;
import com.threerings.media.tile.NoSuchTileSetError;
import com.threerings.media.tile.Tile;
@@ -25,7 +28,7 @@ import com.threerings.miso.util.ObjectSet;
public class SceneBlock
{
private var log :Log = Log.getLog(MisoScenePanel);
private var log :Log = Log.getLog(SceneBlock);
public static const BLOCK_SIZE :int = 4;
@@ -149,6 +152,17 @@ public class SceneBlock
}
}
public function addToCovered (covered :Set) :void
{
for each (var sprite :ObjectTileIsoSprite in _objSprites) {
for (var xx :int = sprite.x; xx < sprite.x + sprite.width; xx++) {
for (var yy :int = sprite.y; yy < sprite.y + sprite.length; yy++) {
covered.add(StringUtil.toCoordsString(xx, yy));
}
}
}
}
/**
* Removes our tiles' sprites from the scenes.
*/
@@ -164,22 +178,29 @@ public class SceneBlock
protected function createBaseSprite (tileSet :TileSet, x :int, y :int, tileId :int,
panel :MisoScenePanel) :void
{
var fringeTile :Tile = panel.computeFringeTile(x, y);
var fringeTile :BaseTile = panel.computeFringeTile(x, y);
var tile :Tile = tileSet.getTile(TileUtil.getTileIndex(tileId));
var tile :BaseTile = BaseTile(tileSet.getTile(TileUtil.getTileIndex(tileId)));
var maybeLoaded :Function = function (loaded :Tile) :void {
if (tile.getImage() != null && (fringeTile == null || fringeTile.getImage() != null)) {
_baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics,
fringeTile));
noteTileLoaded();
}
};
var bx :int = getBlockX(_key);
var by :int = getBlockY(_key);
_passable[(y - by) * BLOCK_SIZE + (x - bx)] =
tile.isPassable() && (fringeTile == null || fringeTile.isPassable());
if (tile.getImage() != null && (fringeTile == null || fringeTile.getImage() != null)) {
_baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics, fringeTile));
} else {
noteTileToLoad();
var maybeLoaded :Function = function (loaded :Tile) :void {
if (tile.getImage() != null &&
(fringeTile == null || fringeTile.getImage() != null)) {
_baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics,
fringeTile));
noteTileLoaded();
}
};
if (tile.getImage() == null) {
tile.notifyOnLoad(maybeLoaded);
}
@@ -209,10 +230,16 @@ public class SceneBlock
}
}
public function canTraverse (traverser :Object, tx :int, ty :int) :Boolean
/**
* Returns whether the base & fringe tiles are traversable here.
*/
public function canTraverseBase (traverser :Object, tx :int, ty :int) :Boolean
{
// TODO Path
return true;
// Only handles the base tiles since the objects cross multiple scene blocks...
var bx :int = getBlockX(_key);
var by :int = getBlockY(_key);
return _passable[(ty - by) * BLOCK_SIZE + (tx - bx)];
}
protected function noteTileToLoad () :void
@@ -234,6 +261,8 @@ public class SceneBlock
}
}
protected var _passable :Array = new Array(BLOCK_SIZE * BLOCK_SIZE);
protected var _baseScene :IsoScene;
protected var _objSprites :Array;