I tried using the event dispatch but unable to get clear view of this one, so tell me if anyone know this.
This is Sample Code but i can't understand could you explain elaborate.
var ball:Shape = new Shape();
ball.graphics.beginFill(0xFF0000);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
addEventListener("myCustomEvent", myCustomEventListener);
function mouseMoveListener(event:MouseEvent):void
{
dispatchEvent(new Event("myCustomEvent"));
}
function myCustomEventListener(event:Event):void
{
ball.x = stage.mouseX;
ball.y = stage.mouseY;
}
Think about stage as a big box where magic happens. Stage knows when you resize it, when you press keyboard buttons or when you move mouse on top of it. It does extend EventDispatcher which means it can broadcast stuff (and it does!). You usually don't pay attention to it, but in this particular piece of code you have:
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
function mouseMoveListener(event:MouseEvent):void
{
dispatchEvent(new Event("myCustomEvent"));
}
What's going on in here? You're curious about MOUSE_MOVE event and that's why you add listener. Now every time you move your mouse over the stage, stage is going to broadcast (dispatch) event (like : "HEY! Mouse just moved!"). And every time that happens your mouseMoveListener would be called. You can add trace(stage.mouseX, stage.mouseY); inside it and it would trace your mouse position as you move it. You could also move this code
ball.x = stage.mouseX;
ball.y = stage.mouseY;
to that function and your ball would follow mouse cursor.
However what you're doing is:
dispatchEvent(new Event("myCustomEvent"));
Which basically means that you're broadcasting (dispatching) an event now. What event? "myCustomEvent". Now anyone who is interested might listen for it. And somebody is indeed:
addEventListener("myCustomEvent", myCustomEventListener);
function myCustomEventListener(event:Event):void
{
ball.x = stage.mouseX;
ball.y = stage.mouseY;
}
So you're basically listening for this even in the same class and when this even it being dispatched you execute myCustomEventListener function.
Hope that's gonna make it a bit more clearer for you :)
Related
I'm new to AS3 and need help figuring out how to remove my MouseEvent.MOUSE_MOVE listener if no user interaction occurs.
I have built an animation that does the following:
A solid line and some text appear on top of an image. After this finishes a mouse event is enabled that allows the user to move the line up and down. When the user stops interacting with the line, the line disappears and the final screen of the animation appears.
In the event that the user does not interact with the animation at all (the line never moves), I need to incorporate some way to remove the event listener, then have the final screen of the animation appear. I think adding a TimerEvent is the correct approach for doing what I want, but I'm not sure how to incorporate it. This also may not be the best or correct method. In that case, does anyone have suggestions as to what should be done?
Any help will be appreciated!
Here is my code:
import com.greensock.*;
//objects on the stage
line_mc.y=250;
raisingTxt.alpha=0;
arrow_mc.alpha=0;
final_mc.alpha=0;
logo_mc.alpha=1 ;
//move line mc to y:125
TweenLite.to(line_mc, 1, {y:125});
TweenLite.to(raisingTxt, .5, {alpha:1, delay:1.2});
TweenLite.to(arrow_mc, .5, {alpha:1, delay:1.2, onComplete:followMouse});
//calls MouseEvent onComplete of tween
function followMouse() {
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveIt);
}
function moveIt(e:MouseEvent):void {
TweenLite.to(line_mc, 0.5, {y:this.mouseY});
TweenLite.to([raisingTxt,arrow_mc], 0.5, {alpha:0, onComplete:finalScreen} );
}
//calls final screen onComplete of MouseEvent
function finalScreen() {
TweenLite.to(line_mc, 0.5, {alpha:0} );
TweenLite.to(final_mc, 0.5, {alpha:1} );
}
You can accomplish this with the built in Timer class. I like it a bit more than the setTimeout function because it's simpler to manage.
First create a class wide variable (assuming you are doing this in the Flash IDE, just create it near the top)
var timeout:Timer;
Then in your followMouse():
private function followMouse():void {
timeout = new Timer( 3000, 1 );
timeout.addEventListener( TimerEvent.TIMER_COMPLETE, removeMouseListener );
timeout.start();
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveIt);
}
Last create the removeMouseListener():
private function removeMouseListener( e:Event=null ):void {
timeout.removeEventListener( TimerEvent.TIMER_COMPLETE, removeMouseListener );
stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveIt);
}
If you want to keep resetting the timer every time the mouse moves, you can add these two lines to your moveIt():
timeout.reset();
timeout.start();
I made the removeMouseListener() have an optional parameter so you can call it any time regardless of the timer.
Hope that helps! Good luck!
I have a project where I have a scrolling list. I would like for my user to be able to "long touch" an item on the list so that they can delete it.
I am developing in Air for iOS using Flash CS6 so I don't really know much about the appropriate MultiTouch gestures for iOS deployment.
In my mind, the animation steps I would like to go like so..
Previously invisible button called btn_delete inside the Item movieclip will appear when Long Touch starts + timer begins
Intermediate step: btn_delete will rotate 90 degrees using TweenMax Rotate (I have this covered)
Final step: when timer reaches it's conclusion, a dialog box / confirmation box will pop up and ask the user if they are sure if they want to delete the item.
So here is some generic code I've written quickly to give you an idea of my structure so far (I've omitted the interlinking listener functions):
function exampleFunction {
_item.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
}
//-- Long Press Listener Functions--//
function onTouchBegin(eBegin:TouchEvent) {
trace("start");
}
function onTouchRotate(eEnd:TouchEvent) {
trace("rotation of image");
}
function onTouchEnd(eEnd:TouchEvent) {
trace("end");
}
If anyone has a piece of code they've already written that roughly matches my criteria then please post it!
I would just use MouseEvent for this.
var timer:Timer = new Timer( 500 ); //ms
timer.addEventListener( TimerEvent.TIMER_COMPLETE, timerCompleteHandler );
listItem.addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
function mouseDownHandler( e:MouseEvent ):void {
timer.start();
stage.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}
function mouseUpHandler( e:MouseEvent ):void {
//just some clean up to reset the timer and remove the mouse up event listener from the stage
timer.reset();
stage.removeEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}
function timerCompleteHandler( e:TimerEvent ):void {
timer.reset();
stage.removeEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
//do delete actions here
}
So on mouse down, you start your timer and listen for a mouse up event (on the stage and not the component. That is important. If you want to know why, try it on the component and experiment). On mouse up, you reset the timer so the next time you mouse down, it starts at 0 (reset() has the added benefit of stopping the timer). On timer complete, you do the same as in mouse up in addition to your delete code.
I'm using a MouseEvent here just because it behaves identical to TouchEvent (for the most part) in this instance and it could be used on the desktop (meaning you can test in the emulator and you could add this to other projects if you wanted)
UPDATE:
Just reread your question and realized I missed the rotate. For this, just add another timer with a separate complete handler that and in that function, ONLY do the rotation and reset that timer.
I am making a game which uses collision detection with the mouse.
The player is a custom mouse cursor when the mouse collies with an object the mouse is moved to the coordinates X0,Y0. The code I have used to achieve this is below. However when the mouse is moved to X0,Y0 after a collision when the mouse is moved it starts back where the collision took place rather than moving from the top of the screen.
import flash.events.Event;
var cursor:MovieClip;
function initializeMovie ():void {
cursor = new Cursor();
addChild (cursor);
cursor.enabled = false;
Mouse.hide ();
stage.addEventListener (MouseEvent.MOUSE_MOVE, dragCursor);
}
function dragCursor (event:MouseEvent):void{
cursor.x = this.mouseX;
cursor.y = this.mouseY;
}
initializeMovie ();
this.addEventListener( Event.ENTER_FRAME, handleCollision)
function handleCollision( e:Event ):void{
if(cursor.hitTestObject( wall )){
cursor.x = 0
cursor.y = 0
}
}
Create a button at the 0, 0 coord that is required to click to continue again. Then your user will have to move the mouse to to that spot where you can continue to have the custom cursor track your mouse.
When you reset the position of cursor object you aren't moving the actual mouse position, I don't believe you can actual do what you're trying to (that is write to the mouse position to move the users cursor, I believe this would require system specific code, like C# or I believe Objective C and Cocoa or Carbon on the Mac side).
http://www.kirupa.com/forum/showthread.php?354641-Possible-to-set-mouse-position-in-flash
Here's a way you would do it on Mac apparently
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/Quartz_Services_Ref/Reference/reference.html#//apple_ref/c/func/CGWarpMouseCursorPosition
And a way on Windows
Set Mouseposition in WPF
And a way on Linux (Although this only has AIR support up to 2.6)
How to set the mouse position under X11 (linux desktop)?
So if you implemented both of those solutions and are packaging as an AIR app you could make this work, but otherwise I'm pretty sure it's impossible.
I am making a platform game in flash.
I have a goal class(the class which contains code for the goal sprite, where when you hit it, it continues to next part of game).
Inside the goal constructor, 2 event listeners are added, they are as follows:
addEventListener(Event.ADDED, beginClass);
addEventListener(Event.ENTER_FRAME, eFrame);
The beginClass function is fine, and only runs once, but eFrame is what checks if the player has hit the goal, so it is constantly running. The problem is, once the player hits the goal, eFrame continues to run, while in a menu describing the next scene to the player. My eFrame function is below.
private function eFrame(event:Event):void{
if(hitTestObject(_root.mcMain)){
var lastScore:int = _root.mainScore;
_root.mainScore = lastScore;
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
_root.mcMain.removeChildAt(0);
_root.isInCut = true;
if (_root.lvlCurrent == 1) {
_root.gotoAndStop(2);
} else if (_root.lvlCurrent == 2) {
_root.gotoAndStop(3);
} else if (_root.lvlCurrent == 3) {
_root.gotoAndStop(4);
}
}
}
Frames 2, 3, 4, are frames with just text and a button that display a message to the player, and then the player hits continue. My problem is that eFrame is still trying to be run, but the class has not been instantiated, and the method is causing extreme amounts of lag once the player continues.
Inside Goal, what's the point of _root?
Anyway here's what I've done:
Change the event ADDED to ADDED_TO_STAGE, that way, when the event is fired we know this Sprite has a stage property.
addEventListener(Event.ADDED_TO_STAGE, beginClass);
Remove the eFrame event from the constructor. Add it to beginClass, with stage, like so:
stage.addEventListener(Event.ENTER_FRAME, eFrame);
Now in eFrame, you can awesomely remove the event with the stage reference. It didn't work earlier because the reference was wrong (whatever it was with the _root variable).
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
BUT - remember to do it before this part of your code:
while (_root.lvlHolder.numChildren > 0) {
_root.lvlHolder.removeChildAt(0);
}
because when the sprite is removed, it won't have the stage property anymore. Just remember to clean up events in all possible scenarios. I'm not entirely sure stage is the right place to place your enter frame event, I just assumed so because of what you earlier called _root.
Inside eFrame() stop the event listener:
removeEventListener(Event.ENTER_FRAME, eFrame);
you're adding eventListener to stage so try this:
stage.removeEventListener(Event.ENTER_FRAME, eFrame);
or
parent.removeEventListener(Event.ENTER_FRAME, eFrame);
or
event.target.removeEventListener(Event.ENTER_FRAME, eFrame);
Are there any circumstances under which a Flash application could receive two MouseEvent.MOUSE_DOWN without a MouseEvent.MOUSE_UP in between?
In my ActionScript 3 application, I want to track the user dragging a sprite. My plan is to listen for a MouseEvent.MOUSE_DOWN, start an indefinitely repeating timer that records the mouse position, and stop the timer on MouseEvent.MOUSE_UP. Is that a good plan?
Click but do not release the button.
While keeping the button down move the cursor outside.
Release the button outside.
Come back inside and click again.
You will get two down event without an up event.
A better solution to drag-and-drop might be to listen MOUSE_MOVE event and in the event handler check buttonDown property. If the button is down while moving, this will be true, otherwise false.
EDIT: For stage even if you release the button outside the flash window then up event is fired. So for stage this can work, but still instead of timer using MOUSE_MOVE with buttonDown looks better to me. You can check yourself with the following code:
public class StageEventTest extends Sprite
{
public function StageEventTest()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
}
private function onDown(evt:MouseEvent):void {
trace("down");
}
private function onUp(evt:MouseEvent):void {
trace("up");
}
private function onMove(evt:MouseEvent):void {
trace("move", evt.buttonDown);
}
}
it will miss the mouse up event if the mouse is outside of the stage and continue it's mouse tracking when mousing over the stage since the mouse up event was never called. this likely problem can be mitigated by using Event.MOUSE_LEAVE - forward the mouse leave event to the mouse up event handler so that if the user mouses away from the stage the mouse up event will be called.
Yes, but unless you are listening to the stage, I think you can miss the mouseup event if the mouse has gone outside the Flash movie. Nothing beats an experiment though.
Below you can find the code I always use for custom dragging. Normally, it should work fine. I listen to the MOUSE_MOVE-event for repositioning and tracking the sprite, but you can just as well use the Event.ENTER_FRAME-event or use a timer instead.
ObjectToDrag.addEventListener(MouseEvent.MOUSE_DOWN, startCustomDrag);
public function startCustomDrag(e:MouseEvent):void
{
_prevX= e.stageX;
_prevY= e.stageY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragObject); //REPLACE BY TIMER OR Event.ENTER_FRAME
stage.addEventListener(MouseEvent.MOUSE_UP, stopCustomDrag);
}
private function dragObject(e:MouseEvent):void
{
ObjectToDrag.x += _prevX - e.stageX; //OR ANY OTHER CALCULATION
ObjectToDrag.y += _prevY - e.stageY; //OR ANY OTHER CALCULATION
_prevX= e.stageX;
_prevY= e.stageY;
}
public function stopCustomDrag(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragObject); //REPLACE BY TIMER OR Event.ENTER_FRAME
stage.removeEventListener(MouseEvent.MOUSE_UP, stopCustomDrag);
}