actionscript child sprite coordinate - actionscript-3

I have 3 square. smallest square s3 is inside s2. s2 is in side s1. each is 10px larger
var s1:Sprite = new Sprite();
var s2:Sprite = new Sprite();
var s3:Sprite = new Sprite();
s2.addChild(s3);
s1.addChild(s2);
how can I find the coordinate of child in its parent's coordinate system?
Inside s3
trace(x) //10
trace(parent.childXof(s3)) //20 how do I get this?

What you are looking for is the localToGlobal and globalToLocal methods of DisplayObjects
Links to documentation:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObject.html#globalToLocal%28%29
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObject.html#localToGlobal%28%29
They allow you to transform a point from one coordinate space to the other, which is what you are looking to do.
Hope it helps!

Related

AS3 image rotate within / scale to fit sprite

We're making bitmap data from a sprite where we want to take an image and rotate within / scale to fit. This is our code, which includes a rotation.
_rotation defines how much the user has input.
The problem is, we're getting an output file that is 100% white.
We think that the image is rotating about 0x0y therefore rotating the image outside the bounds of the sprite.
Furthermore, the image is not scaling to the child, instead is sort of "cropping" as it inherits.
What is the best way of doing this? Basically we want to take an image and rotate within / scale to fit
var sprite1:Sprite = new Sprite();
addChild(sprite1);
var photoBitmap:Bitmap = new Bitmap(_bitmapData);
sprite1.addChild(photoBitmap);
sprite1.rotation = _rotation;
var sprite2:Sprite = new Sprite();
addChild(sprite2);
sprite2.addChild(sprite1);
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
bitmapData.draw(sprite2);
The simple way to draw sprite with scaling/rotating is using Matrix in method bitmapData.draw().
Example:
var sourceImage:SomeSprite = new SomeSprite();
var matrix:Matrix = new Matrix();
matrix.scale(0.5, 0.5);
matrix.rotate(0.5 * Math.PI);
var newImage:BitmapData = new BitmapData(sourceImage.width/2, sourceImage.height/2);
newImage.draw(sourceImage, matrix);
Your issue is likely a cause of rotating around the top left corner (which can make the entire object left of or above the registration point (0 x and 0 y) and not get drawn.
An easy way you can account for this, is to move sprite1 after the rotation to account for the new size and position caused by rotating:
...
sprite2.addChild(sprite1);
var actualPosition:Rectangle = sprite2.getBounds(sprite2); //this gets the new position/dimensions of the object
sprite1.x = -actualPosition.x;
sprite1.y = -actualPosition.y;
var bitmapData:BitmapData = new BitmapData(sprite2.width,sprite2.height,false,0xFFFFFF);
...

Resize as a function of distance between mc's

I hope this hasn't been asked too much before. When I search I only get questions pertaining to rescaling to window size.
Now my question. I got one space ship firing a beam against another ship. I want the beam to show for some time and I want it to "bridge" the two ships. In other words, I want the beam to extend its width between the two ships.
I try to do this with a dot movie clip that is 1 pixel wide and high (and aligned left edge). I try to resize it with the following code: (target is the ship to be fire at and owner is the ship firing)
dist.vx = target.x - owner.x;
dist.vy = target.y - owner.y;
dist.dist = Math.sqrt(dist.vx*dist.vx + dist.vy*dist.vy);
width = dist.dist;
x = owner.x;
y = owner.y;
rotation = Math.atan2(target.y-y, target.x-x)*180/Math.PI;
This doesn't work as intended because 1) dot also gets alot bigger in the other dimension - how can I "turn off" this behavior? and 2) sometimes it seems to get way to wide - but only in certain angles...
Any suggestions on either solving the heigh/width scaling or on another way to achieve the same effect?
(I'm new to coding and flash.) Thanks!
By resizing a dot, you will have a rectangle...
You can dynamically create a sprite covering both ships and moveTo the hit point of one ship then lineTo the other ship... You do not need distance calculation at all. What you have to do is being careful on the placement of the sprite. So that you can calculate relative hitting points by simple math.
Suppose you have mc space contining mc ship1 and mc ship2, and hit point coords on ships are named hx, hy and you will use sprite s, calculation will be as follows.
// calculate hit points relative to mc space
var s1HX:int = ship1.x + ship1.hx,
s1HY:int = ship1.y + ship1.hy,
s2HX:int = ship2.x + ship2.hx,
s2HY:int = ship2.y + ship2.hy,
// sprite relative moveTo lineTo coords will be these.
mX: int, mY: int,
lX: int, lY: int;
// top left of sprite will be minimum of the hit coords.
s.x = (s1HX <= s2HX)? s1HX : s2HX;
s.y = (s1HY <= s2HY)? s1HY : s2HY;
// now we can get sprite relative moveTo lineTo coordinates:
mX = s1HX - s.x;
mY = s1HY - s.y;
lX = s2HX - s.x;
lY = s2HY - s.y;
The rest is implementation with using these with fancy line styles etc...
To create a new sprite:
var s:Sprite = new Sprite();
Adding / removing it to/from mc space:
space.addChild(s);
space.removeChild(s);
For graphics use the graphics object of sprite.
s.graphics
For setting line styles you can use:
s.graphics.lineStyle(...) ,
s.graphics.lineBitmapStyle(...),
s.graphics.lineGradientStyle(...)
Functions, please read the manual for usage.
After setting the line style to draw the line use:
s.graphics.moveTo(mX,mY);
s.graphics.lineTo(lX,lY);
For pulsating effects you have to do a little more complicated things such as using tween class which you can read about here: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fl/transitions/Tween.html
Note that:
Sprites are no complicated magic, they are like mc's but they do not have timelines etc.
Sprites try to scale when width or height change programmatically. So do not touch them, moveTo lineTo automatically sets the size of a sprite...

make visual clone of displayObject that's nested within other displayObjects, and add the clone to the stage layer in the same location, rotation, etc

I want to be able to grab a copy of a DisplayObject that is nested within other transformed DisplayObjects (rotated, scaled, stretched objects), and be able to stamp it back into the same visual location, but on the stage layer. Essentially, being able to make a clone of a nested DisplayObject, but be able to add the clone to the stage layer, yet have it perfectly align (visually) with the original (same position, scale, rotation)
I have been working with something along the lines of:
// draw the pixels of a displayobject into a new bitmap object
var bitmapData:BitmapData = new BitmapData(nestedSprite.width, nestedSprite.height, true, 0xFFFFFF);
var bitmap:Bitmap = new Bitmap(bitmapData);
bitmapData.draw(nestedSprite);
// put the copy on the top most layer
stage.addChild(bitmap);
// position the copy to perfectly overlay the original, but on the top stage layer
var point:Point = nestedSprite.localToGlobal(new Point(0, 0));
bitmap.x = point.x;
bitmap.y = point.y;
But this only works well for displayObjects whose parents are not transformed; and for displayObjetcs that are perectly at the (0,0) origin. It falls apart for centered aligned objects or scaled parents, etc.
I am aware that I can add a matrix param to the .draw() method, as well as a clipping rectngle, and scale my bitmap afterwards, or setting the transform of one object to another, or use .transform.concatenatedMatrix, or use nestedObject.getBounds(null), or nestedSprite.getBounds(nestedSprite), etc. But I have unfortunately fallen into doing trial and error programming on this one, and with some many variables, this is never a good way to solve a programming problem.
I believe this function should work, the only extra step was offsetting the concatenated matrix so that the target would draw with its top left at (0, 0) on the Bitmap even if its origin was somewhere else. Hopefully the rest is self explanatory, but I can add more comments if anything doesn't make sense.
function createBitmapClone(target:DisplayObject):Bitmap {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
var clone:Bitmap = new Bitmap(cloneData);
// Move clone to target's global position, minus the origin offset.
clone.x = targetGlobalPos.x - targetOriginOffset.x;
clone.y = targetGlobalPos.y - targetOriginOffset.y;
return clone;
}
Unfortunately, pixelBounds seems to return an origin of (0, 0) if there are any filters on the DisplayObjects, which obviously breaks things.
Edit: Replaced target.transform.pixelBounds with target.getBounds(target.stage) as a slight improvement. This keeps the position correct if there are filters, but filters on parent DisplayObjects still won't be included, and filters on the target can overlap the edges of the Bitmap. I'm not sure if there's a simple way to work around that.
Update: Jimmi Heiserman spotted that this function is broken if the swf is scaled. Without stage.scaleMode = StageScaleMode.NO_SCALE; though, the stageWidth and stageHeight parameters seem to stay unchanged, so the only (rather hacky) workaround I've found is to add an "unscaled" test Sprite and use its concatenatedMatrix to adjust the clone's position and scale:
function createScaledBitmapClone(target:DisplayObject):Bitmap {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Create a test Sprite to check if the stage is scaled.
var testSprite:Sprite = new Sprite();
target.stage.addChild(testSprite);
var testMatrix:Matrix = testSprite.transform.concatenatedMatrix;
target.stage.removeChild(testSprite);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x * testMatrix.a;
targetTransform.ty = targetOriginOffset.y * testMatrix.d;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width * testMatrix.a, targetGlobalBounds.height * testMatrix.d, true, 0x00000000);
cloneData.draw(target, targetTransform);
var clone:Bitmap = new Bitmap(cloneData);
// Move clone to target's global position, minus the origin offset, and cancel out stage scaling.
clone.x = targetGlobalPos.x - targetOriginOffset.x;
clone.y = targetGlobalPos.y - targetOriginOffset.y;
clone.scaleX = 1 / testMatrix.a;
clone.scaleY = 1 / testMatrix.d;
return clone;
}
Have you tried passing the parents transform into draw? draw takes a transform matrix as the second param.
If you have a handle on the parent you can use something like this
bitmapData.draw(nestedSprite, parent.transform.matrix);

Using localToGlobal to switch image positions

I am trying to convert from coordinates of a parent container to global stage coordinates. This is the object and the container:
imgSprite.addChild(imgInstance); //imgInstance is imported from class
imageContainer.addChild(last);
imageContainer.addChild(imgSprite); // imgSprite and last are to be replaced
Basically, I want to switch positions of two images in imageContainer.
I applied the localToGlobal() function, but that hasn't had any effect. What did I do wrong?
This is my function that replaces them. Note: this code belongs to class main, parent of container is stage and every imgSprite is just added to imgContainer and moved via obj.x, obj.y (not in the code).
function click(e:MouseEvent):void {
var p1:Point = e.currentTarget.localToGlobal(newPoint(e.currentTarget.x, e.currentTarget.y));
var p2:Point = last.localToGlobal(new Point(last.x, last.y));
e.currentTarget.x = globalToLocal(p2).x;
e.currentTarget.y = globalToLocal(p2).y;
last.x = globalToLocal(p1).x;
last.y = globalToLocal(p1).y;
}
As I understand it, every object has local and global positions. So, here I convert a local position to a global, and then again when moving the other object to this position, I convert it to local, as they belong to the same parent it should result in matching coordinates, but my images start flying around in all directions and I start pulling my hair.
var p2:Point = last.localToGlobal(new Point(last.x, last.y));
should be
var p2:Point = last.localToGlobal(new Point(0, 0));
The Point argument within localToGlobal() is the point within the DisplayObject that you want to globalize. So if last is located at (50,50) within its parent container, your code is really asking for the global coordinate of (50,50) within last. In this case, (0,0) is (last.x, last.y).

operations with BitmapData

we have a square movie clip with some clild movie clips on it. Consider a diagonal of a squere. I want to make the following transformation with bimap data of a movie clip: the triangle located upper then diagonal should remain unchanged, the lower triangle should be replaced with simetric reflection of upper triangle.
Is there a simple way to do that?
Exactly, the way is to take a snapshot of the movie, then mirror it, take another snapshot and combine these two snapshots.
Note, that the content you will get will be "static", so this way you can't copy the movieclip's animated parts.
//store the movie's graphical content in a bitmapdata
var bmd:BitmapData = new BitmapData(movie.width, movie.height);
bmd.draw(movie);
//then create a temporary movie in which you will do the mirroring
var temp:MovieClip = new MovieClip();
temp.addChild(new Bitmap(bmd));
//create the diagonal mask
var _mask:MovieClip = new MovieClip();
with(_mask.graphics) beginFill(0xff0000), lineTo(movie.width, 0), lineTo(movie.width, movie.height), lineTo(0, 0), endFill();
temp.addChild(_mask);
temp.mask = _mask;
//this is the mirroring part
temp.scaleX = temp.scaleY = -1;
addChild(temp);
//then create another bitmapdata for storing the so called "upper-triangle"
//important, that this bitmapdata should be transparent, "true" sets this
var bmd1:BitmapData = new BitmapData(temp.width, temp.height, true, 0x00);
//then do another mirroring transformation
var matrix:Matrix = new Matrix(-1, 0, 0, -1);
matrix.tx = temp.width;
matrix.ty = temp.height;
//draw the visual content on the bitmapdata
bmd1.draw(temp, matrix);
//and finally, on the original bitmapdata, draw the mirrored part
bmd.draw(bmd1);
//and add it to the top layer of the original movie, or whatever you want to do with it
movie.addChild(new Bitmap(bmd));
The simplest way I can think of is rotating the movieclip 45º and draw the upper rectangle into the lower rectangle inversed, and then rotate the bitmapdata back 45º. You can use a Matrix (2nd argument in the BitmapData.draw method) to draw it rotated and not actually rotate anything.