【问题标题】:How can I drag an object with collision detection?如何使用碰撞检测拖动对象?
【发布时间】:2011-11-11 07:31:14
【问题描述】:

我想创建一个函数,我可以在其中拖动一个 MovieClip,它会撞到舞台上的其他 MovieClip 而不会重叠它们。 (即对象不能被拖过或穿过其他影片剪辑)。

function dragHolder01(event:Event):void{
    if (mouseDownHolder01 == true) {
        for(var m:int = 0;m<blockHolder.numChildren; m++){
            var hitBlock:DisplayObject = blockHolder.getChildAt(m);
            if(movaHolder01.hitTestObject(hitBlock)){
                movaHolder01.x = movaHolder01x;
                movaHolder01.y = movaHolder01y;
                break;
            }
        }
        movaHolder01.startDrag();
        movaHolder01x = movaHolder01.x;
        movaHolder01y = movaHolder01.y;
    }
}

我想我可能有一个概念性的解决方案,但我需要你的帮助。 我想也许我可以限制“startDrag”以允许根据帧进度进行拖动,即玩家将无法为每一帧拖动对象超过一个像素(因此不能将对象拖入另一个像素超过一个像素)。

关于如何做到这一点的任何想法?

【问题讨论】:

  • 到目前为止你尝试了什么,你有什么代码可以展示吗?你的文件是怎么设置的,你对舞台上的其他对象有可用的参考吗?

标签: actionscript-3


【解决方案1】:

把这个问题分成几部分。在我看来,这些部分是:

  • 对象被左键单击,对其调用 startDrag() 并准备好 enterFrame() 监听器。
  • 在每一帧检查拖动对象和所需场景对象之间的碰撞。
  • 假设你有碰撞。接下来是什么 - 你如何处理它?您可以将其捕捉到之前的位置 - 这样物体就会卡在最轻微的接触上。或者您可以将碰撞的对象移动某个向量。它可能是从障碍物中心到碰撞对象中心的向量(如果它们都很小。)
  • 释放左键时,调用 stopDrag()。

如果你更喜欢Box2D,还有其他步骤:

  • 将您的影片剪辑转换为物理形状。不要问我怎么做 - 这不会是自动的。
  • 而不是 startDrag() 对拖动的对象施加一些力。鼠标光标从物体上移的越多,力度就越大。 Box2D 将自动解决碰撞和碰撞对象。

更新:如何存储以前的位置

var positions:Dictionary = new Dictionary();
var clip:MovieClip = ...; //load your clip somehow

//store position
position[clip] = new Point(clip.x, clip.y);

//read position
var pos:Point = position[clip];

//update position - reuses Point objects to make things somewhat faster
var pos:Point = position[clip];
pos.x = clip.x;
pos.y = clip.y;
//that's all, reference to Point is already in the Dictionary.

还有其他方法。 MovieClip 不是 final 类,因此可以继承和扩展之前的位置。它也是动态的,这意味着您可以在其上插入数据:

clip.prevX = clip.x; //prevX will be created if not exist
clip.prevY = clip.y;
//move clip

【讨论】:

  • 完全正确...我似乎可以得到第 3 部分。我有 1(在 enterFrame 中拖动)和 2(命中测试),但我似乎无法有效地得到拖动的对象回到之前的位置。如何对碰撞对象外部的位置进行采样?
  • 要捕捉对象(最简单的版本),存储与剪辑关联的先前位置(在带有 MovieClip 键的字典中,或制作将保存 MovieClip 和额外数据的包装类。)或基于计算所述向量在碰撞物体的中心。你的对象有多大?
  • 对象大小不同。我的问题正是存储以前的位置......我不熟悉 Dictionary 或包装类。
  • 谢谢你,alxx。我已经能够通过将变量赋值(prev 位置)放在 startDrag 之后、enterFrame 内以及 startDrag 之前的 if 来存储 prev 位置。我仍然面临的唯一问题是,如果我将对象拖得太快,它会“进入”另一个对象。拖动停止,但随后被拖动的对象被定位在碰撞对象的“上”。有办法解决吗?
  • 所以拖慢就回,拖快不回?
【解决方案2】:

如果您想要物理行为(即物体在被击中时弹跳),请不要自己实现它并使用物理引擎,例如 Box2D。他们有几个 MouseDragged 对象的示例(请参阅 Test 类的 MouseDrag http://box2dflash.svn.sourceforge.net/viewvc/box2dflash/Examples/TestBed/Test.as?revision=158&content-type=text%2Fplain)。

如果您只想要不重叠的对象(取决于您想要的碰撞检测程度),您可以使用 MovieClip.hitTest() 作为碰撞检测并验证被拖动的对象(在鼠标位置)是否没有击中任何东西,如果击中了,则将其恢复到以前的位置。但是请注意,鼠标可以在一个时间范围内以任何速度移动,因此如果鼠标移动得太快,被拖动的对象可能会穿过另一个对象(您可以执行固定大小的连续插值来避免这种情况)。

物理行为和碰撞检测是严重的数学和计算机问题,不应掉以轻心。如果您想要体面的碰撞和物理行为,那么熟悉物理引擎(已经被使用、测试和优化过很多次)比编写自己的代码来执行该行为所花费的时间要少得多。

如果您仍然不想使用物理引擎,请向我展示您的代码,我可能会更符合您的喜好(也许会花费一些计算时间)。

【讨论】:

    【解决方案3】:

    您可能想看看 Box2D 等物理引擎:http://box2dflash.sourceforge.net/

    【讨论】:

    • 谢谢。恐怕要在我现有的代码上实现需要很长时间。我只想使用一个执行此操作的函数。
    猜你喜欢
    • 1970-01-01
    • 2012-10-24
    • 2015-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 2015-12-29
    • 1970-01-01
    相关资源
    最近更新 更多