Flash:最接近MovieClip的点

时间:2010-03-05 18:58:39

标签: flash actionscript-3

我需要约束艺术家给我的DisplayObject内的一个点。

我让它工作但仅适用于光标仍在bounds内的位置 有限的对象称为limited

function onSqMouseMove(event:MouseEvent) {
    if(bounds.hitTestPoint(event.stageX, event.stageY, true)) {
        limited.x = event.stageX;
        limited.y = event.stageY;
    } else {
        /* Find closest point in the Sprite */
    }
}

limited.addEventListener(MouseEvent.MOUSE_DOWN, function(event:MouseEvent) {
    stage.addEventListener(MouseEvent.MOUSE_MOVE, onSqMouseMove);
});

limited.addEventListener(MouseEvent.MOUSE_UP, function(event:MouseEvent) {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSqMouseMove);
});

如何实现该功能的另一半?我知道Sprite的startDrag接受参数,其中第二个是约束矩形,但在我的情况下,bounds是一个任意形状。

当对象被拖到边界外时,我想计算从光标到bounds'多边形的最近点。

请注意bounds可以有'漏洞'。

编辑:

要清楚,我不想找到一个点是否在MovieClip内,我想要从MovieClip外的一个点得到最近点(注意hitTestPoint 失败)到它的边界。

alt text http://liranuna.com/junk/closest-point.png

5 个答案:

答案 0 :(得分:1)

我看到这些家伙曾经回忆过一些关于“图像像素精确度”的问题,在那里他能够通过图像和热门测试真的很酷,但我不记得了:p。

如何开始这些:

鉴于您的DisplayObject是纯色,但是任意形状,Doug McCune的教程将非常容易。如果能让你更接近,请告诉我。

最佳, 兰斯

答案 1 :(得分:1)

嗯,这实际上取决于你所关注的准确性(以及背景图像的风格或复杂程度)。据我所知,除非你有一个特定的数学参考,否则没有直接测试距离的方法,因此除非你动态地绘制背景,否则你会遇到很多麻烦。

直接想到两种方法:

  1. 加载关卡时,将其计算为第n个精度数组(例如5x5像素),复制背景的一部分,然后测试它是否包含透明度(也许是getColorBoundsRect( 0xff000000, 0, false );?)。注意哪些包含数组中的边,然后您可以针对鼠标位置测试此网格,以告知最可能最近边的位置(任意一个方格,然后是两个,然后是三个等)。如果您需要更高的准确度,那么一旦您知道哪些最有可能容纳最近的像素,您就可以尝试某种计算。这不准确,并且在开始时需要一些计算,但它应该快速运行。

  2. 如果你有一个圆形的hitdetect精灵,你附加到光标位置,那么你可以扩展/收缩它并找到命中点。从宽度开始:0,高度:0,当它与背景接触时,当它在边缘上移动时,每个循环将其展开一个合理的量(例如5px),直到它有一个hittest。然后你可以跟踪这一点(如发布的viatropos页面中所示的Grant Skinners页面所示),如果碰撞区域太大,那么你的光标移动到更接近碰撞点,并且可以减少一定量,直到碰撞大小再次合理为止。这对处理器来说有点密集,但它只有几个测试帧,就像有30个球弹跳一样,它不应该太难了。

  3. 希望这会给你一些想法!

答案 2 :(得分:1)

你可以从鼠标位置开始,然后开始螺旋式地对每个像素进行命中测试。这将导致长循环,但根据您的使用情况,它应该可以合理地执行。这只能通过测试看到。

答案 3 :(得分:0)

根据您的具体情况,有多种算法可以很好地运行:

  1. 每20像素左右预处理图稿和标记点。这是为了减少您需要执行的距离测试的数量。如果拖动对象位于边界之外,则确定最近的参考点。确定其两个相邻参考点中的哪一个最接近拖动对象。根据距离的比例选择它们之间的一些点(如果它们几乎等距,则意味着最近的点几乎是中途)。这样的事情:Point.interpolate(closestRef, nextClosestRef, factor)。这种方法的缺点是它不会100%准确,因为参考点之间的区域将减少为直线(这可能影响参考点的位置)。换句话说,如果你的边界艺术有很多复杂的边缘,这种方法并不好,如果另一方面它有很多直线,那就太好了。
  2. 在抽象层面上,您的问题称为“nearest-neighbor problem". Google搜索可能会提供一些有效的解决方案。
  3. 类似于上面描述的短杆,将圆形hitdetect精灵附加到光标位置。但是,不是每次将半径增加5px,而是每次加倍,直到它与边界形状相交。然后使用最后两个半径长度作为下限和上限执行二分查找。这将为您提供到边界形状上最近点的距离。将其转化为实际点有点困难,但并非不可能。你只需要一个辅助的部分圆(不确定这是如何调用的)hitdetect精灵附加。在类似的二分搜索中调整弧长以确定角度。现在执行Point.polar(radius, angle).add(cursorPosition)以获取形状边界上的实际点。
  4. 我很确定有办法做3,但是使用矩形,它在Flash平台上有一个原生实现。我不完全确定,但值得一些思考。
  5. 仅供参考,首先深入挖掘API并查看是否已有一个可满足您需求的库。

答案 4 :(得分:0)

讨厌给出另一个理论答案并再次打开它,但我最近一直在思考这个问题。我认为光线跟踪方法可以工作。这个想法如下:

  • 将光线从光标投射到[movie-clip / sprite]的中心
  • 获取与[movieclip / sprite]
  • 发生碰撞的距离
  • 左转&从鼠标到中心点的右边法线
  • 沿着正常的
  • 移动中心点
  • 为新点重新制作光线
  • 获取与[movie-clip / sprite]
  • 发生碰撞的距离
  • 如果距离大于之前的距离,则在相反的法线上进行中心点
  • 重复,直到找到最小距离

我能用这种方法想到的唯一问题是它可能容易受到局部最小/最大值问题的影响。它的计算成本也可能很高。

快速谷歌给了我以下资源,如果你要尝试上述(如果我找不到替代方案,我想我可能会这样做)

如果你在形状的内部有一个点并且在表面上找到最近的点(在大多数情况下导致那个点的法线),那么可以实现什么的一个例子,这是一个在boids上{{3 }}

你找到了解决方案吗?