Arrange Z-index of movieclip and sprite in Actionscript AS3 - actionscript-3

I found this piece of code which apparently sets the 'z-index' of a child object, however I have a movieclip on the stage and a sprite which is being generated from the actions class. I understand they have to be within the same parent? but have no idea how to do this.
parent.setChildIndex(childObject, i)
My pie chart sprite is called into being with this function...
this.graphics.clear();
this.graphics.lineStyle(3, 0xFFFFFF);
this.graphics.beginFill(0xFF0000, 0.5);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge1start, wedge1end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge1end, wedge2end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge2end, wedge3end);
this.drawSegment(this, stage.stageWidth/2, stage.stageHeight/2, piesize, wedge3end, wedge4end);
this.graphics.endFill();
public function drawSegment(target:Sprite, x:Number, y:Number, r:Number, aStart:Number, aEnd:Number, step:Number = 1):void {
// More efficient to work in radians
var degreesPerRadian:Number = Math.PI / 180;
aStart *= degreesPerRadian;
aEnd *= degreesPerRadian;
step *= degreesPerRadian;
// Draw the segment
target.graphics.moveTo(x, y);
for (var theta:Number = aStart; theta < aEnd; theta += Math.min(step, aEnd - theta)) {
target.graphics.lineTo(x + r * Math.cos(theta), y + r * Math.sin(theta));
}
target.graphics.lineTo(x + r * Math.cos(aEnd), y + r * Math.sin(aEnd));
target.graphics.lineTo(x, y);
}
currently I just plonked my movieclip on the stage but I'm going to guess I need to call the movieclip from the actions class as well. I think I can manage that but can't figure out how to first create a parent and then call those 2 children into it.
Thanks for any help

You need to wrap those two graphics into two separate Sprite objects. Those two objects can be added to stage (or this in your case, I don't know what is it). So you will have a parent object with two children objects. Then you can swap them.
Working with graphics disables your option to swap them. It's a single object in which you are drawing.
So you just need to wrap those graphics into another child:
var drawings:Sprite = new Sprite();
drawings.graphics.clear(); // instead of this.graphics.clear()
drawings.graphics.lineStyle(3, 0xFFFFFF);
this.drawSegment(drawings, stage.stageWidth/2 ...) // pass DRAWINGS instead of this
this.addChild(drawings);
This way you have wrapped all those graphics and added them to this. Now you can use:
this.swapChildren(drawings, otherChild); // swaps two objects
this.setChildIndex(drawings, 5); // sets index for drawings only

Related

as3 - How to access child's child?

I dispatched an event for a bullet to spawn on the page. However the bullet should be located in the area where the page's child child should be. There is a Page One MovieClip, which has a child named player and the player's child is gun. So I'm trying to keep the location and rotation of the bullet the same as the player's gun. So I need to access Page One's child's child. The player and the turret are using instance names and not variables.
I tried this code, but the bullet spawns in the page but will not spawn itself on the turret's location. This event is located in the PageOne class.
function fire(e:Event)
{
var b:Bullet = new Bullet();
b.rotation = player.turret.rotation;
b.x = player.turret.x + player.turret.width * Math.cos(player.turret.rotation / 180 * Math.PI);
b.y = player.turret.y + player.turret.width * Math.sin(player.turret.rotation / 180 * Math.PI);
addChild(b);
}
You can access to the turret child. The problem is that you need to convert the coords inside the turret MovieClip to the coords inside the PageOne MovieClip:
var b: Bullet = new Bullet();
var turretpoint:Point = new Point(player.turret.width, 0);
var pagepoint: Point = this.globalToLocal(player.turret.localToGlobal(turretpoint));
b.rotation = (player.scaleX > 0) ? player.turret.rotation : 180 - player.turret.rotation;
b.x = pagepoint.x;
b.y = pagepoint.y;
addChild(b);

How can masking not work in ActionScript 3?

I wanted to mask some nodes of my DisplayObject tree. I couldn't make masking work in my big project. So I build a simple example for me and I saw it works actually pretty good. But I can't figure out why it doesn't work in my big project. All my visible objects are Sprites or from classes that extend Sprite.
masking in big project doesn't work
I can see the normal state of my nodeToBeMasked
when I add the mask to this node I can see the mask
but when I set the mask to be the mask, I continue to see everything (pure nodeToBeMasked is masked but not the children - which would be much more important)
masking in simple example works fine
How can masking stop working ?
Code: (that doesn't work, big project)
// custom class extends Sprite
override protected function onAddToStage(event:Event):void
{
trace(stage); // stage exists
var maskSprite:Sprite = new Sprite();
maskSprite.graphics.beginFill(0xffff00, 1);
maskSprite.graphics.drawCircle(0, 0, 64);
maskSprite.graphics.endFill();
maskSprite.x = 64;
maskSprite.y = 64;
if (true)
{
this.addChild(maskSprite); // doesn't help
this.mask = maskSprite; // I can see EVERYTHING here, inside and outside the cirle
}
else
addChild(maskSprite); // I can see the mask here
}
Code: (that works)
[SWF(frameRate="60",backgroundColor="0xffffff",width="128",height="128")]
public class MaskTest extends Sprite
{
public function MaskTest()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event: Event): void
{
trace(stage);
// this
graphics.beginFill(0x00ff00, 1);
graphics.drawRect(8, 8, 112, 112);
graphics.endFill();
// extra childs <- ^^
for (var i: int = 0; i < 100; i++)
{
var child: Sprite = new Sprite();
child.graphics.beginFill(uint(Math.random() * 0x1000000), 1);
child.graphics.drawRect(Math.random() * 64, Math.random() * 64, 64, 64);
child.graphics.endFill();
addChild(child);
}
// mask
var maskSprite: Sprite = new Sprite();
maskSprite.graphics.beginFill(0xffff00, 1);
maskSprite.graphics.drawCircle(0, 0, 64);
maskSprite.graphics.endFill();
maskSprite.x = 64;
maskSprite.y = 64;
// switch to check the mask
if (true)
this.mask = maskSprite;
else
addChild(maskSprite);
}
}
Update:
I found out that my custom class (that is the root and is only responsible for Event.ENTER_FRAME updates) was causing the problem. I don't know why but by disabling the z update in all my project solved the children of my maskedNode not being masked.
The mask MUST be added to the parent to work, not only used as
obj.mask = myMask; //This will not work alone
To make it work, it must be added to the parent object display list
obj.addChild(myMask);
obj.mask = myMask;
//this wasthe problem in my big project
maskSprite.z = 0; // avoid this with masks
Just a wild guess from me:if you use the properties z, rotationX, rotationY, rotationZ (maybe some more) the sprite is shifted to the 3D space and the masking is only working in 2D.
I have experimented with Flash 3D a bit. The transition from 2D to 3D seemed very smooth. You can't see when they "turn".

Zooming and translate in as3 AIR Android

I am developing an android app with Adobe Flash cs6 and actionscript3. I have multiple moviclips at various locations on stage. Now I need to add a zoom feature that will zoom all movieclips as one movieclip. I cannot combine all movieclips together into one movieclip. My zoom feature works but it does not translate the movieclips to a new position. (Meaning they zoom at their original positions only) How can I accomplish this? Following is my zooming code :
/* ZOOM FEATURE */
Multitouch.inputMode = MultitouchInputMode.GESTURE;
zoomer.addEventListener(TransformGestureEvent.GESTURE_ZOOM , onZoom);
function onZoom (e:TransformGestureEvent):void{
mc1.scaleX *= (e.scaleX+e.scaleY)/2;
mc1.scaleY *= (e.scaleX+e.scaleY)/2;
mc2.scaleX *= (e.scaleX+e.scaleY)/2;
mc2.scaleY *= (e.scaleX+e.scaleY)/2;
mc3.scaleX *= (e.scaleX+e.scaleY)/2;
mc3.scaleY *= (e.scaleX+e.scaleY)/2;
}
Not the cleanest code I've written, but it should do the trick. scaleInPlace() accepts 4 arguments, 2 required, two optional:
obj: the display object you want to scale
scaleFactor: just as it sounds, how big/small do you want it?
fromX: the X coordinate where you want to scale from. Left, middle, right? If omitted, it operates from the middle of the compiled stage size.
fromY: same as the previous, but for top, middle, bottom.
This will preserve your DisplayList hierarchy while allowing you to scale to your heart's desire. If you had a lot of objects to scale, I'd probably parent all of them to the container first, and then run the scale and reparenting operations. While it works, this is the reason I feel it's not the "cleanest" solution. In my own classes, I've written a purely mathematical solution that doesn't include adding/removing DisplayObjects, but it's fairly tied up in my own classes I couldn't pull it out here and have it work.
Cheers!
// Let's scale myObject to 50% of its original size.
scaleInPlace(myObject, 0.5);
function scaleInPlace(obj:DisplayObject, scaleFactor:Number, fromX:Number = NaN, fromY:Number = NaN):void {
// If no coordinates from where to scale the image are provided, start at the middle of the screen
if (isNaN(fromX)) { fromX = loaderInfo.width/2; }
if (isNaN(fromY)) { fromY = loaderInfo.height/2; }
var father:DisplayObjectContainer = obj.parent;
var rect:Rectangle; // Coordinates for tracking our object
var index:int = getChildIndex(obj) // Where this object should go when we put it back
// Create the container
var container:Sprite = new Sprite();
father.addChild(container);
// Place the origin of the scale operation
container.x = fromX;
container.y = fromY;
// Get the coordinates of our object relative to our container
rect = obj.getRect(container);
// Parent and move into place
container.addChild(obj);
obj.x = rect.x;
obj.y = rect.y;
// Scale
container.scaleX = container.scaleY = scaleFactor;
// Get the coordinates and size of our scaled object relative to our father
rect = obj.getRect(father);
// Cleanup the display list
father.addChildAt(obj, index);
father.removeChild(container)
// Apply the new coordinates and size
obj.x = rect.x;
obj.y = rect.y;
obj.width = rect.width;
obj.height = rect.height;
}

Why doesn't my custom FlxSprite appear on the stage?

I created a custom FlxSprite for a fireball by creating a new class(Fireball.as) and typing "extends FlxSprite" after the class name. In the constructor, it calls a function called "shoot()", which directs it to the target and plays a sound:
private function shoot():void {
dx = target.x - x;
dy = target.y - y;
var norm:int = Math.sqrt(dx * dx + dy * dy);
if (norm != 0) {
dx *= (10 / norm);
dy *= (10 / norm);
}
FlxG.play(soundShoot);
}
Then, I created an array to hold all the fireballs in the game state(PlayState.as):
public var fire:Array = new Array();
Then in my input() function, when someone pushes the mouse button, it pushes a new Fireball in the array:
if (FlxG.mouse.justPressed()) {
fire.push(new Fireball(x, y, FlxG.mouse.x, FlxG.mouse.y));
}
But when I test it, it only plays the sound, but the fireball doesn't show up. I'm guessing that the fireball is somewhere offstage, but how do I fix it?
If it helps, here's the constructor for Fireball.as:
public function Fireball(x:Number, y:Number, tar_x:Number, tar_y:Number) {
dx = 0;
dy = 0;
target = new FlxPoint(tar_x, tar_y);
super(x, y, artFireball);
shoot();
}
I think you must add them to stage.
if (FlxG.mouse.justPressed()) {
var fireball:Fireball = new Fireball(x, y, FlxG.mouse.x, FlxG.mouse.y);
fire.push(fireball);
// This line needs to be changed if you add the fireball to a group,
// or if you add it to the stage from somewhere else
add(fireball);
}
Let me know if it worked for you.
As stated before, the problem was due to not adding the FlxSprite to the Flixel display tree. But also I would advise you to use FlxObject groups instead of a simple Array.
FlxGroups are way better data structure than arrays. For instance they inherit all the methods from a FlxObject, so you can check for collisions directly against the group, also they have specific methods to handle the collection of objects, such as countDead and countAlive (if you make you of the alive attribute), recycle, getFirstDead and so on.
Check it out, you won't be disappointed. :)

ActionScript Local X And Y Coordinates Of Display Object?

i'm trying to trace the x and y coordinates from within a sprite. i've added a rectangle to the stage:
var rect:Rectangle = new Rectangle(10, 10, 200, 200);
addChild(rect);
rect.x = rect.y = 100;
adding a Mouse_Move event to the rect, i can trace mouseX and mouseY to receive the coordinates of the stage while moving over the rect, but how do i get the local x and y coordinates? so if i mouse over the very top left of the rect sprite, the mouseX and mouseY return 10 as the global coordinates, but how do i make it return 0 and the local coordinates of the sprite?
i assumed localX and localY was what i was looking for, but this doesn't work:
function mouseOverTraceCoords(evt:MouseEvent):void
{
trace(mouseX, mouseY, evt.localX, evt.localY);
}
It depends how you have designed your Rectangle class,
if you have done something like this:
class Rect1 extends Sprite {
public function Rect1(x:Number, y:Number, width:Number, height:Number) {
var g:Graphics = graphics;
g.beginFill(0xff0000, 0.5);
g.drawRect(x, y, width, height);
g.endFill();
}
}
your local coordinate will be at 0,0 but you drawing start at x,y so when you are getting the localx, localY you will obtain x,y and not 0,0.
But if your class is designed as something like that :
class Rect2 extends Sprite {
public function Rect2(x:Number, y:Number, width:Number, height:Number) {
var g:Graphics = graphics;
g.beginFill(0xff0000, 0.5);
g.drawRect(0, 0, width, height);
g.endFill();
this.x = x;
this.y = y;
}
}
then your drawing start at 0,0 and your object is moved at x,y so the localX and localY from the MouseEvent will be ok.
Edit:
To get the local coordinate you can try using getBounds :
function mouseOverTraceCoords(evt:MouseEvent):void {
var dob:DisplayObject = DisplayObject(evt.target);
var bnds:flash.geom.Rectangle = getBounds(dob.parent);
var localX:Number=e.localX - bnds.x + dob.x;
var localY:Number=e.localY - bnds.y + dob.y;
trace(mouseX, mouseY, evt.localX, evt.localY, localX, localY);
}
take a look at globalToLocal
There's no need to do any transformations at all *, your Rectangle will have two properties called mouseX and mouseY which contain the local coordinates of the mouse.
If you're drawing your graphics offset within the rectangle, the coordinate system will not consider this, it's a better idea to offset the entire rectangle instead.
* assuming your Rectangle class is a subclass of DisplayObject, which I'd assume since you've got it on the stage.