【问题标题】:How to rotate BitmapData when using draw method. Width height bounds clipping / cropping problem使用 draw 方法时如何旋转 BitmapData。宽度高度边界裁剪/裁剪问题
【发布时间】:2011-01-11 00:38:05
【问题描述】:

我编写了一个使用 BitmapData.hitTest 的碰撞检测类。基本上,每次更新时,都会调用 .draw 方法,然后将两个 BitmapData 相互碰撞测试以查看是否存在冲突。

它工作得很好,但是如果我开始旋转用于 BitmapData 的源影片剪辑,则转换不会在 draw 方法中注册。所以我所做的就是在draw方法中通过一个Matrix。这样可行。但这是实际问题。如果我将 BitmapData 输出到舞台上的 Bitmap,我看到 Bitmap ,实际上是在旋转,但现在它超出了 BitmapData 的边界(宽度和高度)。哪个正在裁剪/裁剪源 MovieClip 的图像。

我的第一个猜测是旋转 BitmapData,但旋转似乎是不可能的。没有任何属性可以帮助您实现这一目标。还有其他方法吗?

更新:基本上,当电影剪辑的位图克隆在正坐标空间之外旋转时,它不会被绘制。它在 BitmapData 设置的宽度和高度范围之外旋转。我可以将边界乘以 2,然后将位图居中设置边界内,但是原点永远不会固定,并且对象总是在移动。效果很好,但无法将对象与任何特定点对齐。

这是我的独立测试代码。它要求您在舞台上有一个名为“iTest”的 MovieClip。我使用了一个相当垂直的箭头形状(高于它的宽度),因此我可以直观地跟踪旋转并帮助突出剪裁问题:

var rotateTimer:Timer = new Timer(10);

function rotateObject_init():void
{
 rotateTimer.addEventListener(TimerEvent.TIMER, rotateObject);
 rotateTimer.start();
}

function rotateObject_stop():void
{
 rotateTimer.removeEventListener(TimerEvent.TIMER, rotateObject);
 rotateTimer.stop();
}

function rotateObject(_event:TimerEvent):void
{
 // Deletes the previous bitmap
 if (this.getChildByName("iTestClone") != null)
 {
  removeChild(this.getChildByName("iTestClone"));

  testClone = null;
  testData = null;
 }

 iTest.rotation += 1;

 // Capture source BitmapData
 var testData:BitmapData = new BitmapData(iTest.width, iTest.height, false, 0xFFFFFF); 

 // Capture source transformations
 var testMatrix:Matrix = new Matrix();
 testMatrix.scale(iTest.scaleX, iTest.scaleY);
 testMatrix.rotate( iTest.rotation * (Math.PI / 180) );
 testMatrix.translate(0, 0);

 // Draw source with matrix
 testData.draw(iTest, testMatrix);

 // Output Bitmap
 var testClone:Bitmap = new Bitmap(testData);
 testClone.name = "iTestClone";
 testClone.transform = testMatrix.tra
 addChild(testClone);

 // Always makes sure source is visible
 this.swapChildren(iTest, testClone);
}

rotateObject_init();

【问题讨论】:

  • 也许您可以使用 CDK (code.google.com/p/collisiondetectionkit) 并完全避免这个问题?
  • 我宁愿使用自己的代码,这样我可以从经验中学习。另外,我真的不喜欢使用其他人的代码,人们有如此不同的思维方式,我发现最好坚持自己的工作流程。不过我很欣赏这个链接。
  • 甜蜜,分享。我也可能有一个修复,我今晚可以尝试。基本上,您需要进行预先计算,将目标对象旋转 360 度,然后在此过程中捕获它的最大值和高度。使用它作为您的 BitmapData 大小,然后使用与您所做的有点相似的技术,但也许更简单,因为我们现在有了宽度和高度,并为 Bitmap 计算出固定的左上角位置,当然,适合在 BitmapData 的范围内。灵感来自 8BitRocket 上的教程。

标签: flash actionscript-3 actionscript


【解决方案1】:

只需使用旋转属性:

THENAMEOFMovieClip.rotation=number;

数字是您要旋转的度数。

【讨论】:

    【解决方案2】:

    好问题!

    我试图制作一个旋转了 10 度的正方形的 BitmapData 克隆。为了得到位图数据的旋转,我使用了克隆对象的矩阵。正如您所提到的,问题是由于旋转枢轴而获得的偏移量。

    这是我的样子:

    为了解决这个问题,我认为如果我得到 BitmapData 的 with 和最右边的点之间的差异,那会给我 x 的偏移量,并且对 y 执行类似的操作,会让我正确地方。

    几乎,我看起来好多了(只有一两个像素似乎受损):

    好吧,我觉得我明白了:)

    那个偏移是针对x的,但他误导的是,它是由边界矩形的height定义的,而不是width .试试这个:

    var box:Sprite = new Sprite();
    box.graphics.lineStyle(0.1);
    box.graphics.drawRect(0,0,150,100);
    box.rotation = 10;
    //get the size of the object rotated
    var bounds:Rectangle = box.getBounds(this);
    //make a bitmap data
    var extra:int = 2;//cheating the trimmed pixels :)
    var bitmapData:BitmapData = new BitmapData(bounds.width+extra,bounds.height+extra,false, 0x00009900);
    //get the bottom left point
    var bl:Point = getBottomLeft(box,bitmapData);
    //get the matrix
    var m:Matrix = box.transform.matrix;
    //offset if
    m.tx += Math.abs(bl.x);
    //draw, using the offset, rotated matrix
    bitmapData.draw(box,m);
    
    var bitmap:Bitmap = new Bitmap(bitmapData);
    bitmap.x = bitmap.y = 100;
    addChild(bitmap);
    
    function getBottomLeft(displayObject:DisplayObject,data:BitmapData):Point{
        var radius:int = displayObject.getBounds(displayObject).height;
        var angle:Number = displayObject.rotation * Math.PI / 180;
        var angle90:Number = angle + Math.PI * .5;
        return new Point(Math.cos(angle90) * radius, Math.sin(angle90) * radius);
    }
    

    您不需要在 BitmapData 构造函数中使用绿色背景,这是用于调试的。 另外,您只需要左下角的 x 位置,因此您需要返回一个数字而不是一个点。

    所以稍微短一点的版本是:

    var box:Sprite = new Sprite();
    box.graphics.lineStyle(0.1);
    box.graphics.drawRect(0,0,150,100);
    box.rotation = 10;
    
    var bounds:Rectangle = box.getBounds(this);
    var extra:int = 2;//cheating the trimmed pixels :)
    var bitmapData:BitmapData = new BitmapData(bounds.width+extra,bounds.height+extra,false, 0x00009900);
    
    var m:Matrix = box.transform.matrix;
    m.tx += Math.abs(getLeftmost(box,bitmapData));
    bitmapData.draw(box,m);
    
    var bitmap:Bitmap = new Bitmap(bitmapData);
    bitmap.x = bitmap.y = 100;
    addChild(bitmap);
    
    function getLeftmost(displayObject:DisplayObject,data:BitmapData):Number{
        var radius:int = displayObject.getBounds(displayObject).height;
        var angle90:Number = displayObject.rotation * Math.PI / 180 + Math.PI * .5;
        return Math.cos(angle90) * radius;
    }
    

    结果:

    HTH,乔治

    提醒自己:小心你的愿望^_^

    【讨论】:

    • 是的,我以前见过这种方法。可惜它只适用于盒子。虽然,我开始认为,也许在我想要进行碰撞检测的对象上创建一个框是唯一的前进方式。如果你愿意的话,一个通用的命中框。我看不到任何其他合乎逻辑的解决方案。
    • 我知道你的意思...我希望我知道算法,或者更多的几何知识。
    【解决方案3】:

    您说 bitmapData 的边界导致了剪切,但您将边界设置为对象的宽度和高度。这表明返回的宽度和高度实际上是不正确的(即没有考虑旋转)。

    也许尝试使用 getBounds() 来找到 iTest 的实际宽度和高度:

    // Capture source BitmapData
    var bounds:Rectangle = iTest.getBounds(iTest);
    var testData:BitmapData = new BitmapData(bounds.width, bounds.height, false, 0xFFFFFF); 
    

    我不完全确定这是否会起作用——我还没有测试过这些:-)

    【讨论】:

    • getBounds 的一个很好的实现,但宽度和高度不是问题。事实上,一旦克隆的 iTest 位图旋转到 BitmapData 的边界之外,它就会被剪裁。基本上,一旦它移过原点 0, 0。一旦它旋转过 0 到负片,你什么也看不到。希望这能很好地解释它。
    • 啊,在那种情况下没关系。我在考虑一个简单的情况,即对象围绕其中心旋转......显然不是这样。
    猜你喜欢
    • 2018-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    相关资源
    最近更新 更多