Add a bunch of hooks to handle finding the object the mouse is over.

git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@985 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Mike Thomas
2010-08-14 05:10:02 +00:00
parent 7a72ac8fb2
commit 815b5d7be7
3 changed files with 147 additions and 9 deletions
@@ -37,6 +37,8 @@ import flash.events.MouseEvent;
import mx.core.ClassFactory;
import as3isolib.display.IsoSprite;
import as3isolib.display.primitive.IsoBox;
import as3isolib.core.IsoDisplayObject;
import as3isolib.geom.Pt;
import as3isolib.geom.IsoMath;
@@ -45,6 +47,7 @@ import as3isolib.display.IsoView;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.util.ClassUtil;
import com.threerings.util.DelayUtil;
import com.threerings.util.Log;
import com.threerings.util.Map;
@@ -98,9 +101,10 @@ public class MisoScenePanel extends Sprite
_isoView.size.x, _isoView.size.y);
_isoView.addEventListener(MouseEvent.CLICK, onClick);
_isoView.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoved);
_isoView.addEventListener(MouseEvent.ROLL_OUT, mouseExited);
_objScene = new IsoScene();
_objScene.layoutRenderer = new ClassFactory(PrioritizedSceneLayoutRenderer);
addObjectScenes();
addChild(_loading = createLoadingPanel());
@@ -158,8 +162,98 @@ public class MisoScenePanel extends Sprite
public function onClick (event :MouseEvent) :void
{
// TODO - handle _hobject
handleMousePressed(null, event);
handleMousePressed(_hobject, event);
}
public function mouseMoved (event :MouseEvent) :void
{
var viewPt :Point = _isoView.globalToLocal(new Point(event.stageX, event.stageY));
var x :int = event.stageX;
var y :int = event.stageY;
// give derived classes a chance to start with a hover object
var hobject :Object = computeOverHover(x, y);
// if they came up with nothing, compute the list of objects over
// which the mouse is hovering
if (hobject == null) {
var hits :Array =
_objScene.displayListChildren.filter(
function(val :Object, idx :int, arr :Array) :Boolean {
if (val is PriorityIsoDisplayObject) {
return PriorityIsoDisplayObject(val).hitTest(x, y);
} else {
return false;
}
});
hits.sort(function (v1 :PriorityIsoDisplayObject, v2 :PriorityIsoDisplayObject) :int {
// We want reverse order, highest prio first...
return v2.getPriority() - v1.getPriority();
});
if (hits.length > 0) {
hobject = hits[0];
}
}
// if the user isn't hovering over a sprite or object with an
// action, allow derived classes to provide some other hover
if (hobject == null) {
hobject = computeUnderHover(x, y);
}
changeHoverObject(hobject);
}
/**
* Gives derived classes a chance to compute a hover object that takes precedence over sprites
* and actionable objects. If this method returns non-null, no sprite or object hover
* calculations will be performed and the object returned will become the new hover object.
*/
protected function computeOverHover (mx :int, my :int) :Object
{
return null;
}
/**
* Gives derived classes a chance to compute a hover object that is used if the mouse is not
* hovering over a sprite or actionable object. If this method is called, it means that there
* are no sprites or objects under the mouse. Thus if it returns non-null, the object returned
* will become the new hover object.
*/
protected function computeUnderHover (mx :int, my :int) :Object
{
return null;
}
/**
* Change the hover object to the new object.
*/
protected function changeHoverObject (newHover :Object) :void
{
if (newHover == _hobject) {
return;
}
var oldHover :Object = _hobject;
_hobject = newHover;
hoverObjectChanged(oldHover, newHover);
}
/**
* A place for subclasses to react to the hover object changing.
* One of the supplied arguments may be null.
*/
protected function hoverObjectChanged (oldHover :Object, newHover :Object) :void
{
// Nothing by default.
}
public function mouseExited (event :MouseEvent) :void
{
// clear the highlight tracking data
changeHoverObject(null);
}
public function handleMousePressed (hobject :Object, event :MouseEvent) :Boolean
@@ -309,6 +403,19 @@ public class MisoScenePanel extends Sprite
}
}
protected function renderObjectScenes () :void
{
_objScene.render();
}
protected function addObjectScenes () :void
{
_objScene = new IsoScene();
_objScene.layoutRenderer = new ClassFactory(PrioritizedSceneLayoutRenderer);
_isoView.addScene(_objScene);
}
protected function resolutionComplete () :void
{
// First, we add in our new blocks...
@@ -319,11 +426,7 @@ public class MisoScenePanel extends Sprite
}
_readyBlocks = Sets.newSetOf(SceneBlock);
// Force to end of list so it's on top...
_isoView.removeScene(_objScene);
_isoView.addScene(_objScene);
_objScene.render();
renderObjectScenes();
// Then we let the scene finally move if it's trying to...
if (_pendingMoveBy != null) {
@@ -500,6 +603,9 @@ public class MisoScenePanel extends Sprite
/** If any block happens to resolve should we currently skip calling completion. */
protected var _skipComplete :Boolean
/** Info on the object that the mouse is currently hovering over. */
protected var _hobject :Object;
protected var _vbounds :Rectangle;
protected var _covered :Set = Sets.newSetOf(String);
@@ -28,5 +28,10 @@ public interface PriorityIsoDisplayObject
* Returns the render priority for the display object.
*/
function getPriority () :int;
/**
* Returns whether the location on the object should register a hit if clicked.
*/
function hitTest (stageX :int, stageY :int) :Boolean;
}
}
@@ -19,8 +19,11 @@
package com.threerings.miso.client {
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.geom.Point;
import as3isolib.core.IsoDisplayObject;
import as3isolib.display.IsoSprite;
import as3isolib.display.primitive.IsoBox;
@@ -92,6 +95,30 @@ public class TileIsoSprite extends IsoSprite
return _priority;
}
public function hitTest (stageX :int, stageY :int) :Boolean
{
if (sprites == null || sprites.length == 0) {
return false;
}
if (sprites[0] is Bitmap) {
if (!sprites[0].hitTestPoint(stageX, stageY, true)) {
// Doesn't even hit the bounds...
return false;
}
// Check the actual pixels...
var pt :Point = sprites[0].globalToLocal(new Point(stageX, stageY));
return Bitmap(sprites[0]).bitmapData.hitTest(new Point(0, 0), 0, pt);
} else {
return sprites[0].hitTestPoint(stageX, stageY, true);
}
}
public function toString () :String
{
return x + ", " + y + ": " + _tileId;
}
protected var _tileId :int;
protected var _priority :int;