iv made a colouring game and i want to make it so you can save the drawing (a Movieclip) and send it to another frame or scene, iv been looking into how it may be possible and it looks like it can be done with bitmapdata but i don't know how to even go about it.
You'll need to name your save button, and add a click listener to it.
// create the BitmapData that you'll be drawing to, give it the same dimensions
var savedImage:BitmapData = new BitmapData(holder.width, holder.height, false, 0xFFFFFF);
// add a click listener to your save button
saveBtn.addEventListener(MouseEvent.CLICK, onSave);
function onSave(event:MouseEvent):void
{
// need to apply a transformation matrix because holder's origin is centered
var matrix:Matrix = new Matrix();
matrix.translate(holder.width * .5, holder.height * .5);
// clear out any existing image on savedImage
savedImage.fillRect(savedImage.rect, 0xFFFFFF);
// draw the holder onto the savedImage bitmapdata, using the transform matrix
savedImage.draw(holder, matrix, null, null, null, true);
}
From there on out, you can pass your savedImage BitmapData to a Bitmap instance:
var savedBitmap:Bitmap = new Bitmap(savedImage);
As long as savedBitmap is in the correct scope, you can add it to the display list on another frame:
addChild(savedBitmap);
Related
This seems like it should be so easy that I'm embarrassed to ask, but I just can't get it.
I have a large round MovieClip (being used as a button). This MovieClip contains a PNG with a transparent background inserted into the MovieClip.
Due to its size there are large empty registration areas on the 4 corners (the bounding box).
How can I have the mouse register as being over only the circle pixels and not the blank space (of Alpha channel pixels) in the square boundary box?
Simple sample code:
public function simpleSample () : void
{
mc1.buttonMode = true;
mc1.addEventListener(MouseEvent.CLICK, doStuff);
}
public function doStuff (event:MouseEvent) : void
{
mc2.gotoAndStop(2);
}
Here are 3 different ways to accomplish this.
EDIT Since you've later explained that your button is an image, this first option won't work for you
If the shape flag on hitTestPoint works with your button (eg it's a shape), you can use hitTestPoint inside your mouse click handler to figure out if the click is actually over the object:
public function doStuff(event:MouseEvent){
//only continue if hit test point is true,
//the x and y values are global (not relative to the mc your testing as one might suppose)
//the third parameter should be true, so it takes into account the shape of object and not just it's bounds
if(mc1.hitTestPoint(stage.mouseX, stage.mouseY, true)){
mc2.gotoAndStop(2);
}
}
If the above doesn't work because you have bimtap data in your button, then an easy way to accomplish this is to just add a shape mask to the button.
So, either inside your button using FlasPro, mask everything with a circle shape, or, do it via code by doing the following when you first show the button:
var s:Shape = new Shape();
s.graphics.beginFill(0);
s.graphics.drawCircle(mc1.x + (mc1.width * .5), mc1.y + (mc1.height * .5), mc1.width / 2);
addChild(s);
mc1.mask = s;
If using an image as the button, or you want to set a threshold of how transparent to consider a click, then you can check the transparency of the pixel under the mouse:
function doStuff(event:MouseEvent){
//only continue if pixel under the mosue is NOT transparent
//first, you need a bitmap to work with
//if you know for sure the position of your bitmap, you can do something like this:
var bm:Bitmap = mc1.getChildAt(0) as Bitmap;
//annoyingly though, FlashPro makes timeline bitmaps shapes,
//so the above won't work UNLESS you take your bitmap in the FlashPro Library
//and export it for actionscript, giving it a class name, then it will be an actual bitmap on the timeline.
//As an alternative, you could (very CPU expensively) draw the whole button as a bitmap
var bmd:BitmapData = new BitmapData(mc1.width,mc1.height,true,0x00000000);
bmd.draw(mc1);
var bm:Bitmap = new Bitmap(bmd);
//we get the 32bit pixel under the mouse point
var pixel:uint = bm.bitmapData.getPixel32(bm.x + event.localX,bm.y + event.localY);
//then we grab just the Alpha part of that pixel ( >> 24 & 0xFF ).
//if the value is 0, it's totally transparent, if it's 255, it's totally opaque.
//for this example, let's say anything greater than 0 is considered good to be a click
if((pixel >> 24 & 0xFF) > 0){
mc2.gotoAndStop(2);
}
}
I'm drawing a textfield onto a bitmap which I use as texture for a 3D object.
I'm listening for Event.change, and so whenever the user adds a character I redraw the texture. But to really give the 3D object a 'interactive textfield feeling', I want to draw text selections and draw the caret (the blinking text cursor), but by default these a not drawn when using bitmapData.draw(textField), nor can I find a Event to listen for 'textSelected'.
Any ideas?
//is there any event that catches text selection / blinking of text-cursor?
textField.addEventListener(Event.CHANGE, redrawTexture);
//...
//is there any way to draw text selection / text-cursor in the bitmap?
bmpData.draw(textField);
textField.addEventListener(FocusEvent.FOCUS_IN, redrawTexture, false, 0, true);
textField.addEventListener(FocusEvent.FOCUS_OUT, redrawTexture, false, 0, true);
var bmp:BitmapData = new BitmapData(width, height);
bmp.draw(textField);
var snapshot:Bitmap = new Bitmap(bmp);
I have this function:
public static function cloneDpObj(target:DisplayObject):Bitmap
{
var duplicate:Bitmap;
var tBitData:BitmapData = new BitmapData(target.width, target.height);
tBitData.draw(target);
duplicate = new Bitmap(tBitData);
return duplicate;
}
to clone target displayObject (MovieClip or Sprite) and return Bitmap Object.
It can get bitmap from the target object, but it seem don't get all the area of the image.
By give the width and height of target object, but the target object in design was applied by Glow Effect, so my question can we get the all view of bitmapdata from a displayobject?
BitmapData.draw() takes a snapshot of a given object removing all transformations and filters applied on the stage. Resulting image shows object as it is present in your movie library.
There are two basic options when drawing display objects with transformations and/or filters.
You can apply all transformations during drawing with matrix parameter for BitmapData.draw(). After drawing you can apply filters to resulting bitmap with BitmapData.applyFilter().
Just draw parent container, not the object itself.
I usually choose the latter. That's pretty straightforward. There are some disadvantages: if you choose the second method, your target has to have a display list parent and you may draw unwanted content that resides in parent container. (However, these drawbacks are easily eliminated.)
// bounds and size of parent in its own coordinate space
var rect:Rectangle = target.parent.getBounds(target.parent);
var bmp:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
// offset for drawing
var matrix:Matrix = new Matrix();
matrix.translate(-rect.x, -rect.y);
// Note: we are drawing parent object, not target itself:
// this allows to save all transformations and filters of target
bmp.draw(target.parent, matrix);
You need compute the area/rectangle of your DisplayObject including the area taken by the filter applied. Luckily you can do that with with built-in functionality by using the generateFilterRect() method of the BitmapData class.
Also, for other reasons, if you need the transformation of your DisplayObject applied to the BitmapData snapshot, you can pass the source DisplayObject's .transform.concatenatedMatrix as the second parameter of BitmapData's draw() method.
Thank you very much to all of you that take valuable time answer my question. I improved that function, but I is better, but I notice that the width of result of capture is 1pixel offset, so I decided to add 1 pixel to width of the bitmapdata, I know that is not a good practice. because I have to do that now, I don't know the issue yet. Here is how our function now:
public static function cloneDpObj(target:DisplayObject, optWidth:Number = -1, optHeight:Number = -1):Bitmap
{
var duplicate:Bitmap;
if (!target.parent) {
var tempSprite:Sprite = new Sprite;
tempSprite.addChild(target);
}
var rect:Rectangle = target.parent.getBounds(target.parent);
var bmp:BitmapData = new BitmapData(rect.width + 1, rect.height, true, 0);
// offset for drawing
var matrix:Matrix = new Matrix();
matrix.translate( -rect.x, -rect.y);
// Note: we are drawing parent object, not target itself:
// this allows to save all transformations and filters of target
bmp.draw(target.parent, matrix);
duplicate = new Bitmap(bmp);
return duplicate;
}
I would actually go with Nox's first option as the easier approach, and modifying your function to do it should only take one extra line of code:
public static function cloneDpObj(target:DisplayObject):Bitmap
{
var duplicate:Bitmap;
var tBitData:BitmapData = new BitmapData(target.width, target.height);
tBitData.draw(target);
duplicate = new Bitmap(tBitData);
//add the filters
duplicate.filters = target.filters;
return duplicate;
}
In my Actionscript program, I draw a polygon using the methods:
this.graphics.moveTo()
and
this.graphics.lineTo()
In the update function of the polygon model I change it a bit, and then draw it all over again. Eventually, every call to the update() function draws the updated polygon and I can see it changes.
On some point of the program, I want to be able to use this polygon as a movieclip, so I
can attach a mask to it - so as the polygon drawn over and over again, I could see a nice
background in the form of that polygon, fills it inside.
Problem is - I do not know how to take this array of points I have, which is my polygon representation, and turn it into a movieclip ( if possible at all... )
If you have any other recommendations how to implement the above, It would be great.
You can just create a new MovieClip and use it's graphics for drawing. So instead of using this.graphics.moveTo / lineTo, try this:
var mc:MovieClip = new MovieClip();
mc.graphics.moveTo(...);
mc.graphics.lineTo(...);
this.addChild(mc);
A convenient way of drawing, if you want to type less, is to do something like this:
var mc:MovieClip = new MovieClip();
with(mc.graphics) {
clear();
lineStyle(...);
moveTo(...);
lineTo(...);
...
ect.
}
this.addChild(mc);
I suggest you take a look at Point class. For example,
var p1:Point = new Point(100,150);
Then you can have an array of points
var arrPoints:Array = new Array(p1,p2,p3);
With a for loop, you can decide if i==0 you use moveTo and for the rest use lineTo. You can have a special condition at the end to close your polygon, i==arrPoints.length-1.
So, basically create a movieclip object, use its graphic property to fill it with the points you defined in your array. As long as your points are in a movieclip, you can mask it. Finally, that "this" notation you used is probably referring to the main movieclip which is the stage.
var mc:MovieClip = new MovieClip();
mc.graphics.moveTo(p1.x,p1.y);
will draw your graphics into your mc.
i have a
dsgnArea----> a movieclip
dsgnArea is masked by dsgnAreaMask, which inturn is a movieclip
dsgnArea.mask=dsgnAreaMask;
the width,height and position of dsgnAreaMask and dsgnArea are same.
i dynamically added multiple movieclips and labels to dsgnArea;
like..
dsgnArea.addChild(movieClip1);
dsgnArea.addChild(movieClip2);
dsgnArea.addChild(label1);
dsgnArea.addChild(label2); and so on...
these movieclips (movieClip1,movieClip2,......) and labels(label1,label2,....) positions can be altered in runtime..
but as i masked the dsgnArea with dsgnAreaMask, only a portion of the added movieClips and labels are visible...
So, my problem is to grab that visible portion in dsgnArea into a bitmap,like a screenshot of that particular dsgnArea, and save it in my server.
please help me out in this problem.
Say s is the DisplayObject object you want to capture and m is the mask applied on it.
var maskRect:Rectangle = m.getRect(s);
var matrix:Matrix = new Matrix(1, 0, 0, 1, -maskRect.x, -maskRect.y);
var w:Number = Math.min(s.width, maskRect.right) - maskRect.x;
var h:Number = Math.min(s.height, maskRect.bottom) - maskRect.y;
var bd:BitmapData = new BitmapData(w, h);
bd.draw(s, matrix);
Does that work?
The BitmapData draw method is what you are looking for. You can use it's clipRect param to define what you would like to draw (the masked parts).
Quasimondo did a handy little method to do this (take a snapshot of the whole displayObject), it's available here: http://www.quasimondo.com/archives/000670.php
I don't know if it works with masked content though.
if it doesn't, the trick would be to translate the whole content by the size of the mask
var bounds:Rectangle = dsgnAreaMask.getBounds( dsgnAreaMask );
instead of using the content of the clip
var bounds:Rectangle = clip.getBounds( clip );
as far as saving file to server is concerned, the question was asked (answered?) here AS3 Save Media File to server