Flash / ActionScript: нарисуйте экранный объект "на" другом - PullRequest
0 голосов
/ 17 февраля 2009

Как правильно нарисовать один векторный объект на определенной позиции другого в ActionScript с учетом позиционирования, прозрачности и т. Д.

Моя идея (как предложено, например, здесь ) заключалась в том, чтобы использовать beginBitmapFill () и drawRect () для рисования растровой копии (сделанной с использованием BitmapData.draw ()) одного мувиклипа на . graphics свойство другого MovieClip, но это оказалось сложнее, чем я думал, в основном по следующим причинам:

  1. Прозрачность не сохраняется : если исходный MovieClip является прозрачным, целевая графика становится белой. Я пытался использовать BlendMode, но это не помогает. Кажется, белые пиксели на самом деле копируются в BitmapData. Я, должно быть, что-то упускаю, но я не знаю, что. Кажется, проблема заключалась в том, что документация для конструктора BitmapData неверна: прозрачность по умолчанию не true , а ложь . Так что если вы создаете new BitmapData(x, y, true) прозрачность сохраняется, в противном случае нет.

  2. Позиционирование . Если исходный MovieClip центрирован (с центром в (0, 0), необходимо применить матрицу, чтобы переместить его при копировании в BitmapData, или растровое изображение будет содержать только правый нижний угол исходного MovieClip. переместить его сложно, и я предполагаю, что это связано с получением границ каким-либо образом (если исходный объект идеально центрирован в пределах его холста, вы, конечно, можете просто сместить его на половину его ширины и высоты.)

  3. beginBitmapFill плитка . Кажется, что если вы не начнете drawRect () с (0, 0), заливка растрового изображения не начинается с (0, 0) внутри растрового изображения. Это означает, что вам нужно снова сдвинуть исходное растровое изображение в зависимости от того, где вы хотите начать рисование.

(Тогда есть другие вещи, такие как необходимость lineStyle (0,0,0), поэтому drawRect () не рисует границу и т. Д.)

Все эти хитрые проблемы заставляют меня поверить, что я поступаю неправильно. Есть ли более простой способ сделать это? Где-нибудь есть библиотека, которая может мне помочь? Кто-нибудь успешно сделал это? Возможно, мой холст для рисования должен быть не спрайтом, а растровым изображением? Но тогда я не знаю, как рисовать, используя lineTo () и т. Д.

Вот ситуация : у меня есть Sprite, в который я рисую, используя его .graphics, используя lineTo () и т. Д. Теперь я хочу использовать MovieClip в качестве кисти при рисовании (или просто разместить копию другого мувиклипа на поверхности рисования), делая другой мувиклип частью графики первого. Я не могу addChild (), потому что тогда векторная графика не будет взаимодействовать с нарисованной графикой.


РЕДАКТИРОВАТЬ : Тео предоставил рабочее решение, которое отлично работает , за исключением , поскольку он не применяет вращение и масштабирование применяется к объекту DisplayObject, рисуемому на графической поверхности. Это решение Тео :

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() не будет точным?

РЕДАКТИРОВАТЬ : Вот рабочая реализация, которая поддерживает масштабирование и поворот, сделанные из всех отзывов:

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

Несколько связанный, но не очень горячий вопрос: Как разместить изображение (скажем, PNG) на графике во Flex 3?

Ответы [ 3 ]

2 голосов
/ 17 февраля 2009

Как я вижу, у вас есть несколько способов подойти к этому:

  • Использовать графическое свойство формы "canvas"
    Плюсы: красиво и просто
    Минусы: очень ограничены, особенно если вам нужно удалить вещи, так как вам придется перерисовать весь холст.

  • Использование растрового изображения и метода .draw ()
    Плюсы: также красиво и просто, и вы можете делать дублирование вещей проще.
    Минусы: в основном те же проблемы, что и в предыдущем подходе, удаление чего-либо потребовало бы полной перерисовки. Также это не будет масштабируемым, так как это растровое изображение.

  • Используйте Sprite и добавляйте примитивы как дети
    Плюсы: очень гибкий.
    Минусы: это позволяет перемещать, масштабировать и удалять объекты по отдельности. Однако это будет немного сложнее, чем в двух предыдущих вариантах.

Используя последний подход (который я бы порекомендовал, если вы собираетесь делать с ним что-то большее, чем что-то очень маленькое), ваша проблема может быть решена с помощью растровых изображений, которые вы добавляете к своему «чертежу», они поддерживают прозрачность (например вы узнали) и немного более просты, чем использование bitmapFill (что сложно сделать правильно).

У меня есть пример с использованием растрового изображения для клонирования и рисования других объектов DisplayObject в моем блоге. Это не совсем то, что вам нужно, но код может быть полезен, по крайней мере, часть матрицы для метода draw.

1 голос
/ 16 мая 2009

bzlm - вы всегда можете сделать начальную позицию X постоянной и комбинировать drawRect с Matrix translate.

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);
1 голос
/ 17 февраля 2009

Использование экранных объектов Функция 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 в качестве canvas:

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