Actionscript 3 如何确定给定对象是否为遮罩

Actionscript 3 如何确定给定对象是否为遮罩,actionscript-3,mask,Actionscript 3,Mask,显然,在Adobe的智慧中,被屏蔽的对象和屏蔽对象都包含一个“mask”属性。这导致循环参考,阻止确定哪一个是实际掩码,哪一个是掩码 例如 var clip:MovieClip = new MovieClip(); clip.name = "clip"; addChild(clip); var boundary:Shape = new Shape(); boundary.name = "boundary"; clip.addChild(boundary); clip.mask = bound

显然,在Adobe的智慧中,被屏蔽的对象和屏蔽对象都包含一个“mask”属性。这导致循环参考,阻止确定哪一个是实际掩码,哪一个是掩码

例如

var clip:MovieClip = new MovieClip();
clip.name = "clip";
addChild(clip);

var boundary:Shape = new Shape();
boundary.name = "boundary";
clip.addChild(boundary);

clip.mask = boundary;

trace(clip.mask.name); // outputs "boundary"
trace(clip.mask.mask.name); // outputs "clip"
MainTimeline ¬
    0: clip ¬
        0: boundary
我反复研究了
clip
boundary
的属性,似乎没有任何独特之处将它们区分开来。我的第一个想法是强制删除
boundary
中多余的“mask”引用,但是,这也会将
clip
中的
mask
属性设置为null,从而删除掩码

var a:Array = [clip, boundary];

for each (var item in a) {
    if (item.mask == item.parent) {
        trace(item.name + " is a mask");
    }
}

// outputs "boundary is a mask"
我的第二个想法是检查面具的父母关系。如果父对象与对象的掩码相同,则所讨论的对象本身就是掩码

var a:Array = [clip, boundary];

for each (var item in a) {
    if (item.mask == item.parent) {
        trace(item.name + " is a mask");
    }
}

// outputs "boundary is a mask"
似乎可以工作,在检查掩码后,很明显,在缓存时,掩码需要是掩码的子项,但是。。。将遮罩与遮罩深度相同也是有效的(当遮罩不需要与遮罩内容一起移动时,我会不时这样做)

例如

var clip:MovieClip = new MovieClip();
clip.name = "clip";
addChild(clip);

var boundary:Shape = new Shape();
boundary.name = "boundary";
clip.addChild(boundary);

clip.mask = boundary;

trace(clip.mask.name); // outputs "boundary"
trace(clip.mask.mask.name); // outputs "clip"
MainTimeline ¬
    0: clip ¬
        0: boundary
。。。也可以布置为

MainTimeline ¬
    0: clip ¬
    1: boundary

所以,有一个难题。关于如何解决这个问题有什么想法吗?

好问题,以前从未遇到过。我不知道循环引用

如果你的面具是唯一的面具,我建议你把它纳入你的命名惯例。例如,将其称为clipMask而不是boundary

如注释中所述,在掩码位于同一显示列表中的情况下,可以使用getChildIndex()比较它们在父级显示列表中的位置

通常在这种情况下,我会将遮罩分层到另一个显示对象上。这显然不是强制的,我也不相信这对面具的视觉效果有任何影响。但是对于一个大的组来说,它比命名约定更容易维护

显然仍然不理想。

到目前为止,我发现的“最佳”黑客方法是在对象上运行
hitTestPoint
(在确保它们在目标下有东西击中之后)。对于全像素命中测试,遮罩似乎永远不会返回
true
。这似乎适用于我测试过的最基本的情况:

public function isMask(displayObject:DisplayObject):Boolean {

    // Make sure the display object is a Class which has Graphics available,
    // and is part of a mask / maskee pair.
    if ((displayObject is Shape || displayObject is Sprite) && displayObject.mask) {

        // Add a circle at the target object's origin.
        displayObject['graphics'].beginFill(0);
        displayObject['graphics'].drawCircle(0, 0, 10);

        var origin:Point = displayObject.localToGlobal(new Point());
        var maskLocal:Point = displayObject.mask.globalToLocal(origin);

        // Add a circle at the same relative position on the "mask".
        displayObject.mask['graphics'].beginFill(0);
        displayObject.mask['graphics'].drawCircle(maskLocal.x, maskLocal.y, 10);

        // No matter which is the actual mask, one circle will reveal the other,
        // so hit testing the origin point should return true.
        // However, it seems to return false if the object is actually a mask.
        var hit:Boolean = displayObject.hitTestPoint(origin.x, origin.y, true);

        displayObject['graphics'].clear();
        displayObject.mask['graphics'].clear();

        // Return true if the hit test failed.
        return !hit;
    } else {
        return false;
    }
}
显然,如果对象已经有了一些图形,那么您需要缓存
图形
,并且可以做一些比使用Sprite更优雅的事情,这样它就可以处理形状,但这只是一个开始


编辑:通过访问
['graphics']
可以接受
形状,但显然效率不高。除了添加接口之外,我不确定最好的方法是什么。

这是一种解决方法,但不是理想的解决方案。这是针对一个有许多程序员的大型项目的代码库。每个人给面具取的名字都不一样,所以它只能在某些时候起作用/这里很可能没有理想的解决方案。在这种情况下,更接近的一步可能是使用
parent.getChildIndex(clip)
parent.getChildIndex(boundary)
,并假设较高的索引是掩码。如果每个人都能在显示列表中始终将掩码放在较高的位置,那就行了。在研究掩码时发现了这一点:-如果您的任何掩码都是在IDE中创建的,那么这对您来说非常重要。我查看了您共享的链接。我看到的两个解决方案都与确定可见性作为相交因子有关,但是,它们都不能提供哪个对象生成遮罩的实际答案。至少通过将交叉点栅格化为图像并测试白色的普遍性,您可以通过将一个对象移动到另一个对象的另一侧并再次运行测试来结束测试。这将告诉您哪个对象与这些可见性维度相匹配,但如果经常使用,可能会证明计算成本很高……您的解决方案很有趣,而且看起来确实有效,但是,我承认我不完全理解它为什么有效。奇怪的是,如果
hitTestPoint
在像素标志设置为true的遮罩对象上运行,它将失败,但只有在
beginfl
draw
操作之前才会失败。如果只是在指定的点进行测试,那么任何对象类型都是可行的。我可以理解hitTestPoint可以在可见对象上工作(不要与属性
obj.visible
混淆,因为掩码和对象都保留真实值),但为什么它在非预绘制对象上失败让我困惑。如果我理解你的问题,
graphics
调用只是为了确保有像素要点击,这样非掩码总是返回
!hit==false
。如果对象恰好在0,0处不透明,则可以删除所有的
图形调用
,这将正确返回。这是一个可怕的黑客虽然,所以我只建议作为最后的手段!我添加了一些评论,因为我认为我没有很好地解释自己。希望他们能帮点忙!这不能处理所有可能的掩码类(例如,
SimpleButton
),这让人很恼火,但我不知道如何确保在没有
Graphics
addChild
的情况下,这些掩码类是不透明的。这是有道理的。谢谢你的澄清。我得等到今晚回家再试试这个,但是;如何使用临时形状代理原始DisplayObject,对其应用掩码,运行hitPointTest,还原掩码,并删除代理?从理论上讲,这将为所有对象类型提供精确的遮罩检查。嗯,可能有一些方法可以处理一些事情,但我现在还不能完全理解它。您需要使遮罩对中的两个对象在同一位置不透明,以确保某些对象可见。