How to tell stage that event didn't handle - libgdx

I'm new with scene2d I don't know if what I do is right or not but I struggling with this problem.
I have two stage that add to InputMultiplexer.
first stage have two type of actor as stage's actor
stage.addActor(actor_1);
stage.addActor(actor_2);
then I add listener to the stage to check
if actor_1 or actor_2 was clicked
stage1.addListener(new ClickListener() {
#Override
public void clicked (InputEvent event, float x, float y) {
//task1;
}
});
if actor_2 was dragged I want the stage to pass the event to next stage below it but it seem the listener is always check event as handled so the stage below is not handle the drag event as I intent.
I check on Event class it doesn't have method to change handle state to false, then what I have to do to make this listener tell the first stage to pass event to the second stage in InputMultiplexer.

Related

click events don't reach root flash object

I started using as3 a while ago, and mostly used starling instead of native flash objects. Today I decided to give a try to raw flash, and created a simple button:
private var _button: SimpleButton;
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
}
private function OnClick(e:MouseEvent):void
{
trace("clicked");
}
This would definely work in starling, but I found that the click event won't dispatch to the button for some reason. Neither is hand cursor shown on mouse over. I tried mouse over, mouse up and other mouse events, but none of them work. I checked that the button is correctly added to stage. Also, when I add a mouse click event listener to the stage itself, clicks register normally. When I add a listener to Main, no events are registered again.
I'm probably misunderstanding something obvious. Maybe I need to dispatch events manually down to the children? But that would be strage, though. Or can it be a bug in FlashDevelop? Please, help.
The constructor of SimpleButton takes 4 optional parameters:
public function SimpleButton(upState:DisplayObject = null,
overState:DisplayObject = null,
downState:DisplayObject = null,
hitTestState:DisplayObject = null)`
of which you supply the first one (upState):
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
The others default to null. That includes hitTestState which is the same as property of the class hitTestState:
Specifies a display object that is used as the hit testing object for the button. [...] If you do not set the hitTestState property, the SimpleButton is inactive — it does not respond to user input events.
It also includes a solution to your problem:
For a basic button, set the hitTestState property to the same display object as the overState property.
However, if all you want is to add click functionality to that Bitmap, which it doesn't have on its own, because it's not an InteractiveObject, simply use a Sprite:
// entry point
_button = new Sprite();
_button.addChild(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
Use SimpleButton only if you want the functionality of its 4 states.
Please be careful with the overloaded term "stage":
I checked that the button is correctly added to stage.
If you mean the "drawing area" that you can see in the Adobe Flash IDE or the main time line with "stage", then yes, you'd be correct that your button is added to that.
The stage property of DisplayObject however is something different. It's the top most element of the display list and the container that the instance of your Main class is added to, which happens at the start of the execution of your .swf in the FlashPlayer.
As your Main class adds the _button to itself by calling its ownaddChild(), the button is added to the instance of Main and not stage, which are two different objects.

Libgdx Hud Stage Button not Listening events

I am trying to implement a HUD stage on top of the current stage. I am able to render and draw the HUD stage but its buttons' touch events are not responding.
I am calling my drawHUD() from my draw() method of GameScreen. Code for drawHUD() is
public void drawHud(int scoreVal){
Hud.this.getCamera().update();
Hud.this.hudSpriteBatch.setProjectionMatrix(Hud.this.getCamera().combined);
hudSpriteBatch.begin();
scoreStr = "Score: " + scoreVal;
glyphLayout.setText(scoreFont, scoreStr);
halfWidth = glyphLayout.width/2;
halfHeight = glyphLayout.height/2;
scoreFont.draw(hudSpriteBatch, scoreStr, EatGame.CAMERA_WIDTH/2 - halfWidth, EatGame.CAMERA_HEIGHT - halfHeight);
hudSpriteBatch.end();
}
I have added a listener to my pauseBtn like this when creating my HUD
pauseBtn.addListener(new InputListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("PauseBtn Touched");
return false;
}
}
I have also tested by setting the bounds of the button, but it is not responding to events.
Thanks for reading and helping.
Usually you use the scene2d API for implementing buttons and stuff like that. The Stage class is responsible for handling the events on the correct actor. Look at the Stage#touchDown() how they do it. If you want to implement this on your own, you would have to implement a global touch-listener and check, if the coordinates are inside the bounds of the button and then call fire on the button with the correct Event object.
I would highly recommend to use the scene2d api, its far more easier then to write your own hit-detection-firing-event-system.
I had to use InputMultiplexer for taking input events from both the stages. I have done this that way.
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(GameScreen.this);
multiplexer.addProcessor(hud);
Gdx.input.setInputProcessor(multiplexer);
This way it will receive events from both the stages. GameScreen and Hud are Stages.

MouseEvent not dispatching on movie clip

I know this must be easy but somehow I have not been able to figure it out after spending more than hours. I have two movie clips in a class that extends Sprite. When I add event listener to the stage every thing works fine. But when I try to add event listener to one of the movie clips, the event never dispatches it seems. Here is how it looks like -
public class MyClass extends Sprite
{
private var movieclip1:MovieClip, movieclip2:MovieClip;
private function init(e:Event == null):void
{
movieclip1 = new MovieClip();
movieclip2 = new MovieClip();
//works fine, dispatches event
stage.addEventListener(MouseEvent.MOUSE_DOWN. mousedown);
//not working
movieclip1.addEventListener(MouseEvent.MOUSE_DOWN, mousedown);
addChild(movieclip1);
addChild(movieclip2);
}
}
Actually I want both the movie clips to work mutually exclusively, i.e., a mouse event on one movie clip should not interfere with that of the other. Any pointers?
Empty MovieClips and Sprites CANNOT be sized, they will be 0,0 and then they will not be able to dispatch MouseEvents.
You can resize a MovieClip when it has some content.
The Sprite will be of the size of the rectangle that encloses the 2 MovieClip.
If the MovieClips are empty = 0,0 the Sprite will be 0,0
About the events between the 2 MovieClips:
They are not going to interfere because the events when are bubbling goes upwards.
So the listeners put on MC1 will listen ONLY onClick on MC1 and the same does MC2
You can trace the width and height of the movieclip1 or movieclip2, you will get 0 both.
So, you can't click them.
You can use graphcis to draw a shape in these two mcs, and try again.

Is every MOUSE_DOWN guaranteed a MOUSE_UP?

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);
}

as3 RollOver movieclip menu

I'm trying to do a bottom menu like in www.zara.com.
My code have a transparent movieclip that shows the menu when mouse rolls over it, and hide when mouse rolls out.
The menu appears over that transparent movieclip, so I can use the roll over and out actions to maipulate the menu with the transparent MC.
The problem here is when mouse Roll Over my menu MC and it behaves as rolling out the transparent movieclip.
How can I make mouse rolls over a movieclip over another movieclip without roll out the first one?
Is it to confuse?
Thanx!
When a MovieClip B appears on top of another MovieClip A, MovieClip A will fire the MouseEvent.ROLL_OUT event. This is because MovieClip B is preventing MovieClip A from receiving any MouseEvents (since it is on top).
If you do not need to receive any MouseEvents from MovieClip B, you can set its mouseEnabled property to false, then MovieClip A underneath it will receive MouseEvents.
Also, depending on whether it makes sense in your particular case or not, you can make MovieClip B a child of MovieClip A, so that when MovieClip B obscures MovieClip A, the ROLL_OUT event will not be fired.
I hope this helps answer your question.
Here is a quick and dirty trick originaly from javascript technique
1.) build extra logic into the clipA rollout which waits a small period of time and then checks if the mouse is on the menu or not before closing it.
// define a boolean value for the moust beeing on the menu
public var menuOver:Boolean = false;
public function onMenuOver( event:MouseEvent ):void
{
menuOver = true;
// other menu code here
}
public function onMenuOut( event:MouseEvent ):void
{
menuOver = false;
// other menu code here
}
public function onMainClipOver( event:MouseEvent ):void
{
// show menu code here
}
public function onMainClipOut( event:MouseEvent ):void
{
setTimeout(execMainClipOut,100);
}
/**
* close the menu only if the mouse is not over the menu
*/
public function execMainClipOut()
{
if(!menuOver){
// close the menu
}
}
Ooh! I just remembered something interesting that might solve your problem.
When a MouseEvent.ROLL_OUT event is fired, the listener function is called with a MouseEvent object that has the relatedObject property. This is a reference to the object that is gaining mouse focus (getting rolled over) -- in your case, you could ignore the event if this property is set to your other MovieClip object, then fire the event manually when your other MovieClip object rolls out (so that it rolls out both of them).
as mentioned above, relatedObject works PERFECTLY
so for example if you have MovieClip A and then have Movieclip B on top.
You want Movieclip B to show on rolling over MovieClip A and hiding when rolling out of Movieclip A,
what generally happens is that Movieclip B will show but then when you hover over B, Moveclip B will dissappear, as B lies on top of A, rollout event takes place
so on Movieclip A rollout even just use
if((event.relatedObject == MoveClipB)
{
//if its rolling over B, which is a related object, dont do anything
}
else
{
//Hide B
}
Events for B still work when this is used