localToGlobal/globalToLocal AS3 confusion - actionscript-3

I want to move a display object from one container to another, but have it appear in the same place on screen.
I thought I'd understood this years ago, but the following does not work:
function moveToNewContainer(obj:DisplayObject, newParent:DisplayObjectContainer):void {
var pos:Point = new Point(obj.x, obj.y);
var currentParent:DisplayObjectContainer = obj.parent;
pos = currentParent.localToGlobal(pos);
currentParent.removeChild(obj);
newParent.addChild(obj);
pos = newParent.globalToLocal(pos);
obj.x = pos.x;
obj.y = pos.y;
}
This doesn't position the object in the same place as I would have expected.
Does anyone know what I am doing wrong, please?
Thanks,
James

Using localToGlobal/globalToLocal and setting the x and y properties like you showed calculates the correct position for the object in its new parent, but does not adjust for other aspects of the transformation such as scaling or rotation. In other words, the object's registration point will indeed remain in the same place, but the object may be rotated, scaled, or sheared differently.
The solution to your problem will need to take into account the transform.concatenatedMatrix properties of the old and new parents--you'll need to multiply the object's transformation matrix by one and then by the inverse of the other, or something along those lines. Leave a comment if you need help working out the math.

There is nothing wrong with your code, provided that both containers have no transformations applied. If your clips are scaled, rotated, etc.. you need to handle that in addition to the coordinate space transformations that localToGlobal and globalToLocal do.

You have to check if your containers are actually placed on stage. If your new container isn't added as a child to stage, function globalToLocal fails, just because it doesnt know how to correctly calculate that data.

Related

cocos 2dx getPosition() , always returns initial position instead of current position

I have a sprite with having an action through which, it moves towards right side.
CCSprite *spaceShip1=CCSprite::create("ufo_1.png");
spaceShip1->setPosition(ccp(visibleSize.width/8,visibleSize.height/2));
this->addChild(spaceShip1, 3);
CCMoveBy* moveleft1 = CCMoveBy::create(3, ccp(visibleSize.width, 0));
spaceShip1->runAction(moveleft1);
I want to get the current visual position of sprite, as it is moving due to runAction, it should return its updated position.
I am using:
spaceShip1->getPosition();
and this position is utilizing here:
CCParticleSystemQuad* _spaceShip1 = new CCParticleSystemQuad();
_spaceShip1 = CCParticleSystemQuad::create("growingFlare.plist");
_spaceShip1->setPosition(spaceShip1->getPosition());
_spaceShip1->setAngle(180);
_spaceShip1->setScale(5);
_spaceShip1->stopSystem();
this->addChild(_spaceShip1, 4);
That particle effect must take place at the current position of spaceship, but it always took effect at initial position of spaceship.
I'm trying to get the current position of sprite. but it always returns the initial position instead of its current moving position.
What I have to do to get its current position?
float xPos = spaceShip->getPositionX();
float yPos = spaceShip->getPositionY();
CCLog("%f %f", xPos, yPos);
Try this in the method where you want to get the current x,y position of the moving sprite. It won't get the initial position what you get now.
That particle initialization happens during init(). Animation is not live then, hence will always give initial position.
You have 2 options.
In your update method. SetPosition() of your particle system every frame to the updated spaceship getPostion.
Make particle system as a child of spaceship.
In case of, "this->addChild()", do "_firstSpaceShip->addChild(_particleSystem)" and give it a initial x position like -10, so it always follow behind your spaceship.
May be this will help you out
CCParticleSystemQuad* _spaceShip1 = new CCParticleSystemQuad();
_spaceShip1 = CCParticleSystemQuad::create("growingFlare.plist");
_spaceShip1->setPosition(spaceShip1->getPositionX(), spaceShip1->getPositionY());

AS3 - Finding an objects x and y position relative to the stage

I'm new to ActionScript 3 and I have a character which you can control, the screen scrolls right along the stage and he can fire missiles.
The problem I'm getting is the missiles are created via these co-ords:
bullet.x = hero.mc.x;
bullet.y = hero.mc.y
These work fine untill the screen has scrolled to the right. I assume it's because the bullets are being spawned as a result of them using the canvas x,y and not the stages x,y
So i'm wondering how to find out the x and y of my hero in relative to the canvas so i can spawn the missiles on top of him!
Thanks, and if you need any more information let me know, I'm new to all this. Thank you.
You can do that with localToGlobal and globalToLocal. Your solution would be something like:
bulletPos = bullet.parent.localToGlobal(new Point(bullet.x, bullet.y));
Beware, though, as those are last resort functions. Normally, you'd have all your elements using the same 'layer', so comparisons are easier and faster.

ActionScript 3: Zoom into movieclip while not scaling its childrens

I've included a zoom functionality similar to the one explained at this website:
http://www.flashandmath.com/howtos/zoom/
This works perfectly on my background image(a map, that is), but I want to keep the symbols on my map the same size while zooming in.
I probably could work this out by changing all the children's size when calling the zoom-function, but I am hoping there is some kind of easy code adapt in my children class to make the size of the instances unchangable. Is there?
Thanks!
One crude way, so you don't have to calculate the symbols scale, would be to remove the symbols from the mapDisplayObject so they're no longer a child and instead put symbol placeholders. Then match each symbol's x and y to each place holder, using localToGlobal...
If your children are not scaled or skewed or rotated you can iterate all of them and set transformation matrix to 1/parentScale. Something like:
for each (var child:DisplayObject in parent) {
var matrix:Matrix = child.transform.matrix;
matrix.a = 1/parentScale;
matrix.d = 1/parentScale;
child.transform.matrix = marix;
}

Object does not rotate around pivot point

I have an object which looks like this:
When I try to rotate it using [INSTANCENAME].rotation += 10;
it still rotates around the middle of the object. Am I doing something wrong?
I've done a little research, and apparently there is no direct way to change the pivot point programmatically, AFAIK. Rather odd, seeing as you can change it in the Flash Pro IDE. (For those reading, the pivot point is NOT the same as the registration point.)
[EDIT: Thinking more about it, I don't think the pivot point actually "exists", at least in the context of a programmable property. It only exists in the context of some tools in the Flash IDE.]
You will need to place your object ALONE inside another object, so that the desired pivot point of the inner object is over the center of the outer object. Then, rotate the outer object.
You can later control your object's "pivot point" by changing the position of the inner object.
Since the outer object's center moves depending on its size, and the position of the inner object determines the size of the outer object, you'd need to apply some math. The x position of the inner object would need to be equal to the distance from the desired pivot point on the inner object to the far right edge of that inner object. The same concept applies to the y position.
This can be accomplished both in the IDE directly, or through code, whichever you choose.
An example of code to change this dynamically. This function is inside the outer object. (You can get pivotX and pivotY off an event listener, if you want.) [Sorry, the code is untested.]
function newPivot(int pivotX, int pivotY):void
{
inner.x = inner.width - pivotX;
inner.y = inner.height - pivotY;
}
I hope that solves your problem!
A very simple way is to do like this.
Convert the image to a symbol(MovieClip). [you might have already done it].
Double Click on the MovieClip/Sprite to enter inside.
Move the Image so that the registration point align towards the pivot.
NB: Applicable only in case of FLASH IDE.

Comparing two bitmaps against each other for match as3

I'm trying to position an image on top of another image based upon the make-up of the smaller image. The smaller image is a cut-out of a larger image and I need it to be positioned exactly on the larger image to make it look like a single image, but allow for separate filters and alphas to be applied. As the images are not simple rectangles or circles, but complex satellite images, I cannot simply redraw them in code. I have quite a few images and therefore do not feel like manually finding the position of each image every and hard setting them manually in actionscript. Is there any way for me to sample a small 5-10 sq. pixel area against the larger image and set the x and y values of the smaller image if a perfect match is found? All the images are in an array and iterating through them has already been set, I just need a way to sample and match pixels. My first guess was to loop the images pixel by pixel right and down, covering the whole bitmap and moving to the next child in the array once a match was found, leaving the matched child where it was when the perfect match was found.
I hope I understood your question correctly.
There may be an option that uses copypixels to achieve what you want. You can use the bitmapdata.rect value to determine the size of the sample you want, and loop through the bigger bitmap using thet rectangle and a moving point. Let's see if I can code this out...
function findBitmapInBitmap(tinyimg:BitmapData, largeimg:BitmapData):Point {
var rect:Rectangle = tinyimg.rect;
var xbound:uint = largeimg.rect.width;
var ybound:uint = largeimg.rect.height;
var imgtest:BitmapData = new BitmapData(tinyimg.rect.width, tinyimg.rect.height);
for (var ypos:uint = 0, y <= ybound, y++) {
for (var xpos:uint = 0, x <= xbound, x++) {
imgtest.copyPixels(largeimg, rect, new Point(xpos, ypos);
if (imgtest.compare(tinyimg) == 0) return new Point(xpos, ypos);
}
}
return new Point(-1,-1); // Dummy value, indicating no match.
}
Something along those lines should work - I'm sure there's room for code elegance and possible optimization. However, it seems like something like this method would be very slow, since you'd have to check each pixel for a match.
There is a better way. Split your big image into layers, and use the blitting technique to composite them at runtime. In your case, you could create a ground texture without satellites, and then create the satellites separately, and use the copyPixels method to place them whereever you want. Google "blitting in as3" to find some good tutorials. I'm currently working on a game project that uses this technique and it's a very good method.
Good luck!
Edit: Forgot to code in a default return statement. Using this method, you'd have to return an invalid point (like (-1,-1)) and check for it outside the function. Alternatively, you could just copy your small bitmap to the big one within the function, which would be much more logical, but I don't know your requirements.
You need to find pixel sequence in the big image. BitmapData.getPixel gives you pixel value. So get first pixel from small image, find it in big image, then continue comparing until you find full match. If you have trouble to code that, feel free to ask.
For the actual comparison, there's BitmapData.compare which returns the number 0 if the BitmapData objects are equivalent.