Depth related problem for actionscript 3 [duplicate] - actionscript-3

This question already has an answer here:
How do I set the depth of images in ActionScript?
(1 answer)
Closed 2 years ago.
I'm having trouble managing the depths of my movie clips.
I've got a startDrag() function and a stopDrag() function.
Whenever I rollover another MC, I want the depth of that object to change to 1+ the object it rolled over.(I apologize if my English is poor)
Can anyone give me a nudge in the right direction?
EDIT: This is as far as I got, but cIndex returns the depth of the object that is currently being dragged; not the object it's hovering over... Is there a way to get that depth?
mc.addEventListener(MouseEvent.MOUSE_OVER, objectFront);
function objectFront(e:Event):void{
cIndex_t3 = getChildIndex(DisplayObject(e.currentTarget))
trace("ROLLOBJ: " + e.target.name + " " + cIndex_t3);
addChild(DisplayObject(e.currentTarget));
}

If you actually want to object to be +1 the object it rolled over then use getChildIndex() on the object dragged over and use setChildIndex() on the dragged object.
However if you simply want the dragged object on top then the easiest way is to simply use addChild() on it. You can use addChild() even if the object is already a child, and that'll bump it to the top of the stack.

You should use getChildIndex and setChildIndex for depth related operations of display objects.
mc.addEventListener(MouseEvent.MOUSE_OVER, objectFront);
function objectFront(e:Event):void
{
//Set display object child index on top in container
e.target.parent.setChildIndex(e.target as MovieClip, e.target.parent.numChildren - 1);
}

Related

Object changing layer when going between frames?

I have a child of an object that stays on the scene when the frame changes. So I gotoAndStop(2); and the object is still there. However, when I come back to frame one. The object is on the lowest layer, despite the fact that I originally added it using addChildAt(character, 1); I think this adds it to the first layer? Anyone know how I can fix this issue of keeping a movieclip object on the top layer despite changing frames? Thanks.
In AS3/Flash, the bottom most layer is 0. So doing addChildAt(character, 1) would make your character the second to the bottom layer. addChildAt(character, 0) would make it the very bottom/back layer.
If you want to make it the top most layer, you do any one of the following:
addChild(character); //this is the shortest amount of code
addChildAt(character, numChildren-1); //the is exactly the same as above
setChildIndex(character, numChildren-1); //this is also the same but requires the character already be present on the display list
The latter (setChildIndex) may be preferred IF your character originates on the timeline (eg not created through code). The reason being, if you change through code the parentage of something created on the timeline, it will not go away when no longer present on the timeline.
If you want a way to force something to always be on top, you can do something along these lines:
this.addEventListener(Event.ADDED, bringToTop);
function bringToTop(e:Event):void {
setChildIndex(character, numChildren-1);
}
Doing that, makes it so whenever any other object is added as a child of this, it will set the character to the very top most layer/z-index.

nested collision starling as3

I am using starling and tweenMax frameworks in my project.
The trouble I am running into is this:
For the purpose of animating along different paths, I am using tweenmax.
There is one _leaderEnemy that animates along a path and I am pushing several other _shooterEnemy (they are of the same class) into it.
public function createEnemies(enemyNo:int, path:Array, offset:int):void
{
for(var i:uint=1;i<=enemyNo;i++){
if (i==1){
_leaderCount++;
_leaderEnemy = new ShooterEnemy();
_leaderEnemy.x=600;
_leaderEnemy.y=300;
_leaderEnemy.name="_shooterEnemy"+_leaderCount;
this.addChild(_leaderEnemy);
leaderEnemyArray.push(_leaderEnemy);
}
else
{
_leaderCount++;
_shooterEnemy= new ShooterEnemy();
_shooterEnemy.x=0;
_shooterEnemy.y=(offset*(i-1));
_shooterEnemy.name="_shooterEnemy"+_leaderCount;
trace("no: "+_shooterEnemy.name);
leaderEnemyArray.push(_shooterEnemy);
_leaderEnemy.addChild(_shooterEnemy);
}
}
Now I want to check for collision using starling between each of the _leaderEnemy and the _shooterEnemy inside it with _shooterHero.
Running this array successfully checks collision with the whole group i.e. _leaderEnemy but not the individual ones inside it.
Technically, I should be able to do this just by:
var Track:Object;
for(var i:uint=0;i<leaderEnemyArray.length;i++) {
Track=leaderEnemyArray[i];
if (Track.bounds.intersects(_shooterHero.bounds)){
Track.rotation=deg2rad(70);
}
}
It may be something stupid I am doing. But I have not been able to solve this.
Any help on this would be appreciated.
Some other questions I have:
Can I check for collision with _shooterHero from inside the _shooterEnemy's class?
I have tried:
if (this.bounds.intersects(stage.getChildByName("_hero"))){
}
although it did not work.
Can I check for collision of one Enemy with everything on stage, so I can assign individual functions for his each contact?
For example: hit with hero: die; hit with another enemy: turn around
If you need more info, I will be happy to provide it.
Thank You.
Can I check for collision of one Enemy with everything on stage, so I can assign individual functions for his each contact? For example: hit with hero: die; hit with another enemy: turn around
Of course you can. You should! This is approximatively how collision engines works.
Running this array successfully checks collision with the whole group i.e. _leaderEnemy but not the individual ones inside it.
Nope. It won't work. Because the bounds property use the parent coordinates.
Meaning you can intersect each child display (of same container) with each other.
But you shouldn't intersect a child display of A with a child display of B.
Except if you convert every bounds coordinates (which are local) to global.
http://doc.starling-framework.org/core/starling/display/DisplayObject.html#localToGlobal()
Using Track.bounds.intersects is one way of checking collosions. Another would be to use hitTest method of starling.displayDisplayObject
You could also check the distance of your hero and other enemies calculated by a pythagorean theorem type calculation.
Are you checking enemies against each other? If you have many enemies you might want to look into "flocking" algorithms. Keith Petes covers this subject nicely in his book Advanced Actionscript Animation.

AS3 Custom Depth Control

I am trying to create a way of controlling movieclip depths, which movieclip is show above another, so that I can set the depth of a movieclip to any number and they will be displayed with higher values above lower values.
I was thinking of creating a MovieClipDepth class that extends MovieClip with the added property depth, and a Container class that extends DisplayObjectContainer which all objects will be placed inside of.
The Container class will override the addChild method to update the child display order when a child is added.
What I need help with is how do I reorder the children according to
their depth value?
As you can read in the comment below your question, there are several methods for this.
But actually, what you asked "set the depth of a movieclip to any number" can't really be done in AS3. If i'm correct, you could do this in AS2, so...
... how was it ...
_root.createEmptyMovieClip("mc", -1000);
or
_root.createEmptyMovieClip("mc1", 1);
_root.createEmptyMovieClip("mc2", 10);
worked, but does not work in AS3. In AS3 depth starts with 0 and you can't force a DisplayObject to sit on a level what is not continous from zero.
So the depths' of 3 movieclips in a container is only possible with these values: 0, 1, 2.
Depth can't be a negative number for example.
Now, if you want to build a custom depth manager, you can do that, but you have to consider these facts.
So to say, you could create virtual depths.
So I guess, you could override the addChildAt method for example. At the moment, if you would give a wrong number: negative, or higher then the number of children, flash would give back the error:
RangeError: Error #2006: The supplied index is out of bounds.
So mc.addChildAt(newchild, -1000) gives an arror.
But with overriding the method, you could make a trick, so you could store the depths in an array. You could store any numbers and then transform that order for the needs of AS3.
Like pairing the depths with the added children, sorting the array by the depths, then manage the children according to the order.
If you have more questions, feel free to ask, hope this gets you closer to the solution.
I suggest you take a look at this tutorial :
A Tour of Depths Management Methods on the website http://www.flashandmath.com/. I presume you not a newbie .
The link is this:
http://www.flashandmath.com/intermediate/depths/index.html

localToGlobal/globalToLocal AS3 confusion

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.

AS3 - Using Matrix3D objects for reordering display

I'm working with about 20 objects that are moving around in 3D space. Adobe recommends "Using Matrix3D objects for reordering display":
Use the getRelativeMatrix3D() method of the Transform object to get the relative z-axes of the child 3D display objects.
Use the removeChild() method to remove the objects from the display list.
Sort the display objects based on their relative z-axis values.
Use the addChild() method to add the children back to the display list in reverse order.
Great. That's fine if the objects aren't moving. But what if there are animations happening and one object comes in front of another in z-space? The objects are displayed accoring to the position in the display list, not according to their z-order. How can you make objects respect z-order while animating (make object A appear in front of object B if object A's z-value becomes smaller than object B)? Obviously you can't clear the display list during an animation.
It's practically the same as adobe's docs says... and it works perfectly for moving objects.
The simplest way, so you have some code reference, and given you have all of your 3d objects in an array, would go something like this:
function zSort(objects:Array) {
objects.sortOn("z", Array.DESCENDING | Array.NUMERIC); // sort the array on the "z" property
for each(var clip:DisplayObject in objects) { //loop the array and add the childs in the corrected order...
addChild(clip);
}
}