【问题标题】:Flash: Closest point to MovieClipFlash:离影片剪辑最近的点
【发布时间】:2011-01-24 06:07:21
【问题描述】:

我需要在艺术家给我的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 失败 !) 到它的边界。


(来源:liranuna.com)

【问题讨论】:

  • 你的边界对象是不是 getPixel() 会给你一种颜色来帮助你确定它是在边界内还是在边界外?即与外面不同的纯色?
  • hitTestPoint 就是这样做的。

标签: flash actionscript-3


【解决方案1】:

我前段时间看到这个家伙的博客关于“图像的像素精度”,他能够在图像和命中测试方面做一些非常酷的事情,但我不记得了:p。

先从这些开始:

鉴于您的 DisplayObject 是纯色,但是是任意形状,Doug McCune 的教程将非常容易上手。让我知道这是否能让你更接近。

最好, 兰斯

【讨论】:

  • 前两个没用,因为我已经在使用hitTestPoint,效果很好。我需要进一步调查第三个链接。
  • 如果您需要与嵌套显示对象和/或旋转等配合使用的完美像素碰撞检测,请查看碰撞检测套件 (CDK):code.google.com/p/collisiondetectionkit
  • 碰撞检测不是我的问题。我想从影片剪辑外部获得最接近其边界的点。看看我编辑的帖子。
【解决方案2】:

好吧,就我而言,这实际上取决于您所追求的准确性(以及背景图像的样式或复杂性究竟是什么)。据我所知,除非您有特定的数学参考,否则没有直接的测试距离的方法,因此除非您动态绘制背景,否则您会遇到很多麻烦。

两种方法浮现在脑海中:

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

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

希望这能给你一些想法!

【讨论】:

    【解决方案3】:

    您可以从鼠标位置开始,然后开始螺旋式地对每个像素进行命中测试。这将导致一个很长的循环,但根据您的用例,它应该可以正常执行。这只有通过测试才能看到。

    【讨论】:

      【解决方案4】:

      根据您的情况,有多种算法方法可能效果很好:

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

      仅供参考,最好先浏览API,看看是否已经有一个库可以满足您的需求。

      【讨论】:

      • “首先挖掘 API 总是一个好主意”——如果它那么简单,你认为我会提供 200rep 的赏金而没有答案吗?!当然,我阅读了 API 参考!
      【解决方案5】:

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

      • 将光线从光标投射到 [movie-clip/sprite] 的中心
      • 获取它与 [movieclip/sprite] 碰撞的距离
      • 获取从鼠标到中心点的线的左右法线
      • 沿一条法线移动中心点
      • 为新点重铸射线
      • 获取与 [movie-clip/sprite] 碰撞的距离
      • 如果距离大于前一个距离,则沿相反法线前进中心点
      • 重复直到找到最小距离

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

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

      如果您在形状内部找到点并在表面上找到最近的点(在大多数情况下导致该点的法线),可以实现什么,这是 boids 上的一个示例http://www.red3d.com/cwr/steer/Containment.html

      你找到解决办法了吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-06
        • 2011-12-29
        • 2012-06-07
        • 2011-11-02
        • 2017-11-12
        • 1970-01-01
        • 2013-09-29
        相关资源
        最近更新 更多