AS3 在不規則區域內拖動
阿新 • • 發佈:2018-06-10
矩形 算法 etc 規則 sre ref complex 影響 number
原理:
1、確保拖動對象在鼠標點上,如果不確定會出現瞬間移動的感覺
2、確保觸碰到非通行區域,跳回到沒觸碰的點
源碼:
import flash.events.MouseEvent; import flash.events.Event; car.buttonMode = true; car.addEventListener(MouseEvent.MOUSE_DOWN,downH); var diffX:Number, diffY:Number; var canMove:Boolean = false; function downH(e){ diffX = car.x - mouseX; diffY = car.y - mouseY; canMove = true; stage.addEventListener(MouseEvent.MOUSE_MOVE,moveH); stage.addEventListener(MouseEvent.MOUSE_UP,upH); addEventListener(Event.ENTER_FRAME, onEnter); } function upH(E){ stage.removeEventListener(MouseEvent.MOUSE_UP,upH); stage.removeEventListener(MouseEvent.MOUSE_MOVE,moveH); removeEventListener(Event.ENTER_FRAME, onEnter); } //確保在非通行區域可以拖動 function moveH(E){ var xx = car.x; var yy = car.y; if (canMove){ car.x = mouseX + diffX; car.y = mouseY + diffY; } if (HitTest.complexHitTestObject(car,bg)){ car.x = xx; car.y = yy; } } //確保車在鼠標點上 function onEnter(e:Event):void { if (car.hitTestPoint(mouseX,mouseY)) { if (!canMove) { canMove = true; diffX = car.x - mouseX; diffY = car.y - mouseY; } } else { canMove = false; } }
觸碰類網上提供的:
package { //像素級精確碰撞算法優化 //代碼:Aone import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.DisplayObject; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; public class HitTest { public static var tileSize:int = 20; public static function complexHitTestObject(target1:DisplayObject, target2:DisplayObject):Boolean { //橫向縮小到tileSize尺寸需要的倍數,也就是期望檢測的時候縮小到的尺寸。 var scaleX:Number = (target1.width < target2.width ? target1.width : target2.width) / tileSize //縱向縮小到tileSize尺寸需要的倍 var scaleY:Number = (target1.height < target2.height ? target1.height : target2.height) / tileSize // //如果倍數小於1則按原始倍率也就是原始尺寸 scaleX = scaleX < 1 ? 1 : scaleX scaleY = scaleY < 1 ? 1 : scaleY //draw用point var pt:Point=new Point() //做2次draw時使用的顏色 var ct:ColorTransform=new ColorTransform() ct.color=0xFF00000F //原始尺寸下的重疊矩形 var oldHitRectangle:Rectangle=intersectionRectangle(target1, target2) //用於存放縮放的重疊矩形 var hitRectangle:Rectangle= new Rectangle() return complexIntersectionRectangle(target1, target2 , scaleX , scaleY , pt , ct , oldHitRectangle,hitRectangle,tileSize,tileSize).width != 0; } public static function intersectionRectangle(target1:DisplayObject, target2:DisplayObject):Rectangle { // If either of the items don‘t have a reference to stage, then they are not in a display list // or if a simple hitTestObject is false, they cannot be intersecting. if (!target1.root || !target2.root || !target1.hitTestObject(target2)) return new Rectangle(); // Get the bounds of each DisplayObject. var bounds1:Rectangle = target1.getBounds(target1.root); var bounds2:Rectangle= target2.getBounds(target2.root); return bounds1.intersection(bounds2); // // Determine test area boundaries. // var intersection:Rectangle = new Rectangle(); // intersection.x = Math.max(bounds1.x, bounds2.x); // intersection.y = Math.max(bounds1.y, bounds2.y); // intersection.width = Math.min((bounds1.x + bounds1.width) - intersection.x, (bounds2.x + bounds2.width) - intersection.x); // intersection.height = Math.min((bounds1.y + bounds1.height) - intersection.y, (bounds2.y + bounds2.height) - intersection.y); // return intersection; } private static function complexIntersectionRectangle(target1:DisplayObject, target2:DisplayObject, scaleX:Number , scaleY:Number , pt:Point , ct:ColorTransform ,oldhitRectangle:Rectangle,hitRectangle:Rectangle,nowW:int,nowH:int):Rectangle { if (!target1.hitTestObject(target2)) return new Rectangle(); //根據縱橫的縮小倍數來計算縮小的重疊矩形尺寸 hitRectangle.x = oldhitRectangle.x hitRectangle.y = oldhitRectangle.y hitRectangle.width = oldhitRectangle.width / scaleX hitRectangle.height = oldhitRectangle.height / scaleY //建立一個用來draw的臨時BitmapData對象,尺寸為期望寬nowW,期望高nowH var bitmapData:BitmapData=new BitmapData(nowW,nowH, true, 0); //繪制對象1其縮放比例和位移量由getDrawMatrix()函數計算,並且把不透明處繪制為ct的顏色 bitmapData.draw(target1, getDrawMatrix(target1, hitRectangle , scaleX , scaleY ),ct); //當縱橫縮小比例不為1的時候把任何有色像素重新替換成ct的顏色0xFF00000F,原因為縮小的對象在進行純色繪制的時候會有半透明像素產生,如果不加以重新替換會影響後面對象2的濾鏡效果。 if(scaleX!=1&&scaleY!=1) bitmapData.threshold(bitmapData,bitmapData.rect,pt,">",0,0xFF00000F) //繪制對象2其縮放比例和位移量由getDrawMatrix()函數計算,並且把不透明處繪制為ct的顏色,並且模式為疊加。如此一來兩個對象重疊的部分顏色值必定大於0xFF00000F。 bitmapData.draw(target2, getDrawMatrix(target2, hitRectangle , scaleX , scaleY ),ct, BlendMode.ADD); //把所有顏色值大於0xFF00000F的部分(也就是重疊部分)重新替換為不透明紅色方便後面getColorBoundsRect()方法計算尺寸。這裏替換的原因是getColorBoundsRect()不支持範圍取色而只支持單色計算。 //對象1縮放後可以重新替換掉透明色,但是對象2則無法使用同一方法,但是對象2由於也是經過縮放繪制也會有半透明像素,那麽重疊部分雖然全部大於0xFF00000F,但未必是統一的。 var hits:int=bitmapData.threshold(bitmapData,bitmapData.rect,pt,">",0xFF00000F,0xFFFF0000) //判斷紅色區域尺寸 var intersection:Rectangle=bitmapData.getColorBoundsRect(0xFFFFFFFF, 0xFFFF0000); bitmapData.dispose(); //如果紅色區域寬度不為0,即bitmapData中含有紅色像素。此時說明對象1和對象2在此次判定中有重疊有碰撞 //如果縱橫縮放比例有任意一個不是原始尺寸 //並且紅色像素的數量比較少,對象1和對象2的碰撞面積比較小的話 if (intersection.width != 0 && (scaleX > 1 || scaleY > 1) && hits <= (scaleX+scaleY) * 1.5) { //由於bitmapData的寬高坐標都是以整數表示,那麽經過縮放後取整的區域勢必回又可能在取整的時候把真正可能產生碰撞的區域忽略。 //所以要進行下一次檢測時候適當的把檢測區域擴大xadd和yadd就是這個擴大的系數 var xadd:int = 0.5; var yadd:int = 0.5; //下次檢測時候bitmapData的期望大小 //如果此次判定發現碰撞區域和bitmapData尺寸相同,那麽在計算下次需要判斷區域時候會和此次的區域相同,那麽判斷結果可能會和此次結果相同。這樣則會引起堆棧上溢的情況,為了避免該情況發生,將縮小判斷的尺寸擴大一倍進行再次檢測。 var nextW:int = (intersection.width != nowW) ? tileSize : nowW * 2; var nextH:int = (intersection.height != nowH) ? tileSize : nowH * 2; //根據檢測出來的縮的碰撞區域來計算未縮小的碰撞區域大小以方便下一次計算的時候縮小檢測範圍。 oldhitRectangle.x += (intersection.x - xadd) * scaleX; oldhitRectangle.y += (intersection.y - yadd) * scaleY; oldhitRectangle.width = (intersection.width + xadd*2) * scaleX; oldhitRectangle.height = (intersection.height + yadd*2) * scaleY; //根據檢測期望縮小到的尺寸重新計算縮小倍率 scaleX = (oldhitRectangle.width / nextW) scaleY = (oldhitRectangle.height / nextH) //如果倍率小於2則直接按原始尺寸 scaleX = scaleX < 2 ? 1 : scaleX scaleY = scaleY < 2 ? 1 : scaleY //進行下一次判定 intersection = complexIntersectionRectangle(target1,target2, scaleX , scaleY ,pt,ct,oldhitRectangle,hitRectangle,nextW,nextH) } return intersection; } protected static function getDrawMatrix(target:DisplayObject, hitRectangle:Rectangle , scaleX:Number , scaleY:Number ):Matrix { var localToGlobal:Point; var matrix:Matrix; var rootConcatenatedMatrix:Matrix=target.root.transform.concatenatedMatrix; localToGlobal=target.localToGlobal(new Point()); matrix=target.transform.concatenatedMatrix; matrix.tx=(localToGlobal.x - hitRectangle.x) / scaleX; matrix.ty=(localToGlobal.y - hitRectangle.y) / scaleY; matrix.a=matrix.a / rootConcatenatedMatrix.a / scaleX ; matrix.d=matrix.d / rootConcatenatedMatrix.d / scaleY; return matrix; } } }
AS3 在不規則區域內拖動