浏览代码

Take rotation into account for mouseX/Y and event handling in Scene (fixes #51 and #144) (#281)

* Take rotation into account for mouseX/Y and event handling in Scene (close #51, close #144)
trethaller 8 年之前
父节点
当前提交
ef5e5ddddd
共有 2 个文件被更改,包括 98 次插入94 次删除
  1. 61 89
      h2d/Scene.hx
  2. 37 5
      samples/Interactive.hx

+ 61 - 89
h2d/Scene.hx

@@ -76,21 +76,33 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 			posChanged = true;
 		}
 	}
-
-	inline function screenXToLocal(mx:Float) {
-		return mx * width / (stage.width * scaleX) - x;
+	
+	inline function relMouseX() {
+		return stage.mouseX * width / stage.width;
 	}
-
-	inline function screenYToLocal(my:Float) {
-		return my * height / (stage.height * scaleY) - y;
+	
+	inline function relMouseY() {
+		return stage.mouseY * height / stage.height;
 	}
 
 	function get_mouseX() {
-		return screenXToLocal(stage.mouseX);
+		if (rotation == 0) {
+			return relMouseX() / scaleX - absX;
+		}
+		var mx = relMouseX() - absX;
+		var my = relMouseY() - absY;
+		var invDet = 1 / (matA * matD - matB * matC);
+		return (mx * matD - my * matC) * invDet;
 	}
 
 	function get_mouseY() {
-		return screenYToLocal(stage.mouseY);
+		if (rotation == 0) {
+			return relMouseY() / scaleY - absY;
+		}
+		var mx = relMouseX() - absX;
+		var my = relMouseY() - absY;
+		var invDet = 1 / (matA * matD - matB * matC);
+		return (-mx * matB + my * matA) * invDet;
 	}
 
 	public function dispatchListeners( event : hxd.Event ) {
@@ -110,34 +122,17 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		return true;
 	}
 
+	/**
+	 * Return first Interactive which overlaps with x,y coordinates (Scene space) or null
+	 */
 	public function getInteractive( x : Float, y : Float ) {
-		var rx = x * matA + y * matB + absX;
-		var ry = x * matC + y * matD + absY;
-		for( i in interactive ) {
-
-			var dx = rx - i.absX;
-			var dy = ry - i.absY;
-
-			var w1 = i.width * i.matA;
-			var h1 = i.width * i.matC;
-			var ky = h1 * dx + w1 * dy;
-
-			// up line
-			if( ky < 0 )
-				continue;
+		var rx = x * matA + y * matC + absX;
+		var ry = x * matB + y * matD + absY;
+		for ( i in interactive ) {
 
-			var w2 = i.height * i.matB;
-			var h2 = i.height * i.matD;
-			var kx = w2 * dy + h2 * dx;
-
-			// left line
-			if( kx < 0 )
-				continue;
-
-			var max = w1 * h2 - h1 * w2;
-
-			// bottom/right
-			if( ky >= max || kx >= max )
+			// check bounds
+			var local = toInteractiveLocal(i, rx, ry);
+			if (local.x < 0 || local.x > i.width || local.y < 0 || local.y > i.height)
 				continue;
 
 			// check visibility
@@ -156,74 +151,51 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		}
 		return null;
 	}
+	
+	inline function applyFixedSizeScale( e: hxd.Event ) {
+		if (fixedSize) {
+			e.relX *= width / stage.width;
+			e.relY *= height / stage.height;
+		}
+	}
 
 	function screenToLocal( e : hxd.Event ) {
-		var x = screenXToLocal(e.relX);
-		var y = screenYToLocal(e.relY);
-		var rx = x * matA + y * matB + absX;
-		var ry = x * matC + y * matD + absY;
-		e.relX = rx;
-		e.relY = ry;
+		applyFixedSizeScale(e);
+		var px = e.relX - absX;
+		var py = e.relY - absY;
+		var invDet = 1 / (matA * matD - matB * matC);
+		e.relX = (px * matD - py * matC) * invDet;
+		e.relY = ( -px * matB + py * matA) * invDet;
+	}
+	
+	static inline function toInteractiveLocal( i : Interactive, x : Float, y : Float ) {
+		var px = x - i.absX;
+		var py = y - i.absY;
+		var invDet = 1 / (i.matA * i.matD - i.matB * i.matC);
+		var lx = (px * i.matD - py * i.matC) * invDet;
+		var ly = ( -px * i.matB + py * i.matA) * invDet;
+		return new h2d.col.Point(lx, ly);
 	}
 
 	public function dispatchEvent( event : hxd.Event, to : hxd.SceneEvents.Interactive ) {
 		var i : Interactive = cast to;
-		screenToLocal(event);
-
-		var rx = event.relX;
-		var ry = event.relY;
-
-		var dx = rx - i.absX;
-		var dy = ry - i.absY;
-
-		var w1 = i.width * i.matA;
-		var h1 = i.width * i.matC;
-		var ky = h1 * dx + w1 * dy;
-
-		var w2 = i.height * i.matB;
-		var h2 = i.height * i.matD;
-		var kx = w2 * dy + h2 * dx;
-
-		var max = w1 * h2 - h1 * w2;
-
-		event.relX = (kx / max) * i.width;
-		event.relY = (ky / max) * i.height;
-
+		applyFixedSizeScale(event);
+		var local = toInteractiveLocal(i, event.relX, event.relY);
+		event.relX = local.x;
+		event.relY = local.y;
 		i.handleEvent(event);
 	}
 
 	public function handleEvent( event : hxd.Event, last : hxd.SceneEvents.Interactive ) : hxd.SceneEvents.Interactive {
-		screenToLocal(event);
-		var rx = event.relX;
-		var ry = event.relY;
+		applyFixedSizeScale(event);
 		var index = last == null ? 0 : interactive.indexOf(cast last) + 1;
 		for( idx in index...interactive.length ) {
 			var i = interactive[idx];
 			if( i == null ) break;
 
-			var dx = rx - i.absX;
-			var dy = ry - i.absY;
-
-			var w1 = i.width * i.matA;
-			var h1 = i.width * i.matC;
-			var ky = h1 * dx + w1 * dy;
-
-			// up line
-			if( ky < 0 )
-				continue;
-
-			var w2 = i.height * i.matB;
-			var h2 = i.height * i.matD;
-			var kx = w2 * dy + h2 * dx;
-
-			// left line
-			if( kx < 0 )
-				continue;
-
-			var max = w1 * h2 - h1 * w2;
-
-			// bottom/right
-			if( ky >= max || kx >= max )
+			// check bounds
+			var local = toInteractiveLocal(i, event.relX, event.relY);
+			if (local.x < 0 || local.x > i.width || local.y < 0 || local.y > i.height)
 				continue;
 
 			// check visibility
@@ -238,8 +210,8 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 			}
 			if( !visible ) continue;
 
-			event.relX = (kx / max) * i.width;
-			event.relY = (ky / max) * i.height;
+			event.relX = local.x;
+			event.relY = local.y;
 			i.handleEvent(event);
 
 			if( event.cancel ) {

+ 37 - 5
samples/Interactive.hx

@@ -1,3 +1,5 @@
+import h2d.Graphics;
+import hxd.Event;
 //PARAM=-D resourcesPath=../../skin_res
 
 class Interactive extends hxd.App {
@@ -78,16 +80,22 @@ class Interactive extends hxd.App {
 			initInteract(i, m);
 		}
 
+		s2d.setPos(10, 10);
+		s2d.scaleY = 1.2;
+		s2d.rotation = 0.3;
+		// s2d.setFixedSize(600, 600);
+
+		
 		b = new h2d.Interactive(150, 100, s2d);
-		b.backgroundColor = 0x80204060;
+		b.backgroundColor = 0xC0204060;
 		b.rotation = Math.PI / 3;
-		//b.scaleX = 1.5; // TODO
+		b.scaleX = 1.2;
 
 		var pix = null;
 		b.onOver = function(e) {
-			var t = h2d.Tile.fromColor(0xFF0000, 3, 3);
-			t.dx = -1;
-			t.dy = -1;
+			var t = h2d.Tile.fromColor(0xFF0000, 5, 5);
+			t.dx = -2;
+			t.dy = -2;
 			pix = new h2d.Bitmap(t, b);
 			pix.x = e.relX;
 			pix.y = e.relY;
@@ -101,6 +109,22 @@ class Interactive extends hxd.App {
 			pix.remove();
 			pix = null;
 		};
+		b.onClick = function(e) {
+			// Dispatch back a move event. Check that pix doesn't move on click
+			var stage = hxd.Stage.getInstance();
+			e.kind = EMove;
+			e.relX = stage.mouseX;
+			e.relY = stage.mouseY;
+			s2d.dispatchEvent(e, b);
+		}
+		s2d.addEventListener(function (e) {
+			if (e.kind == EPush) {
+				var g  = new Graphics(s2d);
+				g.beginFill(0xff0000);
+				g.drawRect(e.relX, e.relY, 4, 4);
+				g.endFill();
+			}
+		});
 
 		onResize();
 	}
@@ -112,6 +136,14 @@ class Interactive extends hxd.App {
 
 	override function update(dt:Float) {
 		obj.rotate(0, 0, 0.002 * dt);
+		
+		var i = s2d.getInteractive(s2d.mouseX, s2d.mouseY);
+		if (i != null) {
+			b.alpha = 0.5;
+		}
+		else {
+			b.alpha = 1.0;
+		}
 	}