Touch events in game object - actionscript-3

In my Starling game, the player sprite is controlled by clicking the screen where you want to go. Since (AFAIK) you can't have touch events that happen outside a sprite activate handlers in the sprite, I put the handlers in the game object. Here's a basic idea of how it goes:
To create my listener, I do this within my game object:
this.addEventListener(TouchEvent.TOUCH, onTouch);
But onTouch is never called (I even tried putting a trace() in there).
Am I missing something here?

Well, you can make events that happen outside of a sprite to trigger the sprite's handlers, for this, you attach listeners not to the sprite, but to some other object, usually stage. Check if the stage is available, though. The best way to handle stage present is a listener to ADDED_TO_STAGE event. You put that into your handler object's constructor, and put all stage-aware code into that listener.
public function Handler() {
if (stage) init(null);
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point. This is where should stage-aware code start
stage.addEventListener(TouchEvent.TOUCH, onTouch);
// at this point stage is populated and valid, thus we can use stage reference
// without fear of null pointer.
}

Related

Flash AS3: How can I get functions to exit the game loop?

I am working on a Flash project with multiple scenes. I use the function:
function gameloop(e:Event) {
to add my functions in to one scene, but when switching the scene I am rained on with errors because the objects used in the other scene are no longer on screen. Is there an opposite to the code I pasted here to take functions out of the game loop for my other scenes?
function gameloop(e:Event) {
if(currentFrame != 2){
return;
}
}
Check currentFrame in the loop.
I'm assuming the way you're implementing gameLoop is via an Event.ENTER_FRAME listener.
If this is the case, then you simply need to remove the event listener:
stage.removeEventListener(Event.ENTER_FRAME, gameloop);
I'm using stage as an example, you'll want to change that to whatever object on which you originally added the listener.

When to set stage event-listeners in an externally loaded SWF?

Is there an event that would be triggered inside an externally loaded SWF, once that SWF has been loaded into another parent SWF and has had it's stage initialized?
I'm loading in an external SWF that has stage event-listeners added:
stage.addEventListener(MouseEvent.MOUSE_DOWN, stageClick);
stage.addEventListener(MouseEvent.MOUSE_UP, stageRelease);
The problem is, if I load this SWF into another one like so:
var contentLoader:Loader = new Loader();
contentLoader.load(new URLRequest("DrawingBoard/DrawingBoard.swf"));
I get this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at DrawingBoard_fla::MainTimeline/frame1()
I stop getting this if I comment out the stage event-listeners inside the nested SWF. I'm thinking this is because the loaded SWF isn't being added to the timeline immediately. So, could I add the stage event-listeners in that external SWF, only after it's stage has been initialized?
Add Event.ADDED_TO_STAGE inside constructor of external loaded SWF's main class like so:
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
function onAddedToStage(e:Event):void
{
//You can access stage object here
stage.addEventListener(MouseEvent.MOUSE_DOWN, stageClick);
stage.addEventListener(MouseEvent.MOUSE_UP, stageRelease);
}
UPDATE:
For timeline code you can use Event.ACTIVATE. like so,
addEventListener(Event.ACTIVATE, onActivate);
function onActivate(e:Event):void
{
//remove this listener if you want to dispatch it only once
removeEventListener(Event.ACTIVATE, onActivate);
}
But be careful. This event will dispatched every time you will come back to stage (e.g. From desktop to you application). So remove it if you want only once.

as3 how to trace which movieclip is dispatching event

im working on a fps game. The game contains multiple enemy. But im calling the same movieclip as enemy. That movieclip dispatches fire event and reduce player life. But i need to know which movieclip is dispatching event. I've added enemy randomly, i need to know the enemy location of the enemy who just have fired. Heres some code which may help...
dispatchEvent(new Event('Enemy_Fired')); // this event is dispatching from enemy movieclip
this.addEventListener('Enemy_Fired',ReduceLife);
public function ReduceLife(e:Event){
life--;
var currentLife:int = life * lifeRatio;
if(life<1){
Game_Over();
//game_completed();
} else {
sview.playerhit.gotoAndPlay(2);
sview.lifebar.gotoAndStop(100 - currentLife);
sview.health.text = String(currentLife);
}
//Here i need to know this event dispatched from which enemy
}
Thanks in advance
You can get a reference to the object that dispatched the event by using:
e.target
It seems like the parent is dispatching the Event though as seen in this line of code.
dispatchEvent(new Event('Enemy_Fired')); // this event is dispatching from enemy movieclip
because dispatchEvent is the same as this.dispatchEvent, which means your root class is dispatching the event.
You need to change it to this
yourEnemyMovieClip.dispatchEvent(new Event('ENEMY_FIRED',true,false);
Note that i am putting the bubbles property of your Event on true and cancelable on false. Bubbles means that your event will bubble up on the display chain. That is important , because you are listening for the event in your root class, which is one level higher than the movieclip that dispatched the event.
See the constructor of the Event class here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html
in your eventlistener add the following
e.stopImmediatePropagation();
this will stop the event from bubbling any higher up on the displaychain, saving performance in your application.

Checking if Mouse Click was not in a MovieClip

I have number of movieClips on stage, with each having it's own Event Listener. Once Click/Touch the event is called each movie clip does something. For example one movieClip makes about 6 other movie clips visible.
What I want to do is, when the user Touch/Click somewhere else on stage, where there is no movieClip I want to know, so I can perform some actions such as make some movieClips invisible.
P.S the reason why I say Touch/Click is I'm developing this app for Android, however to make testing easier I'm currently testing everything in PC with MouseEvent, rather than TouchEvent. Once I get all the features working, I will switch over to TouchEvent and test it in mobile.
Many Thanks,
Mike
Add event listener to the stage. And in the event handlers of your inner movieclips use event.stopPropagation function to prevent bubble event to the container.
I would just do a check, it's simple and quick and doesn't require adding code to alter propagation.
import flash.events.MouseEvent;
stage.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
function onClick(e:MouseEvent):void
{
if(e.target == stage)
{
trace("click click");
}
}

AS3 MOUSE_LEAVE problem

I am coding a drag and drop application where I can grab an object and then place it over different object containers. When I am dragging the object (keeping the mouse button pressed) and I leave the stage, I can still control the object with the mouse...this is not what I want.
I would like to lose control of the object when the mouse leaves the stage.
I tried to remove the event listener for MOUSE_DOWN on a MOUSE_LEAVE event but nothing.
I also tried to dispatch a MOUSE_UP event on a MOUSE_LEAVE event but it does not work either...it works only if I manually release the mouse button.
Is there any way to override the MOUSE_DOWN event when the user moves the mouse away from the screen but he is still pressing the mouse button???
Any suggestion???
Thanks in advance
Is the stage actually listening to the MOUSE_LEAVE event? In any case , check this article, it may help:
http://www.kirupa.com/developer/flashcs3/detecting_when_mouse_leaves_movie.htm
Here's a couple tricky traps not to fall into :
One bizarre thing is that in Chrome + Firefox, the MOUSE_LEAVE event isn't dispatched for a WMODE of OPAQUE orTRANSPARENT. It just doesn't fire - mouse down or up.
With WINDOW it works fine. That one took me a long time to find out! grr... http://bugs.adobe.com/jira/browse/FP-892
Second, make sure you're using Event for the parameter type for your Event.MOUSE_LEAVE handler and not MouseEvent. If you try to handle MOUSE_LEAVE with e:MouseEvent you'll get an error that you may never see (unless you're using the debug flash player). It's a very easy mistake to make because you're probably pointing all your other handlers to the same method.
Here's what I do: (just call my main endDrag from mouseLeave(e:Event)
stage.addEventListener(MouseEvent.MOUSE_MOVE, drag);
stage.addEventListener(MouseEvent.MOUSE_UP, endDrag);
stage.addEventListener(Event.DEACTIVATE, endDrag);
stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
private function mouseLeave(e:Event):void
{
endDrag(new MouseEvent("MOUSE_LEAVE"));
}
public function endDrag(evt:MouseEvent):void
{
/// handle end drag
}
I believe you are talking about the user leaving the flash content altogether with mouse clicked, and when he/she returns it continues the process right?
I suggest, you track the mouse x & y coordinates. Set a condition which triggers the mouse up event handler when the x or y is equal to the stage width or height respectively.
When you drag an object outside the flash movie, the object will fire a MOUSE_OUT event. You can listen to this event, use a variable to check if the object is being dragged, and, if so, dispatch a MOUSE_UP event.
some_object.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
some_object.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
some_object.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
private function mouseOutHandler(e:MouseEvent):void
{
if (isDragging)
e.target.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
}
private function mouseDownHandler(e:MouseEvent):void
{
e.target.startDrag();
isDragging = true;
}
private function mouseUpHandler(e:MouseEvent):void
{
e.target.stopDrag();
isDragging = false;
}