Reputation: 59
I'm implementing a game and I'm stuck finding a way to calculate the x and y distance from a point and the nearest edge of movieclip. for example:
I need to calculate the distance between from each black dot, to the nearest edge of the movieclip (The movieclip is not always a circle, it's a random shape).
I'll be more than happy to find a solution. Thanks!
Upvotes: 1
Views: 83
Reputation: 3201
I suspect (though would welcome being proved wrong) that without geometrical data about the shape, pixel based operations might be the only way.
If there is geometrical data, then can possibly just do a linear check of the distances between the point and every other point in the shape (the first naive solution that comes to mind -better ones out there).
Even if the shape is user generated (like drawing) one could sample points during drawing to get point data, and so forth. I'm bringing it up as an aside as I think any of those would be faster/more efficient then my solution below (which assumes pixels only).
With that said, this solution works by using BitmapData's hitTest() to check if two shapes collide. It's hardly efficient and admittedly, I just woke up not too long ago and decided it was a good morning exercise. I didn't test for any error cases (aka, like if the point is inside the shape).
It works by starting at the point end and drawing larger and larger circles around it, at each step converting that in to a bitmap and using BitmapData's hitTest(). When it deemed the bitmaps are intersecting/touching, then the radius of the circle around the point would be the closest distance to the shape.
Efficiency however can be improved by adjusting the 'probe/step size' (in a similar way that binary search is more efficient then linear search). However, I'll leave that up to the reader (example in the code comments).
import flash.display.Shape;
import flash.geom.Point;
import flash.display.BitmapData;
import flash.display.Bitmap;
// assumptions: the movie clip is currenly the only thing on the stage
// first generate the first BitmapData by taking all the pixels on the stage (which should just contain the movieclip)
var stagePixels:BitmapData = new BitmapData(this.stage.stageWidth, this.stage.stageHeight, true, 0xffffff);
stagePixels.draw(this);
function getDistance(inputPoint:Point):int {
var currentSearchDistance:int = 1;
var result:Boolean = false;
var zeroPoint:Point = new Point(0, 0); // just a common reference point for the hitTest() call
var pointShape:Shape;
while(result == false){
// create the shape and draw the circle around the point
pointShape = new Shape();
pointShape.graphics.lineStyle(1);
pointShape.graphics.drawCircle(inputPoint.x, inputPoint.y, currentSearchDistance);
// convert to BitmapData
var pointPixels:BitmapData = new BitmapData(this.stage.stageWidth, this.stage.stageHeight, true, 0xffffff);
pointPixels.draw(pointShape);
// left this here to show the steps and what it is doing
// will slow down stage rendering though since there are potentially a lot of bitmaps being added to the stage
this.addChild(new Bitmap(pointPixels));
result = stagePixels.hitTest(zeroPoint, 0xff, pointPixels, zeroPoint);
// for now, increase the search distance by 1 only, so can return true when it hits the shape for the first time.
// This can be optimized to take larger steps (and smaller) steps as well with multiple probes.
// ex:
// take a big step (+50)... didn't hit shape
// so take another big step (+50)... hit shape so we know the point is between the first 50 to 100
// take maybe half a step back (-25)... hit shape, so we know the point is between the first 50 and 75
// take another half step back (-12)... didn't hit shape so we know the point is between 62 abd 75...etc
// thus can slowly close in on the result instead of taking every small step (would have tkaen 62+ checks to get to this point vs 5)
// (and can also decide to quite early for a "good enough" result)
currentSearchDistance++;
}
return currentSearchDistance;
}
var dot:Point = new Point(100, 100); // input point here
trace(getDistance(dot));
edit: Decided to add a picture to show what it's doing.
Upvotes: 2