I need to know where the Sprite.graphics start to do some stuff. When I add the sprite to my MovieClip, (x,y) coordinates are (0,0) but I need to know coordinates from Sprite.graphics, not Sprite. There are some images so clarify what I want:
I have this board where user can draw some forms (lines, arrows, polygons, etc.) When the user draw a line, I interpret that Sprite is created (with Sprite.graphics inside it, the real form).
How can I catch the point where Sprite.graphics is created? Actually I can't because Sprite.graphics is read-only.
Thanks!
EDIT: some source code
line = new Sprite();
line.graphics.moveTo(posX,posY);
line.graphics.lineStyle(10);
line.graphics.lineTo(endposX,endposY);
Global.board.addChild(line);
To get the bounds of visual part, you can try:
var bounds: Rectangle = line.getBounds(line);
There is also a getRect() method, but that leaves out space taken by strokes.
You cannot access the graphics data like that. Your best chance would be to save the coordinates posX and posY yourself when the line is being drawn.
Related
I am developing a coloring game using adobe air and as3. I have an image with black outline and the user can draw / color the image using a pen tool. I need help to figure out how can I restrict the user to draw within the outlines only. Masking the image with the line-graphics is something I have tried but it hangs the application. Any hint / suggestion towards the solution is appreciated.
following is the code on mouse_down event
_dot = new MovieClip();
_dot.graphics.lineStyle(lineSize, color);
_dot.graphics.moveTo(img.mouseX,img.mouseY);
img.addChild(_dot);
Let's say, the area you are drawing on is a DisplayObject with an instance name of Canvas. What you need is to check if the mouse is on Canvas or not.
In order to do so, you want to use the DisplayObject.hitTestPoint(...) method with the shapeFlag set to true (if it is false, it tests the point against the object's rectangle bounding box, which would produce the wrong results for any non-rectangular or rotated shapes).
So, you do as following:
var P:Point = new Point;
// First, convert coordinates to Stage coordinates,
// because the method requires so.
P.x = Canvas.mouseX;
P.y = Canvas.mouseY;
P = Canvas.localToGlobal(P);
// Now, test if the mouse is within the given canvas.
if (Canvas.hitTestPoint(P.x, P.y, true))
{
// The drawing should happen here.
}
I only want to show a portion of a shape drawn on a canvas.
My line is essentially this, and it works fine:
ctx.fillRect( xPosition, rectHeight - offsetV , rectWidth, rectHeight);
The second variable there is going to be negative. So, my quesiton is: is it bad practice (or am I setting myself for errors down the road) to draw a path that starts off the canvas (with a negative coordinate) and then continue drawing on to the canvas.
No problem at all. If you have very large number of drawing object you can (like GameAlchemist said) prevent drawing that object .If you use canvas like map for explore (zoom out/in ctx, translate whole context) that preventing draw can cost more that clip cost. And its complicated ...
I have some expire with drawing object out of canvas. You can have a problem if you put calculation and other (no drawing) staff intro draw function.
Important :
-Make canvas draw function code clear(only draw canvas code).
-If your app no need for const update make update call only when it needs.
-Clear canvas only in (0,0,canvas.w,canvas.h)
-Use style only when it needs (stroke,fill,font etc.)
I'm trying to make a shape available for duplicating. Here's an explanation of what I've done, what I'm trying to do, and where I'm stuck:
Drew a shape manually in the Flash IDE (paintbrush).
Created a new movieclip containing the shape; exports as a class.
Instantiate the class (var mc:MovieClip = new shapeMovieClip()).
Add a reference to the shape in mc that I want (var myShape:Shape = mc.getChildAt(0) as Shape;
This works perfect and I now have my shape, but how can I duplicate it without instantiating the parent MovieClip class - is it possible?
I've tried creating a new shape and using the copyFrom() graphics method with no avail, I believe this method just copies draw calls when they're made on the referenced graphics and instead I just have a reference of a shape that's already been drawn.
Right now I'm extending the movieclip as a sprite instead, instantiating, pulling the shape from the parent and saving its reference, and then nulling the sprite. Does anyone know of a better, more lightweight, strategy for duplicating Shapes in this manner?
Basically depends on whether you need to scale your shapes. If you don't, and you can work it out with a fixed sized bitmap representation of the shape, then you will get much better performance drawing your shape to a BitmapData (it's called rasterisation) and instanciating Bitmap objects (as other commenters have pointed out). The code would go something like this:
var base:Sprite = new shapeMovieClip();
var bmd:BitmapData = new BitmapData(base.width, base.height, true, 0);
bmd.draw(base);
var clip1:Bitmap = new Bitmap(bmd);
var clip2:Bitmap = new Bitmap(bmd);
If you do need to scale the clips, you will get pixelation using bitmaps. When scaling down Bitmap.smoothing can help to some extent (also when rotating), but if you need to scale up, you will probably have to use some kind of mip-mapping. This is basically creating a few bitmaps of the shape at different scale levels, and then swap them depending on the current scale. Coding this has some complexity (using a helper parent to adjust the scale can help) but it will definitely perform better than using many shape symbols (with or without a sprite parent).
This is very old, but it still comes up high in Google, so I just wanted to share a true shape duplicating method:
var shapeonstage:Shape = shapeMadeInIDE;
var g:Vector.<IGraphicsData> = shapeonstage.graphics.readGraphicsData();
var shapecopy:Shape = new Shape();
shapecopy.graphics.drawGraphicsData(g)
And boom. It works. Had to share this because it would have helped me a looooong time ago and in so many ways.
UPDATE:
There is some clarification I'd like to add why you would want to use this method, for duplicating AND for storing references to Shapes that are within an swf.
If you target a Shape object on the stage or in a movie clip, the Flash Rendering engine does something strange. It will RECYCLE Shape objects to render new graphics thus making your Shape reference point to a COMPLETELY different rendering.
For example:
Create an fla with a movieclip.
Inside the movie clip make 10 frames.
On each frame, draw a different shape
In your code, get a reference to the shape (The Shape on Frame 1)
Draw and verify your shape (draw to a bitmap then put the bmp on stage)
Now let the flash engine play for 5 frames
Draw and verify your shape again
The second time you draw your shape without EVER reassigning your shape reference, will SOMETIMES yield a completely different shape.
Just know, this little quirk can leave you pulling your hair out if you don't know what you're looking for :)
I am building a globe with the countries. I have all of the spheres built and everything works fine. The problem is to get the globe to look right I had to put all of the movieclips into one big moveclip then broke down from there. The problem is I cannot get Away3D to recognize the secondary movieclips. If I apply the listener to the whole sphere it works fine (but that isn't functional). Is there a way to use nested movieclips in away3d?
//what works
var materialMovie:MovieClip = new causticsMovie() as MovieClip;
var causticsMaterial:MovieMaterial = new MovieMaterial( materialMovie);
var sphere:Sphere = new Sphere({material:causticsMaterial, radius:300,segmentsH:18,segmentsW:26, interactive:true});
causticsMaterial.interactive = true;
view.scene.addChild(sphere);
sphere.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
//what doesn't
world_map.northAfrica_mc.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
Is there a solution to this problem?
If I understand how 3d engines in flash generally work, this won't be possible. They create a texture from the original movieclip(s) which they then transform. So there are no movieclips left to click on.
There is a couple of ways around this I think. You could transform the click location into polar coordinates (I'm not sure about the maths there, but google should be helpful), and figure out which location was clicked that way.
Or, you could (probably) have a second, invisible sphere (off stage or not added as a child, not sure which will work), where you create a different texture where each country has a different color. You would rotate this to the same angles as the visible sphere. Then, on click, render that to a BitmapData and check the pixel value of the point you clicked (translated so the point on the visible sphere and the invisible sphere are the same). I think this way is the easier of the two, and will have better results.
I know that there are people out there creating classes for this (ie http://coreyoneil.com/portfolio/index.php?project=5). But I want to learn how to do it myself so I can create everything I need the way I need.
I've read about BitMap and BitMapData. I should be able to .draw the MovieClips onto a BitMap so I could then cycle the pixels looking for the collisions. However, It's weird and confusing dealing with the offsets.. And it seams like the MyBitMap.rect has always x = 0 and y = 0... and I can't seam to find the original position of the things...
I'm thinking of doing a hitTestObject first, then if this was positive, I would investigate the intersection betwen the movieclips rectangles for the pixel collisions.
But then there is also another problem (the rotation of movieclips)...
...I need some enlightment here on how to do it.
Please, any help would be appreciated..
If you're using BitmapData objects with transparency you can use BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean.
You'll have to change from global coords to the local BitmapData coords which will require a bit of math if it is rotated. That's easily achieved (look up affine transform for more info on wiki):
var coordTransform:Matrix = new Matrix();
coordTransform.rotate(rotationRadians);
coordTransform.translate(x, y);
coordTransform.transformPoint(/* your point */);
A classic reference for pixel perfect collision detection in flash is this Grant Skinner's article. It's AS2, but the logic is the same for AS3 (there are ports available if you google a bit).
If I recall correctly, this particular implementation worked as long as both tested objects had the same parent, but that can be fixed.
About BitmapData x and y values, I understand it could be confusing; however, the way it works makes sense to me. A BitmapData is just what the name implies: pixel data. It's not a display object, and cannot be in the display list; so having x or y different than 0 doesn't really make sense, if you think about it. The easiest way to deal with this is probably storing the (x,y) offset of the source object (the display object you have drawn from) and translate it to the global coordinate space so you can compare any objects, no matter what's their position in the display list (using something like var globalPoint:Point = source.parent.localToGlobal(new Point(source.x,source.y)).
I've previously used Troy Gilbert's pixel perfect collision detection class (adapted from Andre Michelle, Grant Skinner and Boulevart) which works really well (handles rotation, different parents, etc.):
http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/
http://troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/
and from there he has also linked to this project (which I've not used, but looks really impressive):
http://www.coreyoneil.com/portfolio/index.php?project=5
I managed to do it after all, and I already wrote my class for collision detections,/collisions angle and other extras.
The most confusing process is maybe to align the bitmaps correctly for comparing. When whe draw() a movieclip into a a BitmapData, if we addChild() the corresponding Bitmap we can see that part of it is not visible. it appears to be drawn from the center to right and down only, leaving the top and left parts away from beeing drawn. The solution is giving a transform matrix in the second argument of the draw method that aligns the bitmap and makes it all be drawn.
this is an example of a function in my class to create a bitmap for comparing:
static public function createAlignedBitmap(mc: MovieClip, mc_rect: Rectangle): BitmapData{
var mc_offset: Matrix;
var mc_bmd: BitmapData;
mc_offset = mc.transform.matrix;
mc_offset.tx = mc.x - mc_rect.x;
mc_offset.ty = mc.y - mc_rect.y;
mc_bmd = new BitmapData(mc_rect.width, mc_rect.height, true, 0);
mc_bmd.draw(mc, mc_offset);
return mc_bmd;
}
in order to use it, if you are on the timeline, you do:
className.createAlignedBitmap(myMovieClip, myMovieClip.getBounds(this))
Notice the use of getBounds which return the rectangle in which the movie clip is embedded. This allows the calculation of the offset matrix.
This method is quite similar to the on shown here http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
By the ways, if this is an interesting matter for you, check my other question which I'll post in a few moments.