AS3如何对透明PNG图片和精灵进行碰撞检测?

4
我在这里,因为我正在为我的AS3应用程序的碰撞检测而苦恼。
我加载了一个表示房间的位图 - 它有边界(墙壁),其余部分是透明的(地板)。然后我创建了一个带圆形内部的精灵。
我希望我的精灵可以在这些边界内移动,并在墙上停止,我能够实现这背后的逻辑,我要求的是一种检测与墙碰撞的方法,我的整个房间是一个位图,所以我猜我只需要检查与这个位图的碰撞,但不幸的是它也计算透明部分。
我已经在谷歌上研究过这个问题,但我只找到了非常复杂的系统,无论如何都无法工作。我正在进行学习目的,所以我想知道如何自己实现它。
因此,我想问是否有人能够提供给我一小段代码,仅检查我的位图的非透明部分的碰撞?(或者我应该将此png加载为矢量图形?如何做?)。
我还旋转了我的“圆形”,所以我认为这也应该考虑在内。我假设我应该进行位图到位图的检查,而不是精灵到位图的检查?
我根本没有关于碰撞的工作代码,所以我不会提供任何代码。
如果需要提供更多信息,请告诉我。
预先感谢!
@EDIT
这是我为我的函数拥有的代码,它属于Room Class。
public function detectCollisionWith(obj:Sprite):Boolean
    {
        var _bitmapData:BitmapData = new BitmapData(obj.width, obj.height, true, 0);
        _bitmapData.draw(obj);
        var _bitmap:Bitmap = new Bitmap(_bitmapData);
        if (_bitmapData.hitTest(new Point(_bitmap.x, _bitmap.y), 255, this.bitmap, new Point(this.x, this.y), 255))
            return true;
        return false;
    }
3个回答

4
使用BitmapDatahitTest()方法,可以非常容易地检查两个位图之间的像素级别碰撞。
关于bitmapDatahitTest(),Adobe官方文档如下:
执行一个位图图像和点、矩形或其他位图图像之间的像素级别的碰撞检测。当一个点或矩形与一个不透明像素重叠,或两个重叠的不透明像素时,就定义为碰撞。在执行碰撞检测时,不考虑任何对象的拉伸、旋转或其他变换。
现在来看一个实现的例子。如果将您的精灵转换为位图:
var spriteBmd:BitmapData = new BitmapData( mySprite.width, mySprite.height, true, 0 );
spriteBmd.draw( mySprite ); //get the sprite asset
var spriteBitmap:Bitmap = new Bitmap( spriteBmd ); //create the bitmap to use

然后,您可以运行hitTest()来比较这两个位图,忽略透明部分:

if ( spriteBitmap.bitmapData.hitTest( new Point( mySprite.x, mySprite.y ), 
     255, levelBitmap, new Point( levelBitmap.x, levelBitmap.y ), 255 ) ) {
    trace("Collision detected");
}

这个检查仅检查位图的不透明部分,用于检测碰撞。如果你想增加透明度的检测量,你可以在if语句中调整值255


不需要发送所有点,只需发送位图的x和y即可。点只是告诉它从哪里开始和结束,如果传递显示对象,则算法将浏览它们各自的边界。或者,您可以只传递它们从左上到右下边界的点。 - Bennett Keller
好的,我会尝试并希望能够取得一些积极的结果后再回来。那性能如何?对于如此巨大的位图(我将拥有大约5000 x 5000个“房间”PNG),它不会对性能产生显著影响吗? - pzaj
就性能而言,任何碰撞测试都是相当昂贵的。这个特别使用位图是最昂贵的之一,因为它考虑了透明度。因此,大小肯定会发挥作用,但由于您只是检查2个位图,所以可能不会太糟糕。但请注意,BitmapData的最大大小为“... BitmapData对象的最大宽度或高度为8,191像素,总像素数不能超过16,777,215像素。(因此,如果一个BitmapData对象宽度为8,191像素,则其高度只能达到2,048像素)”。在FP9及更早版本中,该值更低。 - Bennett Keller
好的,我想我需要将我的图像分割到特定的房间中,这样更好。然后,我可以使用hitTestObject检查我的精灵是否在房间的边界内,之后进行位图测试。只要fps不会明显下降,我就很满意。 - pzaj
我可以用其他方式联系您吗?我又遇到了另一个问题。我记得您上次也回答了我的问题,所以我怀疑在这里发布不会有什么区别。我简要地说明一下,这是因为我的精灵上的“圆圈”向精灵的x和y轴偏移(超出了精灵),以便于旋转 - 我尝试使用矩阵进行旋转,但它没有围绕其中心旋转,而是随机旋转并移动到位置之外。不幸的是,这切断了我的测试位图。 - pzaj
显示剩余5条评论

0

简单的房间?是一个简单的矩形吗?那么,我建议通过检查预定义矩形中的点来计算碰撞。创建矩形,将其大小插入到圆的半径上,并检查圆的中心是否在矩形内。

//Some room
var roomBounds:Rectangle = new Rectangle(0, 0, 700, 500);
const circleRadius:int = 10;
var collisionBounds: Rectangle = new Rectangle(circleRadius, circleRadius, roomBounds.width - 2*circleRadius, roomBounds.height - 2*circleRadius);

//Check if center of circle inside of collisionBounds
//For example you have point with name circlePosition
//collisionBounds.containsPoint(circlePosition)
if(!collisionBounds.contains(circleX, circleY)){
    trace("Houston! We have collision here!");
}

不幸的是,这是一个更复杂的房间,嗯,对于完整的信息,不止一个房间,但我现在尝试处理我的第一个房间,这样我就可以停在墙上了。 - pzaj

0

很多年前做过这个...但如果我没记错的话,你可以通过创建一个带有墙体矢量形状的MC(将其放置在墙体下方),并检查与其的碰撞而不是位图来解决问题。


很好,那可能可以,但是我如何让我的图像向量放置在mc上? - pzaj
不是真的,它太复杂了,无法画出来,需要很长时间。除了墙壁之外,我还有其他物体要放入最终产品中,它们都必须从png文件中映射出来。我已经用AirBag库成功实现了它,但由于无法捕获碰撞的漏洞,我不得不放弃使用它 - 似乎没有明显的原因,有时我能穿过墙壁,有时我会停在上面(然后当我试图离开时发生了一件有趣的事情)。所以它可以满足我的需求(读取具有透明度的png),但有时不能让我弹跳或停止。 - pzaj
即使您从Illustrator传递表单,也太长了,将位图转换为曲线,删除透明部分并将其导入Flash? - Nadia
哦,我原本想以编程的方式绘制它!因为我是用 Corel 制作的矢量图,但我不知道应该使用什么文件类型? .svg 吗?它能加载到 Flash 中吗? - pzaj
您可以导入多种格式的向量图:.ai .swf .dxf .fxg 如果Corel不能导出这些格式,您肯定会找到一些转换器。 - Nadia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接