Checkpoint commit wiring up a CrowdStageScenePanel that handles Occupant locations and making a sprite for them on the screen. Lots of TODOs still in this stuff, esp. related to Pathing.

git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@944 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Mike Thomas
2010-08-06 05:23:59 +00:00
parent 607d85ff9b
commit ea5b4e7959
4 changed files with 794 additions and 13 deletions
@@ -0,0 +1,68 @@
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// 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.stage.client {
import com.threerings.miso.util.MisoSceneMetrics;
import com.threerings.miso.util.MisoUtil;
import com.threerings.stage.data.StageLocation;
import as3isolib.display.primitive.IsoBox;
public class CharacterIsoSprite extends IsoBox
{
public function CharacterIsoSprite (bodyOid :int, metrics :MisoSceneMetrics)
{
_metrics = metrics;
_bodyOid = bodyOid;
setSize(1, 1, 2);
}
public function isMoving () :Boolean
{
return false; //TODO Path
}
public function getBodyOid () :int
{
return _bodyOid;
}
public function placeAtLoc (loc :StageLocation) :void
{
moveTo(MisoUtil.fullToTile(loc.x), MisoUtil.fullToTile(loc.y), 0);
// TODO Components - handle orientation
render();
}
public function move (path :Object /*TODO Path */) :void
{
// TODO Path
}
public function cancelMove () :void
{
// TODO Path
}
protected var _bodyOid :int;
protected var _metrics :MisoSceneMetrics;
}
}
@@ -0,0 +1,712 @@
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// 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.stage.client {
import flash.geom.Point;
import flash.events.MouseEvent;
import com.threerings.crowd.client.OccupantObserver;
import com.threerings.crowd.data.OccupantInfo;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.util.Controller;
import com.threerings.util.Integer;
import com.threerings.util.Iterator;
import com.threerings.util.Log;
import com.threerings.util.Map;
import com.threerings.util.Maps;
import com.threerings.util.MathUtil;
import com.threerings.util.StringUtil;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SceneLocation;
import com.threerings.whirled.spot.data.SpotCodes;
import com.threerings.whirled.spot.data.SpotSceneObject;
import com.threerings.whirled.util.WhirledContext;
import com.threerings.stage.data.StageSceneObject;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.util.StageContext;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.presents.dobj.EntryUpdatedEvent;
import com.threerings.presents.dobj.SetAdapter;
import com.threerings.presents.dobj.SetListener;
import com.threerings.miso.util.MisoSceneMetrics;
import com.threerings.miso.util.MisoUtil;
import as3isolib.geom.Pt;
public class CrowdStageScenePanel extends StageScenePanel
implements OccupantObserver
{
private var log :Log = Log.getLog(CrowdStageScenePanel);
public function CrowdStageScenePanel (sCtx :StageContext, cCtx :CrowdContext, ctrl :Controller,
metrics :MisoSceneMetrics)
{
super(sCtx, ctrl, metrics);
_cCtx = cCtx;
// compute our proximity radius (one visible screen diagonal);
// also don't let it shrink when we're birded
_proxrad = int(Math.max(_proxrad, Math.sqrt(_isoView.size.x*_isoView.size.x +
_isoView.size.y*_isoView.size.y)));
recomputeProximate();
}
override public function willEnterPlace (plObj :PlaceObject) :void
{
super.willEnterPlace(plObj);
_scObj = StageSceneObject(plObj);
plObj.addListener(_occupantListener);
_cCtx.getOccupantDirector().addOccupantObserver(this);
updateDisplayForScene();
}
protected function updateDisplayForScene () :void
{
// remove all old-scene sprites
clearAllSprites();
// fake an occupant entry for all scene occupants
for each (var occupantInfo :OccupantInfo in _scObj.occupantInfo.toArray()) {
occupantEntered(occupantInfo);
}
// start out with the view centered on our sprite so that we
// resolve the appropriate scene blocks from the get go
centerView();
}
protected function centerView () :void
{
if (_selfSprite != null) {
var viewPt :Point =
_isoView.isoToLocal(new Pt(_selfSprite.x, _selfSprite.y, _selfSprite.z));
moveBy(new Point(viewPt.x - _isoView.width / 2, viewPt.y - _isoView.height / 2));
}
}
/**
* Clear all the sprites from the scene, even our own.
*/
protected function clearAllSprites () :void
{
// clear the actual sprites
//TODO clearSprites();
// and clear all of our wacky lists
_sprites.clear();
_arriveLists.clear();
_pendingRemoveSprites.clear();
}
override public function didLeavePlace (plObj :PlaceObject) :void
{
super.didLeavePlace(plObj);
plObj.removeListener(_occupantListener);
_cCtx.getOccupantDirector().removeOccupantObserver(this);
}
public function occupantEntered (info :OccupantInfo) :void
{
// we do mostly the same thing for entry and update
occupantUpdated(null, info);
}
/**
* Called when we arrive at our new location, all no longer proximate occupant's sprites are
* booted and any newly proximate occupants have sprites created for them.
*/
protected function recomputeProximate () :void
{
if (_scObj == null) {
return; // nothing doing!
}
for each (var sloc :SceneLocation in _scObj.occupantLocs) {
var sprite :CharacterIsoSprite = getSprite(sloc.bodyOid);
if (isProximateToLoc(sloc)) {
if (sprite == null) {
// fake an update which will create their sprite
occupantMoved(sloc, sloc, false);
}
} else if (sprite != null) {
removeSprite(sprite);
}
}
}
/**
* Returns true if this occupant is proximate to ourself.
*/
public function isProximate (info :OccupantInfo) :Boolean
{
var sloc :SceneLocation = locationForBody(info.getBodyOid());
return (sloc != null && isProximateToLoc(sloc));
}
/**
* Returns true if this user is close enough to us that we want to go to the trouble of
* creating a sprite for them and all the business.
*/
protected function isProximateToLoc (sceneLoc :SceneLocation) :Boolean
{
// make sure we know where we are
var mySceneLoc :SceneLocation = locationForBody(myOid());
if (mySceneLoc == null) {
return false;
}
// if they're within one screen diagonal of us, they're proximate
var myLoc :StageLocation = StageLocation(mySceneLoc.loc);
var loc :StageLocation = StageLocation(sceneLoc.loc);
var pos :Point = _isoView.isoToLocal(new Pt(loc.x, loc.y, 0));
var myPos :Point = _isoView.isoToLocal(new Pt(myLoc.x, myLoc.y, 0));
return int(MathUtil.distance(pos.x, pos.y, myPos.x, myPos.y)) < _proxrad;
}
public function occupantLeft (info :OccupantInfo) :void
{
// remove the occupant's sprite
var oid :int = info.getBodyOid();
if (oid == myOid()) {
// never remove our own sprite!
return;
}
var sprite :CharacterIsoSprite = getSprite(oid);
if (sprite == null) {
if (isProximate(info)) {
log.warning("Proximate occupant left, but no sprite to remove " + info + ".");
}
return;
}
// if they are already moving, stick them in the pending remove
// table so that we give them the boot when they arrive at their destination
if (sprite.isMoving()) {
_pendingRemoveSprites.put(oid, sprite);
return;
}
// if the sprite is already at a portal, go ahead and remove them
var sprLoc :Point = _isoView.localToIso(new Point(sprite.x, sprite.y));
for (var iter :Iterator = _scene.getPortals(); iter.hasNext(); ) {
var port :Portal = Portal(iter.next());
var portLoc :StageLocation = StageLocation(port.loc);
if (portLoc.x == sprLoc.x && portLoc.y == sprLoc.y) {
removeSprite(sprite);
return;
}
}
// walk them to the default entrance; note: we have to put them in the pending table
// *before* we call moveSprite because moveSprite might decide to immediately warp them to
// their destination and call handleLocationArrived() directly which will expect them to be
// in the pending table at that point
_pendingRemoveSprites.put(oid, sprite);
moveSpriteFromScene(sprite);
}
public function occupantUpdated (oldinfo :OccupantInfo, newinfo :OccupantInfo) :void
{
var bodyOid :int = newinfo.getBodyOid();
var sloc :SceneLocation = locationForBody(bodyOid);
if (sloc == null || !isProximateToLoc(sloc)) {
return;
}
// look up their character sprite
var sprite :CharacterIsoSprite = getSprite(newinfo.getBodyOid());
if (sprite == null) {
// ...creating one if necessary
sprite = createAndAddSprite(OccupantInfo(newinfo), null);
// if we couldn't create the sprite for some reason, we can stop now
if (sprite == null) {
return;
}
} else {
// ...updating it if we've already got one
updateOccupantSprite(sprite, newinfo);
// make sure the sprite is no longer set to remove, in case it was
_pendingRemoveSprites.remove(bodyOid);
}
// if this is the first time they entered the scene, fake a move to their starting position
if (oldinfo == null) {
// fake a "moved" to their starting position
occupantMoved(sloc, sloc, false);
}
}
/**
* Performs any updates required to the occupant's character sprite given the updated occupant
* info.
*/
protected function updateOccupantSprite (sprite :CharacterIsoSprite, info :OccupantInfo) :void
{
// Nothing by default.
}
/**
* Called when an occupant has changed location. Updates clusters for this occupant and moves
* their sprite.
*/
protected function occupantMoved (oloc :SceneLocation, nloc :SceneLocation,
reallyMoved :Boolean) :void
{
var sprite :CharacterIsoSprite = getSprite(nloc.bodyOid);
// if their new location is not proximate, yank their sprite
if (!isProximateToLoc(nloc)) {
if (sprite != null) {
// if they are visible, walk them to their new location
if (true/*TODO Path _vbounds.intersects(sprite.getBounds())*/) {
moveSpriteToLoc(sprite, nloc.loc);
}
// now queue them up for removal on arrival as appropriate
if (sprite.isMoving()) {
_pendingRemoveSprites.put(nloc.bodyOid, sprite);
} else {
removeSprite(sprite);
}
}
}
// now walk their sprite to its new location
if (sprite == null) {
var info :OccupantInfo = _cCtx.getOccupantDirector().getOccupantInfo(nloc.bodyOid);
if (info != null) {
sprite = createAndAddSprite(info, oloc);
} else {
log.warning("Can't update location of unknown '" + nloc + "' (" + who(nloc) + ").");
return;
}
}
moveSpriteToLoc(sprite, nloc.loc);
/*TODO Portals
// if self going to a portal, use exiting mode.
// if not-moving someone else to a portal, don't adjust mode
// all other cases, set normal scene mode
if (isPortal(nloc.loc)) {
if (isMe) {
sprite.setExiting();
} else if (moving) {
sprite.setNormalSceneMode();
}
} else {
sprite.setNormalSceneMode();
}*/
}
/**
* Moves the sprite to the referenced location.
*/
protected function moveSpriteToLoc (sprite :CharacterIsoSprite, loc :Location) :void
{
var sloc :StageLocation = StageLocation(loc);
// obtain the screen coordinates of the location
// if they're not already standing where we want them...
if (sprite.x != sloc.x || sprite.y != sloc.y || sprite.isMoving()) {
// ...move them there; but note whether they were put on a path or just warped
// immediately
if (!moveSprite(sprite, sloc)) {
return;
}
}
// if they're already there or they were warped there we want to invoke the arrival
// processing
handleSpriteArrived(sprite, new Date().time);
}
/**
* Move the specified sprite to the specified screen coordinates along a tile path.
*
* @return true if the sprite was warped immediately to that position, false if they were set
* upon a path to it.
*/
protected function moveSprite (sprite :CharacterIsoSprite, loc :StageLocation) :Boolean
{
var cx :int = sprite.x;
var cy :int = sprite.y;
// if this panel is not yet showing, warp the sprite directly
if (!visible) {
sprite.cancelMove();
sprite.placeAtLoc(loc);
return true;
}
// if the source and destination are both offscreen, warp the
// sprite to where they are going
// TODO Path boolean endsOff = !_vbounds.contains(nx, ny);
if (false /*TODO Path!_vbounds.intersects(sprite.getBounds()) && endsOff*/) {
sprite.cancelMove();
sprite.placeAtLoc(loc);
return true;
}
// if we are obviously warping (i.e. we moved a great distance),
// just blink into position and attempt to do so cleanly
//TODO Path int dx = Math.abs(nx - (_vbounds.x + _vbounds.width/2));
//TODO Path int dy = Math.abs(ny - (_vbounds.y + _vbounds.height/2));
if (sprite == _selfSprite/*TODO Path (dx > 2*_vbounds.width || dy > 2*_vbounds.height) &&
(sprite == _selfSprite)*/) {
//TODO Path log.info("Warp-a-saurus! " + StringUtil.toString(_vbounds) +
//TODO Path " -> " + StringUtil.toCoordsString(loc.x, loc.y));
sprite.cancelMove();
sprite.placeAtLoc(loc);
// delay repaint until we resolve our new blocks
centerView();
return true;
}
// if we made it this far, we can actually try to compute a path
// for this sprite; if the end of the path is off-screen, allow "partial" paths
var path :Object = null;//TODO Path TilePath = TilePath(getPath(yocs, nx, ny, endsOff));
if (path == null) {
/*TODO Path log.info("Unable to compute path from " +
StringUtil.toCoordsString(cx, cy) + " to " +
StringUtil.toCoordsString(loc.x, loc.y) + "; warping.");*/
sprite.cancelMove();
sprite.placeAtLoc(loc);
return true;
}
// set the sprite on a path to their new location
path.setVelocity(SPRITE_PATH_VELOCITY);
sprite.move(path);
return false;
}
/**
* Animate a sprite leaving the scene.
*/
protected function moveSpriteFromScene (sprite :CharacterIsoSprite) :void
{
moveSpriteToLoc(sprite, _scene.getDefaultEntrance().getLocation());
}
/**
* A convenience method for getting our OID.
*/
protected function myOid () :int
{
return _cCtx.getClient().getClientObject().getOid();
}
protected function who (loc :SceneLocation) :String
{
var oinfo :OccupantInfo = OccupantInfo(_scObj.occupantInfo.get(loc.bodyOid));
return (oinfo == null) ? ("" + loc.bodyOid) : oinfo.username.toString();
}
protected function createAndAddSprite (info :OccupantInfo,
loc :SceneLocation) :CharacterIsoSprite
{
var sprite :CharacterIsoSprite = createSprite(info);
// stick them in the appropriate location
if (loc == null) {
loc = locationForBody(info.getBodyOid());
}
if (loc == null) {
log.warning("Requested to create sprite for locationless occupant " + info + ".",
new Error());
return null;
}
// set their location and start tracking them
sprite.placeAtLoc(StageLocation(loc.loc));
_objScene.addChild(sprite);
_sprites.put(info.getBodyOid(), sprite);
if (sprite.getBodyOid() == myOid()) {
_selfSprite = sprite;
}
return sprite;
}
override public function handleMousePressed (hobject :Object, event :MouseEvent) :Boolean
{
var viewPt :Point = _isoView.globalToLocal(new Point(event.stageX, event.stageY));
var iso :Point = _isoView.localToIso(new Point(viewPt.x, viewPt.y));
// Move ourselves to the spot clicked.
handleLocationClicked(new StageLocation(MisoUtil.tileToFull(iso.x),
MisoUtil.tileToFull(iso.y), 0));
return true;
}
protected function displayFeedback (msg :String) :void
{
throw new Error("abstract");
}
public function handleLocationClicked (loc :StageLocation) :void
{
// normalize the click to the center of the clicked tile and check
// to see if it is occupied
var tx :int = MisoUtil.fullToTile(loc.x);
var ty :int = MisoUtil.fullToTile(loc.y);
loc.x = MisoUtil.tileToFull(tx, 2);
loc.y = MisoUtil.tileToFull(ty, 2);
if (tileOccupied(tx, ty, false)) {
log.info("Not moving to occupied location " + loc + ".");
displayFeedback(SpotCodes.INVALID_LOCATION);
return;
}
// see if we can walk there and what orientation we'd face once we got there
var orient :int = checkWalkToLoc(loc);
if (orient == -1) {
// if the location is on a passable tile, let the user know why we rejected their click
if (canTraverse(null, tx, ty)) {
displayFeedback("m.cant_get_there");
}
// TODO Path - remove this
changeLocation(loc);
return;
}
// adjust the orientation and head there
loc.orient = orient;
changeLocation(loc);
}
protected function changeLocation (loc :StageLocation) :void
{
throw new Error("abstract");
}
/**
* Returns true if the specified tile coordinate is occupied by any sprites or if the
* specified tile is inside an existing cluster.
*/
protected function tileOccupied (tx :int, ty :int, countSelf :Boolean) :Boolean
{
var self :CharacterIsoSprite = getSprite(myOid());
// if we or the scene object is gone, don't freak out
if (self == null || _scObj == null) {
return false;
}
// next see if any room occupant is standing here
for each (var loc :SceneLocation in _scObj.occupantLocs.toArray()) {
if (!countSelf && loc.bodyOid == myOid()) {
continue;
}
var sloc :StageLocation = StageLocation(loc.loc);
if (MisoUtil.fullToTile(sloc.x) == tx && MisoUtil.fullToTile(sloc.y) == ty) {
return true;
}
}
return false;
}
/**
* Checks to see if we can compute a path to the specified location.
*
* @return the orientation the sprite would have upon arrival or -1 if
* we cannot compute a path to the specified location.
*/
protected function checkWalkToLoc (loc :StageLocation) :int
{
// obtain the screen coordinates of the location
var sc :Point = _isoView.isoToLocal(new Pt(loc.x, loc.y, 0));
var us :CharacterIsoSprite = getSprite(myOid());
if (us != null) {
//TODO Path var path :TilePath = TilePath(getPath(us, loc.x, loc.y, false));
//TODO Path return (path == null) ? -1 : path.getFinalOrientation();
return -1;
} else {
return -1;
}
}
protected function createSprite (info :OccupantInfo) :CharacterIsoSprite
{
return new CharacterIsoSprite(info.getBodyOid(), _metrics);
}
protected function getSprite (bodyOid :int) :CharacterIsoSprite
{
return _sprites.get(bodyOid);
}
protected function removeSprite (sprite :CharacterIsoSprite) :void
{
_sprites.remove(sprite.getBodyOid());
}
protected function handleSpriteArrived (sprite :CharacterIsoSprite, tickStamp :int) :void
{
var oid :int = sprite.getBodyOid();
var alist :ArrivalEntry = _arriveLists.remove(oid);
try {
// make sure we have a place object still
if (_scObj == null) {
return;
}
// if we were going to remove this sprite, do it now
if (null != _pendingRemoveSprites.remove(oid)) {
removeSprite(sprite);
return;
}
// look up the location occupied by the user in question
var loc :SceneLocation = locationForBody(oid);
if (loc == null) {
log.warning("Sprite completed path but no location found?",
"oid", oid, "sprite", sprite, "occlocs", _scObj.occupantLocs);
return;
}
handleLocationArrived(sprite, loc);
// notify any arrival listener
if (alist != null && loc.loc.equals(alist.loc)) {
alist.listener(sprite, loc.loc);
}
} finally {
// keep track of the last time we came to rest
if (sprite == _selfSprite) {
_centerStamp = tickStamp;
}
}
}
/**
* Returns the location id of the location at which the player with the specified body oid
* resides.
*/
protected function locationForBody (bodyOid :int) :SceneLocation
{
return (_scObj == null) ? null :
SceneLocation(_scObj.occupantLocs.get(bodyOid));
}
/**
* Called when a sprite has arrived at its location.
*/
protected function handleLocationArrived (sprite :CharacterIsoSprite, loc :SceneLocation) :void
{
// orient them properly
sprite.placeAtLoc(StageLocation(loc.loc));
// if this is us, recompute our proximate sprite set
if (sprite.getBodyOid() == myOid()) {
recomputeProximate();
}
}
/**
* Registers a listener to be notified when the sprite associated with the specified body
* arrives at the specified scene location. If the body is not currently on a path to that
* location, the listener will be dropped. If the body arrives at any other location, the
* request will be dropped. Only if the body completes their current path toward the specified
* location will the listener be notified.
*
* @return true if the listener was added, false if there was no such sprite or they were not
* moving.
*/
public function addArrivalListener (bodyOid :int, loc :Location, listener :Function) :Boolean
{
var sprite :CharacterIsoSprite = getSprite(bodyOid);
if (sprite != null && sprite.isMoving()) {
_arriveLists.put(bodyOid, new ArrivalEntry(loc, listener));
return true;
}
return false;
}
protected function occupantEntryUpdated (event :EntryUpdatedEvent) :void
{
occupantMoved(SceneLocation(event.getOldEntry()), SceneLocation(event.getEntry()), true);
}
protected var _occupantListener :SetListener = new SetAdapter(null, occupantEntryUpdated, null);
protected var _cCtx :CrowdContext;
/** Map bodyOid to all the sprites we're handling. */
protected var _sprites :Map = Maps.newMapOf(int);
/** Map bodyOid to all the sprites we're getting ready to remove. */
protected var _pendingRemoveSprites :Map = Maps.newMapOf(int);
/** Map bodyOid to listeners waiting for sprites to get somewhere. */
protected var _arriveLists :Map = Maps.newMapOf(int);
/** Timestamp for last time we moved, used for auto-recentering. */
protected var _centerStamp :int;
/** The sprite associated with our client. */
protected var _selfSprite :CharacterIsoSprite;
/** The pixel radius around our sprite which we consider sufficiently
* proximate that we keep sprites around for occupants therein. */
protected var _proxrad :int = 100;
protected var _scObj :StageSceneObject;
/** Our sprite path velocity. */
// if we had more frames, maybe we could only update their
// location when their frame changed. Alas, we do not.
protected static const SPRITE_PATH_VELOCITY :Number = 0.1;
}
}
import com.threerings.whirled.spot.data.Location;
class ArrivalEntry
{
public var loc :Location;
public var listener :Function;
public function ArrivalEntry (loc :Location, listener :Function)
{
this.loc = loc;
this.listener = listener;
}
}
@@ -24,6 +24,7 @@ import flash.display.DisplayObject;
import com.threerings.miso.client.MisoScenePanel;
import com.threerings.miso.util.MisoContext;
import com.threerings.miso.util.MisoSceneMetrics;
import com.threerings.miso.util.MisoUtil;
import com.threerings.miso.client.SceneBlock;
import com.threerings.miso.data.MisoSceneModel;
import com.threerings.util.Iterator;
@@ -47,8 +48,8 @@ public class StageSceneBlock extends SceneBlock
_portalScene = portalScene;
}
override public function resolve (ctx :MisoContext, model :MisoSceneModel, panel :MisoScenePanel,
completeCallback :Function) :void
override public function resolve (ctx :MisoContext, model :MisoSceneModel,
panel :MisoScenePanel, completeCallback :Function) :void
{
_tryingPortals = true;
super.resolve(ctx, model, panel, completeCallback);
@@ -58,14 +59,14 @@ public class StageSceneBlock extends SceneBlock
var iter :Iterator = _spotScene.getPortals();
while (iter.hasNext()) {
var portal :Portal = Portal(iter.next());
var x :int = fullToTile(StageLocation(portal.loc).x);
var y :int = fullToTile(StageLocation(portal.loc).y);
var x :int = MisoUtil.fullToTile(StageLocation(portal.loc).x);
var y :int = MisoUtil.fullToTile(StageLocation(portal.loc).y);
if (x < bx || x > bx + BLOCK_SIZE || y < by || y > by + BLOCK_SIZE) {
continue;
}
var fineX :int = StageLocation(portal.loc).x - FULL_TILE_FACTOR * x;
var fineY :int = StageLocation(portal.loc).y - FULL_TILE_FACTOR * y;
var fineX :int = MisoUtil.fullToFine(StageLocation(portal.loc).x);
var fineY :int = MisoUtil.fullToFine(StageLocation(portal.loc).y);
// Grab the portal image, and center it.
var portalSprite :IsoSprite = new IsoSprite();
@@ -112,13 +113,6 @@ public class StageSceneBlock extends SceneBlock
}
}
protected function fullToTile (fullCoord :int) :int
{
return MathUtil.floorDiv(fullCoord, FULL_TILE_FACTOR);
}
protected static const FULL_TILE_FACTOR :int = 100;
protected var _spotScene :SpotScene;
protected var _tryingPortals :Boolean;
@@ -48,6 +48,13 @@ public class StageLocation extends SimpleStreamableObject
/** The user's orientation (defined by {@link DirectionCodes}). */
public var orient :int;
public function StageLocation (x :int = 0, y :int = 0, orient :int = 0)
{
this.x = x;
this.y = y;
this.orient = orient;
}
/**
* Computes a reasonable hashcode for location instances.
*/