remove or destroy child completely - actionscript-3

I've got a child named "viseur" that appears on a particular scene and replace my actual cursor.
When the event "removeViseur" is called, I would like to completely remove the child "viseur" (and I'll use my previous cursor).
I did that :
stage.addEventListener("functionCalled", removeViseur, false, 0, true);
public function removeViseur(e:Event):void{
trace("removeViseur");
viseur.visible = false;
viseur.parent.removeChild(viseur);
viseur = null;
}
The child "viseur" is no longer here, but if do Alt+tab or changing window and came back, the child "viseur" come back...
Do you know how I can destroy it completely ? (I don't need it after this function is called)
Thx,
EDIT
Here is more of my code.
public static var viseur:Viseur;
var lookCocoDessous:Boolean = thisBack == "cocotierDessous";
if (lookCocoDessous) {
viseur = new Viseur(stage);
stage.addChild(viseur);
viseur.visible = true;
stage.addEventListener("functionCalled", removeViseur, false, 0, true);
public function removeViseur(e:Event):void{
trace("removeViseur");
viseur.visible = false;
viseur.parent.removeChild(viseur);
viseur = null;
}
And "viseur" has is own class like that
viseur.as :
public class Viseur extends MovieClip
{
private var engine:Engine;
private var stageRef:Stage;
private var p:Point = new Point();
public function Viseur(stageRef:Stage)
{
Mouse.hide(); //make the mouse disappear
mouseEnabled = false; //don't let our cursor block anything
mouseChildren = false;
this.stageRef = stageRef;
x = stageRef.mouseX;
y = stageRef.mouseY;
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
stageRef.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler, false, 0, true);
stageRef.addEventListener(Event.ADDED, updateStack, false, 0, true);
}
private function updateStack(e:Event) : void
{
stageRef.addChild(this);
}
private function mouseLeaveHandler(e:Event) : void
{
visible = false;
Mouse.show(); //in case of right click
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler, false, 0, true);
}
private function mouseReturnHandler(e:Event) : void
{
visible = true;
Mouse.hide(); //in case of right click
removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);
}
private function updateMouse(e:MouseEvent) : void
{
x = stageRef.mouseX;
y = stageRef.mouseY;
e.updateAfterEvent();
}
}
}
}

Viseur is adding itself to the stage whenever Event.ADDED fires. This fires whenever anything is added to the stage (not just Viseur). You've also made Viseur a static property, thus ensuring it doesn't disappear from memory.
To be succinct: add Viseur only once, and from outside of itself (thereby removing the need to pass a stage reference). Be aware that once a DisplayObject is parented, it automatically gains stage & root properties which you can reference for mouseX and mouseY.
That said, if you're trying to replace the mouse cursor, I highly recommend taking a different tact: Native cursors.
See http://inflagrantedelicto.memoryspiral.com/2012/07/as3-quickie-native-mouse-cursors/

Related

Check when a part of the MovieClip leaves the Stage

I'm creating a Drag and Drop game using AS3, i want to check when a apart of a Movieclip is outside the screen to move the View behind and let the user choose where to drop it.
I cant' test if the MovieClip credentials are bigger that the stage (scaleMode = NO_SCALE) Width/Height, because there is a part of the stage that it's hidden behind the browser window.
It's the same aspect as MOUSE_LEAVE just this time it has to be for MovieClips, i tried to see the code behind MOUSE_LEAVE but i couldn't reach it.
Thank You.
MAIN CLASS
[SWF(width='800', height='800',backgroundColor='#CC99FF', frameRate='60')]
public class DragTest extends Sprite
{
public function DragTest()
{
addChild(new World(this));
this.stage.scaleMode = "noScale";
this.stage.align = "TL";
this.graphics.lineStyle(5,0x555555,0.5);
this.graphics.drawRect(0,0,800,800);
}
}
WORLD CLASS
public class World extends Container // Container from my SWC
{
private var _display:Sprite;
private var _dragPt:Point;
private var _dragedObject:MovieClip;
public function World(display:Sprite)
{
super();
_display = display;
myMC.addEventListener(MouseEvent.MOUSE_DOWN, onPickUp, false, 0, true );
display.stage.addEventListener(MouseEvent.MOUSE_UP, onDrop, false, 0, true );
display.stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave, false, 0, true );
}
protected function onMouseLeave(event:Event):void
{
trace("Mouse Is Leaving The Stage");
}
protected function onDrop(e:MouseEvent):void
{
_display.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMoveObject);
}
private function onPickUp(e:MouseEvent)
{
_dragedObject = e.currentTarget as MovieClip;
_display.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMoveObject, false, 0, true);
}
protected function onMoveObject(e:MouseEvent):void
{
var point:Point = new Point(_display.stage.mouseX, _display.stage.mouseY);
(_dragedObject as MovieClip).x = point.x;
(_dragedObject as MovieClip).y = point.y;
}
}
Here is an Example :
Simple Code
The easiest approach would probably be to use getBounds(stage) and compare with stageWidth and stageHeight:
var bounds:Rectangle = _draggedObject.getBounds(stage);
if (bounds.left < 0) {
// left part of object is off-screen
} else if (bounds.right > stage.stageWidth) {
// right part of object is off-screen
}
if (bounds.top < 0) {
// top part of object is offscreen
} else if (bounds.bottom > stage.stageHeight) {
// bottom part of object is off-screen
}
You could move the display in each of these cases.
You can try to create an invisible zone that's a little bit smaller than your stage.
So you can add the MOUSE_LEAVE event to the zone, and when your mouse leaves that zone, you can do what you want.
Check the example here.
In response to Aaron Beall's response:
For a more interesting effect, if you want to wait until the movie clip is completely off stage, you can swap the boundaries you check on the object
var bounds:Rectangle = object.getBounds(stage);
if (bounds.right < 0) {
// do thing
} else if (bounds.left > stage.stageWidth) {
// do thing
}
if (bounds.bottom < 0) {
// do thing
} else if (bounds.top > stage.stageHeight) {
// do thing
}
Make sure you have import flash.geom.Rectangle; imported if this is inside a class.

How to change cursor on Roll Over event

I'm making a point and click game in AS3 with flash.
I've changed the skin of my cursor by creating a new class "Souris". It's working just fine. Now I'm trying to change the skin of the cursor when it's on an object on the scene.
I've read that the MouseEvent.ROLL_OVER is the good method but I can't figure out how to do it...
I've got my Souris class like that :
public class Souris extends MovieClip
{
private var engine:Engine;
private var stageRef:Stage;
private var p:Point = new Point();
public function Souris(stageRef:Stage)
{
Mouse.hide(); //make the mouse disappear
mouseEnabled = false; //don't let our cursor block anything
mouseChildren = false;
this.stageRef = stageRef;
x = stageRef.mouseX;
y = stageRef.mouseY;
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, updateMouse, false, 0, true);
stageRef.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler, false, 0, true);
stageRef.addEventListener(Event.ADDED, updateStack, false, 0, true);
stageRef.addEventListener(MouseEvent.ROLL_OVER,hover);
}
private function updateStack(e:Event) : void
{
stageRef.addChild(this);
}
private function hover(e:MouseEvent):void {
souris.visible = false;
}
private function mouseLeaveHandler(e:Event) : void
{
visible = false;
Mouse.show(); //in case of right click
stageRef.addEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler, false, 0, true);
}
private function mouseReturnHandler(e:Event) : void
{
visible = true;
Mouse.hide(); //in case of right click
removeEventListener(MouseEvent.MOUSE_MOVE, mouseReturnHandler);
}
private function updateMouse(e:MouseEvent) : void
{
x = stageRef.mouseX;
y = stageRef.mouseY;
e.updateAfterEvent();
}
}
}
}
In my main class (Engine class) I've got :
private var souris:Souris;
public function Engine(){
souris = new Souris(stage);
stage.addChild(souris);
}
private function startGame(e:Event):void{
....
..
I've tried to put in the "Souris" class
stageRef.addEventListener(MouseEvent.ROLL_OVER,hover);
private function hover(e:MouseEvent):void {
Engine.souris.visible = false;
handCursor.visible = true ;
}
But it seems wrong...
I don't know what to put in my hover function. (I've got the "handCursor" in my library).
Thank you very much for your help!
If you have "handCursor" in your library, then you need to assign a class to it, like 'HandCursor'. I advise that classes start with an uppercase letter.
So your code would need to create a new instance of it then show it, like
var handCursor:HandCursor = new HandCursor; handCursor.visible = false;
handCursor.visible = false; makes it not visible, then to make it visible, you would:
handCursor.visible = true;
Also, handCursor is a local variable if put in a function, to make it global to use in all functions, you would need to put it at the beginning of your Class.
Also, are you getting any errors? If so, please share them.

Drag and Drop allow only one object per target

I'm sure this is simple but I have the drag and drop code that works wonderfully...however, it allows me to drop muliple objects per target. What I want is to allow only one object per target and I've looked and can't seem to find how to test to see if an object had already been dropt. Here's the code I have:
package com {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import com.greensock.*;
public class DraggableObject extends MovieClip
{
protected var origPos:Point;
public function DraggableObject()
{
origPos = new Point(x, y);
buttonMode = true; // changes cursor to hand
addEventListener(MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent): void
{
parent.addChild(this); // adds object to the top of the display list to keep the object on top
startDrag(); // built in Flash method
stage.addEventListener(MouseEvent.MOUSE_UP, stageUp);
var upPosX = x + 5;
var upPosY = y - 5;
TweenMax.to(this, .2, {dropShadowFilter:{color:0x666666, alpha:1, blurX:12, blurY:12, distance:12}});
TweenLite.to(this, .2, {x: upPosX, y: upPosY});
mouseEnabled = false;
}
protected function stageUp (event:MouseEvent): void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, stageUp); // good coding
stopDrag(); // built in Flash method
TweenMax.to(this, .5, {dropShadowFilter:{color:0x666666, alpha:0, blurX:12, blurY:12, distance:12}});
if (dropTarget.parent.name == "root1"){
returnToOrigPos();
}
else if(dropTarget)// dropTarget is a built in property this means if dropTarget != null
{
trace("dropt on "+dropTarget.parent.name);
x = dropTarget.parent.x;
y = dropTarget.parent.y;
//buttonMode = false; //only use these to keep the user's selection...can't change if these are active.
//removeEventListener(MouseEvent.MOUSE_DOWN, down);
}
mouseEnabled = true;
}
protected function returnToOrigPos(): void
{
x = origPos.x;
y = origPos.y;
}
}
I was thinking that hitTestObject or dropTarget would work but can't figure out how to use them.
Thanks for any help!
Mike
Add a public property (eg: _hasDroppedObject) to whatever kind of object you're dropping objects into and set it to true when an object is dropped into it:
dropTarget.hasDroppedObject = true;
Then change your "if (dropTarget.parent.name == "root1")" line to:
if (dropTarget.parent.name == "root1" || dropTarget.hasDroppedObject) {
(This assumes you have access to the drop-receiving Class).

Register some properties in event handling

I want to show several images to my application
sourceAudioFile =(event.target as File);
sourceAudioFile.data;
var myLoader:Loader = new Loader();
var url :URLRequest = new URLRequest("file:///" + sourceAudioFile.nativePath);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
myLoader.load(url);
Registration Listener
private function onImageLoaded(e:Event):void
{
var image : Bitmap= new Bitmap(e.target.content.bitmapData);
image.scaleX = 0.5 ;
image.scaleY = 0.5 ;
}
Is there any way by which i can add some custom values to Event.COMPLETE to know what type of image is being loaded.
like e.imageName , e.noOfImage which i can access in complete handler & provide values to it when i register this event.
Thanks in advance
Yes you can, try registering event like:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event){
dispatchEvent(new CustomEvent(CustomEvent.COMPLETE, "<imageType>"));
}, false, 0, true);
And Add new Class, extending the Event class:
public class CustomEvent extends Event {
public static const COMPLETE:String = "CustomEventComplete";
public var imageType:String = "";
public function CustomEvent(type:String, imageType:String = "", bubbles:Boolean = false, cancelable:Boolean = false){
super(type, bubbles, cancelable);
this.imageType = imageType;
}
override public function clone():Event {
return new CustomEvent(type, customTarget, bubbles, cancelable);
}
}
Now you can register for CustomEvent.COMPLETE & get the image type in the listener.
You can find out what ahs been loaded by checking LoaderInfo's url property
private function onImageLoaded(e:Event):void
{
var cli:LoaderInfo = e.target as LoaderInfo;//you added listener to the contentLoaderInfo property
trace(cli.url);//url of the media being loaded
//do something with it
}
also in this SO question you can get more sophisticated asnwer to your problem:)
pass arguments to event listener
Yes, there's a simple way:
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded(imageName, noOfImage));
myLoader.load(url);
function onImageLoaded(imageName:String, noOfImage:int):Function {
return function(e:Event):void {
// Respective "e", "imageName" and "noOfImage" are available for you here.
}
}
If you need to remove it later, change the first line to:
var functionOnImageLoaded:Function = onImageLoaded(imageName, noOfImage);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, functionOnImageLoaded);
Then later just do it like this:
myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, functionOnImageLoaded);
I've answered this before. See it here.

AS3 Mouse Over Change Image

Currently I'm trying to change image loaded in a sprite with mouseover event and change it back with mouseout. But it's not working correctly, am i missing something?
public class Tab extends Sprite
{
var imageLoader:Loader = new Loader();
var TabSprite:Sprite = new Sprite();
var SkinImages:Array = [Skin.TAB_ACTIVE,Skin.TAB_DISABLED,Skin.TAB_HOVER,Skin.TAB_VIEW];
public function Tab()
{
for each (var Image:String in SkinImages){
imageLoader.load(new URLRequest(Image));
}
TabSprite.buttonMode = true;
addChild(TabSprite);
TabSprite.addChild(imageLoader);
TabSprite.addEventListener(MouseEvent.MOUSE_OVER, onTabHover);
}
private function onTabHover(e:MouseEvent){
trace("HOVER");
TabSprite.removeEventListener(MouseEvent.MOUSE_OVER, onTabHover);
imageLoader.load(new URLRequest(Skin.TAB_HOVER));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OUT, onTabOut);
});
}
private function onTabOut(e:MouseEvent){
trace("OUT");
TabSprite.removeEventListener(MouseEvent.MOUSE_OUT, onTabOut);
imageLoader.load(new URLRequest(Skin.TAB_VIEW));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OVER, onTabHover);
});
}
}
You shouldn't nest listeners that way. Just add two in the constructor:
TabSprite.addEventListener(MouseEvent.ROLL_OVER, onTabHover);
TabSprite.addEventListener(MouseEvent.ROLL_OUT, onTabOut);
Note changing MOUSE_OVER to ROLL_OVER it's better in most cases. You shouldn't also load images at every mouse event. Preload them, and then use. Also using anonymous functions in listeners is bad practice as you are not able to remove that listener:
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
TabSprite.addEventListener(MouseEvent.MOUSE_OUT, onTabOut);
});
And in fact you are not removing it - this is bad.
for each (var Image:String in SkinImages){
imageLoader.load(new URLRequest(Image));
}
I doubt it works, I think you cannot load many images at once by using one loader.
Try this:
public class Tab extends Sprite
{
var imageOverLoader:Loader = new Loader();
var imageOutLoader:Loader = new Loader();
var TabSprite:Sprite = new Sprite();
var SkinImages:Array = Skin.TAB_ACTIVE,Skin.TAB_DISABLED,Skin.TAB_HOVER,Skin.TAB_VIEW];
public function Tab()
{
TabSprite.buttonMode = true;
this.addChild(TabSprite); // you also need to add as a Child "Tab" object in the Main Class
imageOutLoader.load(new URLRequest(Skin.TAB_VIEW));
imageOverLoader.load(new URLRequest(Skin.TAB_HOVER));
TabSprite.addChild(imageOutLoader);
TabSprite.addEventListener(MouseEvent.ROLL_OVER, onTabHover);
TabSprite.addEventListener(MouseEvent.ROLL_OUT, onTabOut);
}
private function onTabHover(e:MouseEvent){
TabSprite.removeChild(imageOutLoader);
TabSprite.addChild(imageOverLoader);
trace("HOVER");
}
private function onTabOut(e:MouseEvent){
TabSprite.removeChild(imageOverLoader);
TabSprite.addChild(imageOutLoader);
trace("OUT");
}
}
Try this.