Flash / ActionScript:将显示对象“绘制”到另一个上

时间:2009-02-16 21:27:04

标签: flash actionscript-3 actionscript graphics bitmap

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

我的想法(如here所示)是使用beginBitmapFill()和drawRect()绘制位图副本(使用BitmapData.draw()制作)一个MovieClip到另一个MovieClip的。graphics属性,但事实证明这比我想象的要困难,主要是出于以下原因:

  1. 不保留透明度:源MovieClip是透明的,目标图形变为白色。我尝试过使用BlendMode,但没有用。看起来白色像素实际上被复制到BitmapData中。我必须遗漏一些东西,但我不知道是什么。问题似乎是BitmapData构造函数的文档是错误的:透明度不会默认为 true ,但 false 。因此,如果您创建了new BitmapData(x, y, true)透明度,则保留,否则不会。

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

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

  4. (然后还有其他东西,比如必须使用lineStyle(0,0,0),所以drawRect()不会绘制边框等。)

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

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


    编辑Theo提供了一个完美的之外的工作解决方案,因为它不会应用旋转和缩放应用于正在绘制到Graphics表面上的DisplayObject。这是Theo's solution

    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. Matrix中使用的draw()应该复制源DisplayObject的缩放和轮换?
    2. Matrix中使用的beginBitmapFill()也应该复制此缩放和旋转吗?或者这可能会产生“双倍”缩放和旋转?
    3. 应修改drawRect()坐标以匹配缩放和旋转DisplayObject的大小?这意味着getBounds()不准确?

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

      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();
      }
      

      有些相关但不那么热门的问题:How to put an image (say, PNG) on a graphics in Flex 3?

3 个答案:

答案 0 :(得分:2)

我认为你有几种方法可以解决这个问题:

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

  • 使用位图和.draw()方法
    优点:也很简单,你可以更轻松地复制事物 缺点:基本上与先前的方法有相同的问题,删除任何东西都需要完整的重绘。它也是不可扩展的,因为它是位图。

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

使用最后一种方法(我建议如果你要做的事情比你用的东西还要小),你可以通过使用添加到“绘图”中的位图解决问题,这些方法支持透明度(如你已经发现了)并且比使用bitmapFill更简单(这有点难以实现)。

我的博客上有using a bitmap to clone and draw other DisplayObjects的示例。它不是你想要的,但代码可能有一些用处,至少是draw方法的矩阵部分。

答案 1 :(得分: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));
}

答案 2 :(得分:1)

bzlm - 您总是可以将起始X位置设为常量,并将drawRect与Matrix平移结合起来。

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);