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);
}
}
Related
I have action
MC1.addEventListener (MouseEvent.MOUSE_OVER, MC1_over);
can a use other MC instead of Mouse?
In other words, when MC2 will be over MC1, my action will start. How do that?
Thanks for help
You'll have to check for intersection. It's called HitTesting and there are several ways to approach this. But first - it won't be an Event anymore, you'll have to check for an intersection in every frame. So first of all, we need to create a new Event.ENTER_FRAME listener.
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void
{
//Your code will go here
}
Second, we check our objects for an intersection of their boudary rectangles. It's ok if you have sqare or rectangular movieclips, if your MCs are more complex (two circles for example) you'll have to use other ways of getting this intersection.
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void
{
if(MC1.getRect(this).intersects(MC2.getRect(this)))
{
//Two movieclips are intersecting
}
}
Third, as long as this condition will be true as long as your MCs are intersecting, we need to define a flag that will tell us if we've already done something we wanted to do.
var alreadyHandled:Boolean = false;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void
{
if(MC1.getRect(this).intersects(MC2.getRect(this)))
{
if(!alreadyHandled)
{
doSomething();
alreadyHandled = true;
}
}
else
{
//When our movieclips are apart again, we reset our helping variable
alreadyHandled = false;
}
}
function doSomething():void
{
//We do what we want to do if our MCs are intersecting
}
If you want to do something continiously, when your movieclips are intersecting, just ignore that helping flag thing.
And by the way, I suggest you to start names your variables with a lowercase letter. In AS3 only Classes and Interfaces have names that start with a capital letter.
Thank you.
Everything works great when I do this on new as3 file.
But i need to use this in class document
When i use
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void
{
if(MC1.getRect(this).intersects(MC2.getRect(this)))
{
trace("intersects")
}
}
Erron#1034: cannot convert type global#23b3a0d1 on
flash.display.DisplayObject.
Perhaps You known where is problem?
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.
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.
I have a function that recognizes the ESC key being pressed. At which point, I want to stop dragging all items.
I"ve tried this.stopDrag() but it wont override the MOUSE_DOWN event.
It there a way to force it to "drop" the item being dragged?
Thanks
stage.addEventListener(KeyboardEvent.KEY_DOWN, escapeKeyDown);
function escapeKeyDown(event : KeyboardEvent):void {
if (event.keyCode == 27) {
trace("ESC");
this.stopDrag();
}
}
Make a global array of all your dragging DisplayObjects:
static var CURRENT_DRAGGING_ITEMS:Array = [];
Then whenever you call startDrag on anything, add it to the array.
function onMouseDown(event:MouseEvent):void
{
event.target.startDrag();
CURRENT_DRAGGING_ITEMS.push(event.target);
}
Then when you hit ESC, just loop through the array, calling stopDrag on all items, and removing them from the array.
function escapeKeyDown(event:KeyboardEvent):void
{
event.target.stopDrag();
var targetIndex:uint = CURRENT_DRAGGING_ITEMS.indexOf(event.target);
CURRENT_DRAGGING_ITEMS.splice(targetIndex, 1);
}
Make sure you also remove the dragging item from the array when you call stopDrag on it from anywhere else.
I just came across a curious scenario where I want to use removeEventListener() within a function that doesn't have a name. By this I mean, I've created the function within addEventListener(), instead of making reference to one:
addEventListener(
Event.ENTER_FRAME,
function(e:Event):void
{
if(getTimer() > 8000)
{
// removeEventListener(Event.ENTER_FRAME, <<this function>>);
// Other stuff
}
}
);
Is it possible to make a reference to the current function (ie the function I'm working within)? Or do I just need to structure the above the standard way?
Please not that I am fully aware that you can use many of the standardized methods available to achieve the above, it was purely an example snippet.
There are two options, you can either give it a name (and there are three ways to do that) or you can use arguments.callee.
In the case of the former, the three ways to name a function in AS3:
class Foo
{
// class (static or member) level
public function bar():void
{
// use a variable (technically, this function is anonymous, but we can
// still use the variable to reference the function itself.
var inVariable:Function = function():void
{
// declare it in a local scope
function local():void
{
}
}
}
}
To use a named function:
function callback(e:Event):void {
trace("tick");
removeEventListener(Event.ENTER_FRAME, callback);
}
addEventListener(Event.ENTER_FRAME, callback);
To use arguments.callee:
addEventListener(
Event.ENTER_FRAME,
function(e:Event):void
{
if(getTimer() > 8000)
{
// I get superstitious and I use a local variable.
var callee:Function = arguments.callee
removeEventListener(event.type, callee);
// Other stuff
}
}
);
You just need to give it a name, eg:
addEventListener(Event.ENTER_FRAME, function callback(e:Event):void {
trace("tick");
removeEventListener(Event.ENTER_FRAME, callback);
});
In this example "tick" will only be traced one time.
Using anonymous functions in actionscript is a bad choice, since it is really slow. Also they hardly can be garbage collected. It is also good to mention that this will only work if when the listener has been called (yes, in case of an enter_frame it will), so outside the anonymous function other functions are unable to remove the listener. Beside that, is is also a actionscript-convention to use separate functions, which makes your code more readable and it will take only a few extra chars (just to name it).
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void
{
if(getTimer() > 8000)
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
If you want a more easy way to remove the event listener; you could detect the type and the function callee of the listener from the target object. However I think this also makes the code a bit less readable.
e.target.removeEventListener(e.type, arguments.callee);
sources
http://jacksondunstan.com/articles/413
http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html