-1

如何在 ActionScript 中正确地将一个矢量对象绘制到另一个矢量对象的特定位置,并考虑定位、透明度等?

我的想法(如这里所建议的那样)是使用beginBitmapFill() 和() 将一个 MovieClipdrawRect的位图副本(使用() 制作)绘制到 . 另一个 MovieClip 的属性,但事实证明这比我想象的要困难,主要是因为以下原因:BitmapData.drawgraphics

  1. 不保留透明度:源影片剪辑是透明的,目标图形变为白色。我试过使用 a BlendMode,但它没有帮助。似乎白色像素实际上被复制到 BitmapData 中。我一定错过了什么,但我不知道是什么。似乎问题在于BitmapData构造函数的文档是错误的:透明度不默认为true,而是false。所以如果你创建的new BitmapData(x, y, true)透明度是保留的,否则不会。

  2. 定位。如果源影片剪辑居中(中心位于 (0, 0),则在将其复制到 BitmapData 时必须应用矩阵来移动它,否则位图将仅包含源影片剪辑的右下角。弄清楚如何移动它很棘手,我认为它涉及以某种方式获取边界。(如果源对象在其画布中完全居中,您可以简单地将其偏移其宽度和高度的一半,当然。)

  3. beginBitmapFill平铺。似乎如果您不在drawRect(0, 0) 处开始 (),则位图填充也不会从位图中的 (0, 0) 开始。这意味着您必须根据要开始绘制的位置再次移动源位图。

(然后还有其他东西,比如必须 lineStyle(0,0,0) 所以 drawRect() 不画边框等)

所有这些棘手的麻烦让我相信我正在以错误的方式解决这个问题。有没有更简单的方法来做到这一点?有没有图书馆可以帮助我?有没有人成功做到这一点?也许我的绘图画布不应该是 Sprite 而是 Bitmap?但是后来我不知道如何使用lineTo() 等来绘制它。

情况如下:我有一个 Sprite,我使用它的 .graphics、lineTo() 等绘制它。现在我想在绘制时使用一个 MovieClip 作为画笔(或者只是将另一个 MovieClip 的副本放在绘图表面上),使另一个 MovieClip 成为第一个的图形的一部分。我不能addChild() 因为那样矢量图形不会与绘制的图形交互。


编辑Theo提供了一个完美的工作解决方案,除了它不应用应用于被绘制到图形表面上的 DisplayObject的旋转和缩放。这是Theo 的解决方案

private function drawOntoGraphics(source : IBitmapDrawable, target : Graphics, position : Point = null) : void
{
    position = position == null ? new Point() : position;
    var bounds : Rectangle = DisplayObject(source).getBounds(DisplayObject(source));
    var bitmapData : BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x00000000);
    bitmapData.draw(source, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y), null, null, null, true);
    target.beginBitmapFill(bitmapData, new Matrix(1, 0, 0, 1, bounds.x + position.x, bounds.y + position.y));
    target.drawRect(bounds.x + position.x, bounds.y + position.y, bounds.width, bounds.height);
}

为了支持旋转和缩放,我假设必须修改以下内容:

  1. 使用Matrixdraw()应该从源复制缩放和旋转DisplayObject
  2. Matrix使用的 in也beginBitmapFill()应该复制这个缩放和旋转?或者这可能会产生“双重”缩放和旋转?
  3. drawRect()应该修改坐标以匹配缩放和旋转的大小DisplayObject?哪种方式getBounds()不准确?

编辑:这是一个支持缩放和旋转的工作实现,由所有反馈制成:

static function DrawOntoGraphics(source:MovieClip, target:Graphics, 
        position:Point = null):void {
    var sourceClass:Class = getDefinitionByName(getQualifiedClassName(source)) 
        as Class;   
    var sourceCopy:MovieClip = new sourceClass();
    sourceCopy.rotation = source.rotation;
    sourceCopy.scaleX = source.scaleX;
    sourceCopy.scaleY = source.scaleY;
    sourceCopy.graphics.clear();
    var placeholder:MovieClip = new MovieClip();
    placeholder.addChild(sourceCopy);
    if (!position) 
        position = new Point();
    var bounds:Rectangle = placeholder.getBounds(placeholder);
    var bitmapData:BitmapData = new BitmapData(bounds.width, bounds.height, 
        true, 0x00000000);
    var drawMatrix:Matrix = new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y);
    bitmapData.draw(placeholder, drawMatrix);           
    placeholder.removeChild(sourceCopy);
    var fillMatrix:Matrix = new Matrix(1, 0, 0, 1, bounds.x + position.x, 
        bounds.y + position.y);
    target.beginBitmapFill(bitmapData, fillMatrix);
    target.lineStyle(0, 0x00000000, 0);
    target.drawRect(bounds.x + position.x, bounds.y + position.y, 
        bounds.width, bounds.height);
    target.endFill();
}

有点相关但不那么热门的问题:如何在 Flex 3 中的图形上放置图像(例如 PNG)?

4

3 回答 3

2

在我看来,你有几种方法可以解决这个问题:

  • 使用“画布”形状的图形属性
    优点:漂亮而简单
    缺点:非常有限,特别是如果您需要删除东西,因为您必须重新绘制整个画布。

  • 使用位图和 .draw() 方法
    优点:也很简单,你可以更轻松地进行复制。
    缺点:基本上和之前的方法有同样的问题,删除任何东西都需要完全重绘。由于它是位图,因此它也无法扩展。

  • 使用 Sprite 并将基元添加为子项
    优点:非常灵活。
    缺点:这允许您单独移动、缩放和删除对象。但是,它会比前两个选项稍微复杂一些。

使用最后一种方法(如果你要做的不仅仅是一些非常小的事情,我会建议你)你的问题可以通过使用添加到“绘图”中的位图来解决,这些支持透明度(就像你已经发现)并且比使用 bitmapFill 更简单(这有点棘手)。

我的博客上有一个使用位图克隆和绘制其他 DisplayObject的示例。这不完全是您想要的,但代码可能有一些用处,至少是 draw 方法的矩阵部分。

于 2009-02-17T09:30:12.207 回答
1

使用显示对象 getBounds 函数可以是在绘图时转换坐标的可靠解决方案:

private function drawOntoGraphics(source : IBitmapDrawable, target : Graphics, position : Point = null) : void
{
        position = position == null ? new Point() : position;

        var bounds : Rectangle = DisplayObject(source).getBounds(DisplayObject(source));
        var bitmapData : BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x00000000);

        bitmapData.draw(source, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y), null, null, null, true);
        target.beginBitmapFill(bitmapData, new Matrix(1, 0, 0, 1, bounds.x + position.x, bounds.y + position.y));
        target.drawRect(bounds.x + position.x, bounds.y + position.y, bounds.width, bounds.height);
}

除了您的评论...下面使用BitmapData而不是 Graphics 对象作为画布的相同方法:

private function drawOntoBitmapData(source : IBitmapDrawable, target : BitmapData, position : Point = null) : void
{
    position = position == null ? new Point() : position;
    var bounds : Rectangle = DisplayObject(source).getBounds(DisplayObject(source));
    var bitmapData : BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x00000000);
    bitmapData.draw(source, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y), null, null, null, true);
    target.draw(bitmapData, new Matrix(1, 0, 0, 1, bounds.x + position.x, bounds.y + position.y));
}
于 2009-02-16T22:46:23.940 回答
1

bzlm - 您总是可以使起始 X 位置为常数,并将 drawRect 与矩阵转换结合使用。

var xPos:Number = 750;
var matrix:Matrix = new Matrix();
matrix.translate(xPos,0);
mySprite.graphics.beginBitmapFill(myBitmap,matrix);
mySprite.graphics.drawRect(xPos,yPos,imgWidth,imgHeight);
于 2009-05-16T16:18:22.963 回答