Use a new, fancy version of the Iso lib scene layout renderer that takes into account a render-priority for use in handling overlapping iso objects. This may want some additional optimization in the future, but we'll see if that's really required.
git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@937 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -27,7 +27,7 @@ public class BaseTileIsoSprite extends TileIsoSprite
|
|||||||
public function BaseTileIsoSprite (x :int, y :int, tileId :int, tile :Tile,
|
public function BaseTileIsoSprite (x :int, y :int, tileId :int, tile :Tile,
|
||||||
metrics :MisoSceneMetrics)
|
metrics :MisoSceneMetrics)
|
||||||
{
|
{
|
||||||
super(x, y, tileId, tile, metrics);
|
super(x, y, tileId, tile, 0, metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function layout (x :int, y :int, tile :Tile) :void
|
public override function layout (x :int, y :int, tile :Tile) :void
|
||||||
|
|||||||
@@ -30,18 +30,7 @@ import flash.geom.Rectangle;
|
|||||||
|
|
||||||
import flash.events.MouseEvent;
|
import flash.events.MouseEvent;
|
||||||
|
|
||||||
import com.threerings.crowd.client.PlaceView;
|
import mx.core.ClassFactory;
|
||||||
import com.threerings.crowd.data.PlaceObject;
|
|
||||||
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.miso.client.MisoMetricsTransformation;
|
|
||||||
import com.threerings.miso.data.MisoSceneModel;
|
|
||||||
import com.threerings.miso.data.ObjectInfo;
|
|
||||||
import com.threerings.miso.util.MisoContext;
|
|
||||||
import com.threerings.miso.util.ObjectSet;
|
|
||||||
import com.threerings.miso.util.MisoSceneMetrics;
|
|
||||||
|
|
||||||
import as3isolib.display.primitive.IsoBox;
|
import as3isolib.display.primitive.IsoBox;
|
||||||
import as3isolib.geom.Pt;
|
import as3isolib.geom.Pt;
|
||||||
@@ -50,9 +39,26 @@ import as3isolib.display.scene.IsoGrid;
|
|||||||
import as3isolib.display.scene.IsoScene;
|
import as3isolib.display.scene.IsoScene;
|
||||||
import as3isolib.display.IsoView;
|
import as3isolib.display.IsoView;
|
||||||
|
|
||||||
|
import com.threerings.crowd.client.PlaceView;
|
||||||
|
import com.threerings.crowd.data.PlaceObject;
|
||||||
|
import com.threerings.util.Log;
|
||||||
|
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.miso.client.MisoMetricsTransformation;
|
||||||
|
import com.threerings.miso.client.PrioritizedSceneLayoutRenderer;
|
||||||
|
import com.threerings.miso.data.MisoSceneModel;
|
||||||
|
import com.threerings.miso.data.ObjectInfo;
|
||||||
|
import com.threerings.miso.util.MisoContext;
|
||||||
|
import com.threerings.miso.util.ObjectSet;
|
||||||
|
import com.threerings.miso.util.MisoSceneMetrics;
|
||||||
|
|
||||||
public class MisoScenePanel extends Sprite
|
public class MisoScenePanel extends Sprite
|
||||||
implements PlaceView
|
implements PlaceView
|
||||||
{
|
{
|
||||||
|
private var log :Log = Log.getLog(MisoScenePanel);
|
||||||
|
|
||||||
public function MisoScenePanel (ctx :MisoContext, metrics :MisoSceneMetrics)
|
public function MisoScenePanel (ctx :MisoContext, metrics :MisoSceneMetrics)
|
||||||
{
|
{
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
@@ -97,7 +103,7 @@ public class MisoScenePanel extends Sprite
|
|||||||
_isoView.removeAllScenes();
|
_isoView.removeAllScenes();
|
||||||
|
|
||||||
var scene :IsoScene = new IsoScene();
|
var scene :IsoScene = new IsoScene();
|
||||||
|
scene.layoutRenderer = new ClassFactory(PrioritizedSceneLayoutRenderer);
|
||||||
var time :int = getTimer();
|
var time :int = getTimer();
|
||||||
var baseArr :Array = [];
|
var baseArr :Array = [];
|
||||||
|
|
||||||
@@ -130,7 +136,7 @@ public class MisoScenePanel extends Sprite
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tileSet == null) {
|
if (tileSet == null) {
|
||||||
trace("TileManager returned null tilset: " +
|
log.warning("TileManager returned null tilset: " +
|
||||||
TileUtil.getTileSetId(tileId));
|
TileUtil.getTileSetId(tileId));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -161,14 +167,15 @@ public class MisoScenePanel extends Sprite
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (objTileSet == null) {
|
if (objTileSet == null) {
|
||||||
trace("TileManager returned null TileSet: " + TileUtil.getTileSetId(objTileId));
|
log.warning("TileManager returned null TileSet: " +
|
||||||
|
TileUtil.getTileSetId(objTileId));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.addChild(
|
scene.addChild(
|
||||||
new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId,
|
new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId,
|
||||||
objTileSet.getTile(TileUtil.getTileIndex(objTileId), getColorizer(objInfo)),
|
objTileSet.getTile(TileUtil.getTileIndex(objTileId), getColorizer(objInfo)),
|
||||||
_metrics));
|
objInfo.priority, _metrics));
|
||||||
}
|
}
|
||||||
|
|
||||||
time = getTimer();
|
time = getTimer();
|
||||||
|
|||||||
@@ -19,15 +19,17 @@
|
|||||||
|
|
||||||
package com.threerings.miso.client {
|
package com.threerings.miso.client {
|
||||||
|
|
||||||
|
import com.threerings.media.tile.ObjectTile;
|
||||||
import com.threerings.media.tile.Tile;
|
import com.threerings.media.tile.Tile;
|
||||||
import com.threerings.miso.util.MisoSceneMetrics;
|
import com.threerings.miso.util.MisoSceneMetrics;
|
||||||
|
|
||||||
public class ObjectTileIsoSprite extends TileIsoSprite
|
public class ObjectTileIsoSprite extends TileIsoSprite
|
||||||
{
|
{
|
||||||
public function ObjectTileIsoSprite (x :int, y :int, tileId :int, tile :Tile,
|
public function ObjectTileIsoSprite (x :int, y :int, tileId :int, tile :Tile,
|
||||||
metrics :MisoSceneMetrics)
|
priority :int, metrics :MisoSceneMetrics)
|
||||||
{
|
{
|
||||||
super(x, y, tileId, tile, metrics);
|
super(x, y, tileId, tile, ObjectTile(tile).getPriority() == 0 ?
|
||||||
|
priority : ObjectTile(tile).getPriority(), metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function layout (x :int, y :int, tile :Tile) :void
|
public override function layout (x :int, y :int, tile :Tile) :void
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.miso.client {
|
||||||
|
|
||||||
|
import flash.utils.Dictionary;
|
||||||
|
import flash.utils.getTimer;
|
||||||
|
|
||||||
|
import as3isolib.display.renderers.ISceneLayoutRenderer;
|
||||||
|
import as3isolib.bounds.IBounds;
|
||||||
|
import as3isolib.core.as3isolib_internal;
|
||||||
|
import as3isolib.core.IsoDisplayObject;
|
||||||
|
import as3isolib.display.scene.IIsoScene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted from the as3isolib DefaultSceneLayoutRenderer, but thanks to its private vars, I cannot
|
||||||
|
* simply extend that class.
|
||||||
|
*/
|
||||||
|
public class PrioritizedSceneLayoutRenderer
|
||||||
|
implements ISceneLayoutRenderer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Places all of our children in their appropriate rendering order based on their iso bounds
|
||||||
|
* and as necessary, by priority. Priority only comes into play if the iso bounds overlap.
|
||||||
|
*/
|
||||||
|
public function renderScene (scene:IIsoScene):void
|
||||||
|
{
|
||||||
|
// This is a little brute-force. Some suggestions from DefaultSceneLayoutRenderer:
|
||||||
|
// - cache dependencies between frames, only adjust invalidated objects, keeping old
|
||||||
|
// ordering as best as possible
|
||||||
|
// - screen space subdivision to limit dependency scan
|
||||||
|
// - set the invalidated children first, then do a rescan to make sure everything else is
|
||||||
|
// where it needs to be, too? probably need to order the invalidated children sets from
|
||||||
|
// low to high index
|
||||||
|
|
||||||
|
// Reset everything for this rendering pass.
|
||||||
|
_scene = scene;
|
||||||
|
_dependencies = new Dictionary();
|
||||||
|
_depth = 0;
|
||||||
|
_visited = new Dictionary();
|
||||||
|
|
||||||
|
var startTime:uint = getTimer();
|
||||||
|
|
||||||
|
// Use the non-rearranging display list so that the dependency sort will tend to
|
||||||
|
// create similar output each pass
|
||||||
|
var children:Array = _scene.displayListChildren;
|
||||||
|
|
||||||
|
// Full naive cartesian scan, see what objects are behind/in front of child[ii]
|
||||||
|
var max:uint = children.length;
|
||||||
|
for (var ii :uint = 0; ii < max; ii++)
|
||||||
|
{
|
||||||
|
var objA:IsoDisplayObject = children[ii];
|
||||||
|
|
||||||
|
var rightA:Number = objA.x + objA.width;
|
||||||
|
var frontA:Number = objA.y + objA.length;
|
||||||
|
var topA:Number = objA.z + objA.height;
|
||||||
|
|
||||||
|
var prioA :int = objA is PriorityIsoDisplayObject ?
|
||||||
|
PriorityIsoDisplayObject(objA).getPriority() : 0;
|
||||||
|
|
||||||
|
for (var jj :uint = ii + 1; jj < max; jj++)
|
||||||
|
{
|
||||||
|
var objB:IsoDisplayObject = children[jj];
|
||||||
|
|
||||||
|
var prioB :int = objB is PriorityIsoDisplayObject ?
|
||||||
|
PriorityIsoDisplayObject(objB).getPriority() : 0;
|
||||||
|
|
||||||
|
var rightB:Number = objB.x + objB.width;
|
||||||
|
var frontB:Number = objB.y + objB.length;
|
||||||
|
var topB:Number = objB.z + objB.height;
|
||||||
|
|
||||||
|
// See if B should go behind A and vice-versa.
|
||||||
|
var bBehindA :Boolean = ((objB.x < rightA) &&
|
||||||
|
(objB.y < frontA) &&
|
||||||
|
(objB.z < topA));
|
||||||
|
var aBehindB :Boolean = ((objA.x < rightB) &&
|
||||||
|
(objA.y < frontB) &&
|
||||||
|
(objA.z < topB));
|
||||||
|
|
||||||
|
if ((bBehindA && aBehindB)) {
|
||||||
|
// Overlap means we need to use the priority...
|
||||||
|
if (prioA > prioB) {
|
||||||
|
addDependency(objA, objB);
|
||||||
|
} else {
|
||||||
|
addDependency(objB, objA);
|
||||||
|
}
|
||||||
|
} else if (bBehindA) {
|
||||||
|
addDependency(objA, objB);
|
||||||
|
} else if (aBehindB) {
|
||||||
|
addDependency(objB, objA);
|
||||||
|
}
|
||||||
|
// Note - if we find that neither is behind the other, we don't add a dependency
|
||||||
|
// ordering. If they actually do visually overlap due to sticking outside their
|
||||||
|
// bounds, this can sometimes cause inconsistent visuals.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("dependency scan time", getTimer() - startTime, "ms");
|
||||||
|
|
||||||
|
// Set the childrens' depth, using dependency ordering
|
||||||
|
for each (var obj:IsoDisplayObject in children) {
|
||||||
|
if (!_visited[obj]) {
|
||||||
|
place(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear these out so we're not retaining memory between calls
|
||||||
|
_visited = null;
|
||||||
|
_dependencies = null;
|
||||||
|
|
||||||
|
trace("scene layout render time", getTimer() - startTime, "ms (manual sort)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the front-to-back dependency to our map of all such dependencies.
|
||||||
|
*/
|
||||||
|
protected function addDependency (front :IsoDisplayObject, back :IsoDisplayObject) :void
|
||||||
|
{
|
||||||
|
var deps :Array = _dependencies[front];
|
||||||
|
if (deps == null) {
|
||||||
|
deps = [];
|
||||||
|
_dependencies[front] = deps;
|
||||||
|
}
|
||||||
|
deps.push(back);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency-ordered depth placement of the given objects and its dependencies.
|
||||||
|
*/
|
||||||
|
protected function place (obj:IsoDisplayObject):void
|
||||||
|
{
|
||||||
|
_visited[obj] = true;
|
||||||
|
|
||||||
|
for each (var inner:IsoDisplayObject in _dependencies[obj]) {
|
||||||
|
if (!_visited[inner]) {
|
||||||
|
place(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_depth != obj.depth)
|
||||||
|
{
|
||||||
|
_scene.setChildIndex(obj, _depth);
|
||||||
|
}
|
||||||
|
_depth++;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The depth we're currently placing children at. */
|
||||||
|
protected var _depth :uint;
|
||||||
|
|
||||||
|
/** Any objects we've already placed. */
|
||||||
|
protected var _visited :Dictionary;
|
||||||
|
|
||||||
|
/** The scene on which we're operating. */
|
||||||
|
protected var _scene :IIsoScene;
|
||||||
|
|
||||||
|
/** All the front-back dependencies we know about. This maps an object to a list of all
|
||||||
|
* the objects that should be rendered behind (and therefore before) it. */
|
||||||
|
protected var _dependencies :Dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.miso.client {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any Iso object wishing to specify a render priority should do so by implementing this interface.
|
||||||
|
*/
|
||||||
|
public interface PriorityIsoDisplayObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the render priority for the display object.
|
||||||
|
*/
|
||||||
|
function getPriority () :int;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,16 +33,19 @@ import com.threerings.util.Log;
|
|||||||
import com.threerings.miso.util.MisoSceneMetrics;
|
import com.threerings.miso.util.MisoSceneMetrics;
|
||||||
|
|
||||||
public class TileIsoSprite extends IsoDisplayObject
|
public class TileIsoSprite extends IsoDisplayObject
|
||||||
|
implements PriorityIsoDisplayObject
|
||||||
{
|
{
|
||||||
private static var log :Log = Log.getLog(TileIsoSprite);
|
private static var log :Log = Log.getLog(TileIsoSprite);
|
||||||
|
|
||||||
public function TileIsoSprite (x :int, y :int, tileId :int, tile :Tile,
|
public function TileIsoSprite (x :int, y :int, tileId :int, tile :Tile, priority :int,
|
||||||
metrics :MisoSceneMetrics)
|
metrics :MisoSceneMetrics)
|
||||||
{
|
{
|
||||||
_tileId = tileId;
|
_tileId = tileId;
|
||||||
|
|
||||||
_metrics = metrics;
|
_metrics = metrics;
|
||||||
|
|
||||||
|
_priority = priority;
|
||||||
|
|
||||||
moveTo(x, y, 0);
|
moveTo(x, y, 0);
|
||||||
|
|
||||||
layout(x, y, tile);
|
layout(x, y, tile);
|
||||||
@@ -93,8 +96,15 @@ public class TileIsoSprite extends IsoDisplayObject
|
|||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPriority () :int
|
||||||
|
{
|
||||||
|
return _priority;
|
||||||
|
}
|
||||||
|
|
||||||
protected var _tileId :int;
|
protected var _tileId :int;
|
||||||
|
|
||||||
|
protected var _priority :int;
|
||||||
|
|
||||||
protected var _metrics :MisoSceneMetrics;
|
protected var _metrics :MisoSceneMetrics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user