Why isn't the child removed from the frame? - actionscript-3

I'm trying to remove a movieclip with removeChild() function. My code is below, but it doesn't work.
addEventListener(Event.ENTER_FRAME, lemons_collide);
function lemons_collide(ev : Event) : void
{
if(currentFrame==1)
{
if(cup2.hitTestObject(lemons))
{
lemons.stopDrag();
lemons.x = 35;
lemons.y = -150;
lemons.gotoAndPlay(1);
if(lemons.currentFrame>=14){
removeChild(lemons);
}
}
}
};

The "currentFrame" check is run directly after the "gotoAndPlay".. so the currentFrame is always "1". You will have to run a separate event listener tracking "ENTER_FRAME" on that object, then have that remove the child once it is on Frame 14.

Related

Action Script 3.0: Stop Drag with hittestobject

how to stop drag(event) the object with hittestobject.. thanks.
object.addEventListener(TouchEvent.TOUCH_BEGIN, drag);
object.addEventListener(TouchEvent.TOUCH_END,drop);
addEventListener(Event.ENTER_FRAME, loop);
function drag(e:TouchEvent):void {
e.target.startTouchDrag(e.touchPointID);
}
function drop(e:TouchEvent):void {
e.target.stopTouchDrag(e.touchPointID);
}
function loop(e:Event):void {
if (object.hitTestObject(collision)) {
//code to stop drag event?
}
}
or is there other way to stop drag event aside from function drop?
sorry for my bad english.
//edited
In the function drop() e.target is the object that currenty processes the event. In the function loop() you also have some objects. It is not clear which of them is dragging but you should call either object.stopTouchDrag() or collision.stopTouchDrag().
UPDATE
There is an argument for both startTouchDrag and stopTouchDrag functions - touchPointID, it is used to determine what touch point (of many) is processed. When stopping the drag, you need to use the same touchPointID which was used for starting it. When calling the stopTouchDrag from a non-event context, you can't know what touch point it should use. So you need to remember it somehow. If your target object is a MovieClip you can just add a dynamic property to it and save the touchPointID there:
function drag(e:TouchEvent):void {
(e.target as MovieClip).touchPointID = e.touchPointID;
e.target.startTouchDrag(e.touchPointID);
}
function loop(e:Event):void {
if (object.hitTestObject(collision)) {
object.stopTouchDrag(object.touchPointID);
}
}

Dragging movie clips in Action Script 3

Hi so recently I have been attempting to Drag a movie clip in AS3 but I'm having some trouble picking up with the hit tests anyone got any ideas? Just to clarify, the issue is that when the movieclips hit the drag test object, they're not executing the gotoframe() function.
initDrag() adds action listeners:
MOUSE_DOWN on the object
MOUSE_UP on the stage so it doesn’t matter if you are off the object
endDrag() removes the action listeners; call this (for each object) before you go to another frame
startADrag()create a rectangle within which the object can be dragged (in this case the stage)
call startDrag() on the object
stopADrag() call stopDrag() on the object from currentObject (but only if currentObject is not null).
var currentObject:MovieClip = null;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
}
}
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
thanks for any advice or answers.
The following code should work as expected. The problem is, as i already stated in my comment, that your calls to hitTestObject(obj) only get executed once, at the very beginning of your application. What you need to do though is to check it constantly.
Think about it, if your calls to hitTestObject-calls only get executed once at the beginning, when you didn't even have a chance to drag one of your objects, it will always return false, right? Because your objects are still in their initial position (outside of the dragtest objecti must assume).
With an event listener for Event.ENTER_FRAME you check it once per frame instead. So even if all the results for hitTestObject are false, it will check them all again on the next frame (if you are currently dragging, controlled through a simple boolean called dragging).
var currentObject:MovieClip = null;
var dragging:Boolean = false;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
addEventListener(Event.ENTER_FRAME, checkForHit);
function checkForHit(e:Event):void{
if(dragging){
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
}
}
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
dragging = true;
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
dragging = false;
}
}

Action Script 3: Problems with gotoAndStop() after a Movie Clip

Upon the click of a button, an animation starts. Then the program directs you to a certain frame when the animation is done.
Is this possible?
So this is what I've got so far: a Movie Clip movQuizIntro and a Button btnBond in Frame 1.
stop()
movQuizIntro.stop()
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz)
btnReg.addEventListener(MouseEvent.CLICK, Registrering)
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
}
}
What is the code and proper syntax you need to write in order to go to frame 2 after the animation is done?
`
stop();
movQuizIntro.stop();
int frameCounter=0;
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz);
btnReg.addEventListener(MouseEvent.CLICK, Registrering);
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
movQuizIntro.addEventListener(EventType.ENTER_FRAME, onEnterFrame);
}
}
// event handler function, runs every enter frame
private function onEnterFrame(event:Event):Void
{
frameCounter++;
if(frameCounter > movQuizIntro.totalFrames)
{
//Place code here because you know the MovieClip finished playings
//Go to desired frame
}
}
`
I wrote this code outside of an editor nor did I get to compile, so the gist is there and may have some minor errors.
NOTE:This is just a quick way of doing this. If you want something more reusable/cleaner then you would want to consider subclassing or alternate Object Oriented tricks.
In button event handler:
function onClick(e:MouseEvent):void{
ANIMATION_MC.addEventListener(Event.EXIT_FRAME, onFromeExit);
}
function onFrameExit(e:Event):void {
if (ANIMATION_MC.currentFrame == SOME_FRAME) {
ANIMATION_MC.removeEventListener(Event.EXIT_FRAME, onFromeExit);
TARGET.gotoAndPlay(NEW_FRAME);
}
}
And you can just use addFrameScript on ANIMATION_MC too.

How to automatically delete Event Listener from an object in AS3

I am working on small flash game. The game contains 20 levels and main menu. The transition between levels is made by deleting every object on the frame and also all event listeners. Then the code adds objects from the next level...
Catching and the removing event listeners is done by this code:
override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
arrListeners.push({type:type, listener:listener});
}
private function clearEvents():void
{
for(var i:Number = 1; i<arrListeners.length; i++){
if(this.hasEventListener(arrListeners[i].type))
{
this.removeEventListener(arrListeners[i].type, arrListeners[i].listener);
}
}
arrListeners = []
}
This code overrides internal addEventListeners and makes every Listener to be added in an array. Second function checks if the EventListeners is still there(not prevoiusly removed) and the just remove every Listener from the array.
This code works fine for EventListeners that are assigned to the stage. However, when an EventListener is assigned directly to an Object then it's not added to the array, so it doesn't get removed automatically later.
I know that when you remove the object, also you remove the Event Listeners assigned to it. But when I add that object again the Listeners run twice. You can freely move through levels, so you can go back and forth. And when you go back I recieve problems. System is overused and is woring slower, because the amount of Event Listeners that are running is doubled.
So, can you modify this code or give me an advice how can I catch EventListeners that are assigned to Object and eventually remove them.
Code:
package
{
Public Class Main extends MovieClip
{
Public function Main()
{
Intro();
}
Private function Intro():void
{
//Constructor contains a lot of addChild and a EventListeners. So I will upload what I think i important for this problem.
Play_btn.addEventListener(MouseEvent.CLICK, clicked);
function clicked (e:MouseEvent):void
{
clearEvents();
clearChild(); // function that removes all children on stage
FirstLevel();
}
}
Private function FirstLevel():void
{
//Also adding children and EventListeners, that affect the gameplay
Next_level_btn.addEventListener(MouseEvent.CLICK, clicked1);
function clicked1 (e:MouseEvent):void
{
clearEvents();
clearChild();
SecondLevel();
}
Main_Menu_btn.addEventListener(MouseEvent.CLICK, clicked1);
function clicked1 (e:MouseEvent):void
{
clearEvents();
clearChild();
Intro();
}
}
And so on for the next 20 levels.
Thanks in advice.
Arrays indices start from 0, clearEvents should be :
private function clearEvents():void
{
for(var i:int= 0; i<arrListeners.length; i++){
if(this.hasEventListener(arrListeners[i].type))
{
this.removeEventListener(arrListeners[i].type, arrListeners[i].listener);
}
}
arrListeners = []
}
Not sure if that will fix your problem though. If you have event listeners that are created when you add new objects you should remove those listeners when the object is destroyed/removed.
Removing an object (removeChild(object)) does NOT automatically remove it's event listeners. You would need to do that yourself. Something like this could work:
in your class constructor:
super.addEventListener(Event.ADDED_TO_STAGE,addedToStage,false,0,true); //only if you want the listeners added back again the next time this object is added to the stage eg. addChild(this)
super.addEventListener(Event.REMOVED_FROM_STAGE,removedFromStage,false,0,true);
The handlers:
//this runs whenever the object is added to the display list
//if you don't want the listeners re-added, remove this function.
private function addedToStage(e:Event):void {
for(var i:int=0; i<arrListeners.length; i++){
super.addEventListener(arrListeners[i].type, arrListeners[i].listener, arrListeners[i].useCapture, arrListeners[i].priority, arrListeners[i].useWeakReference);
}
}
//this runs whenever the object is removed from the display list
private function removedFromStage(e:Event):void {
for(var i:int=0; i<arrListeners.length; i++){
super.removedEventListener(arrListeners[i].type, arrListeners[i].listener, arrListeners[i].useCapture);
}
//OR if you want the listeners gone forever, use your clearEvents() method instead of the for loop above
}
This would make your listeners stop listening when the item is removed from the display list, and re-add them when added. You'd have to modify your array to include the other listener information like capture phase and weakReference. If you don't want them added again, just call your clearEvents() in the removedFromStage handler and take out the addedToStage listener/handler altogether.
This is assuming that the code you posted (and my additions) is the base-class of all the object you want it applied to.

Click event outside MovieClip in AS3

Is there any way to detect if the user click outside a MovieClip?
For instance, I need to detect it to close a previously opened menu (like Menu bar style: File, Edition, Tools, Help, etc).
How can I detect this kind of event? Thanks!
Add a listener to stage and check if stage is the target of the event.
Example of code here:
http://wonderfl.net/c/eFao
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class FlashTest extends Sprite
{
private var _menu : Sprite;
public function FlashTest()
{
_menu = new Sprite();
_menu.x = 100;
_menu.y = 100;
_menu.alpha = 0.5;
with(_menu.graphics)
{
beginFill(0xFF0000, 1);
drawRect(0, 0, 300, 300);
endFill();
}
addChild(_menu);
_menu.addEventListener(MouseEvent.CLICK, onClickHandler);
stage.addEventListener(MouseEvent.CLICK, onClickHandler);
}
private function onClickHandler(event : MouseEvent) : void
{
switch(event.target)
{
case _menu:
_menu.alpha = 0.5;
break;
case stage:
_menu.alpha = 1;
break;
}
}
}
}
You can add a listener to the click event of the root element:
MovieClip(root).addEventListener(MouseEvent.CLICK, clickObject);
then in the function clickObject, you can check to see what you are clicking.
function clickObject(e:Event):void
{
var hoverArray:Array = MovieClip(root).getObjectsUnderPoint(new Point(stage.mouseX, stage.mouseY));
var hoverOverObject:* = hoverArray[hoverArray.length - 1];
}
hoverOverObject references the element that you are clicking on. Often this will be the shape within the movie clip, so you'll need to look at it's parent then compare it to your movie clip. If the click wasn't on the drop down movie clip, trigger the close.
var container:MovieClip = new MovieClip();
var mc:MovieClip = new MovieClip();
with(mc.graphics){
beginFill(0xff0000,1);
drawCircle(0,0,30);
endFill();
}
mc.name = "my_mc";
container.addChild(mc);
addChild(container);
stage.addEventListener(MouseEvent.CLICK, action);
function action (e:MouseEvent):void
{
if(e.target.name != "my_mc"){
if(container.numChildren != 0)
{
container.removeChild(container.getChildByName("my_mc"));
}
}
}
Use capture phase:
button.addEventListener(MouseEvent.CLICK, button_mouseClickHandler);
button.stage.addEventListener(MouseEvent.CLICK, stage_mouseClickHandler, true);
//...
private function button_mouseClickHandler(event:MouseEvent):void
{
trace("Button CLICK");
}
private function stage_mouseClickHandler(event:MouseEvent):void
{
if (event.target == button)
return;
trace("Button CLICK_OUTSIDE");
}
Note that using stopPropagation() is good for one object, but failed for several. This approach works good for me.
Use a stage and a sprite (menu) click listener with the sprite listener executing first and apply the stopPropagation() method to the click handler of the sprite. Like this:
menu.addEventListener(MouseEvent.CLICK, handleMenuClick);
stage.addEventListener(MouseEvent.CLICK, handleStageClick);
private function handleMenuClick(e:MouseEvent):void{
// stop the event from propagating up to the stage
// so handleStageClick is never executed.
e.stopPropagation();
// note that stopPropagation() still allows the event
// to propagate to all children so if there are children
// within the menu overlay that need to respond to click
// events that still works.
}
private function handleStageClick(e:MouseEvent):void{
// put hide or destroy code here
}
The idea is that a mouse click anywhere creates a single MouseEvent.CLICK event that bubbles from the stage, down through all children to the target, then back up through the parents of the target to the stage. Here we interrupt this cycle when the target is the menu overlay by not allowing the event to propagate back up to the parent stage, ensuring that the handleStageClick() method is never invoked. The nice thing about this approach is that it is completely general. The stage can have many children underneath the overlay and the overlay can have its own children that can respond to clicks and it all works.