I am using libGDX on Android. I set up the Stage and added a CustomActor with a custom draw. It's working properly. However, I am not able to get any logs for the touchDragged method via the InputListener for this actor. Even the code within it does not run.
Here is the required exposure to the code:
public class CustomActor extends Actor {
public CustomActor() {
this.setListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
//This log doesn't print up!
Gdx.app.log("CustomActor","touchDragged");
//This code doesn't work either
Vector2 v = CustomActor.this.localToParentCoordinates(new Vector2(x,y));
CustomActor.this.setPosition(v.x, v.y);
}
});
}
}
Can anyone help me out here on what am I missing ?
Add the Stage you are using as InputProcessor to receive the events else the Stage can't forward the event to the actors.
Gdx.input.setInputProcessor(stage);
Should do it.
try using public boolean addListener (EventListener listener) {...} method of Actor. Which version of libgdx are you using? I think actor does not have "setListener" method.
Check your actor bounds. (width & height)
Related
I want to use the exit() method in the InputListener to see wheter the cursor is inside the button or not.
Here is the explanation in the libGDX docs.
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor)
Called any time the mouse cursor or a finger touch is moved out of an actor.
But when I put my cursor on the button and then move it outside the button, the method is not called. I am testing it by a System.out.println("exited"); and I get nothing in the console.
EDIT:
LibGDX Version: Latest Stable Nightlies
InputListener implementation:
//This button class is a custom class to make button creation easier. This is the constructor.
public Button(Vector2 position, String packLocation, String text, Stage stage, BitmapFont font, Color color) {
//Removed buttonStyle creation etc. to shorten the code.
button = new TextButton(text, buttonStyle);
button.setPosition(position.x, position.y);
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
pressed = false;
button.addListener(new ClickListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
pressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
pressed = false;
}
#Override
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
System.out.println("exited");
}
});
}
EDIT:
Hovering over the button also does not change the texture of the button as I set it to like so:
buttonStyle.over = skin.getDrawable("over");
But clicking does.
After searching for a couple hours I finally found what was missing. stage.act(); had to be called in the render method. This both gave functionality to the texture change when we hover over the button and also the enter/exit methods in the InputListener.
I'm making a simple RTS game. I've created separate Stages for map and UI, and used scene2D Table class for side panel. The problem is, when i hover my side panel, if there is an actor (building) under panel at the moment, it fires its mouseover event. Click events work properly.
Here is my building class input listeners:
public class Building extends Actor {
addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Click");
return true;
}
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){
((Building)event.getTarget()).hover = true;
}
Here is my panel class listeners
public class SidePanel extends Table {
panelBg = new Image(skin,"side-panel");
addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Click");
return true;
}
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){
System.out.println("Enter");
}
});
addActor(panelBg);
}
}
Then side panel is added to UI class stage:
public class UI {
public UI(){
stage = new Stage();
sidePanel = new SidePanel();
stage.addActor(sidePanel);
Gdx.input.setInputProcessor(stage);
}
And finally i added UI to main class:
#Override
public void create () {
ui = new UI();
CP =new InputMultiplexer();
CP.addProcessor(ui.stage);
CP.addProcessor(gameStage);
Gdx.input.setInputProcessor(CP);
}
Not sure where the problem is, because click event works fine;
One quick solution would be to have your Building class check if the mouse was also over the SidePanel. For example, you could change your Building listener's enter method to something like this:
if (mouseIsOverSidePanel)
((Building)event.getTarget()).hover = true;
Your SidePanel listener's enter method can be something like this:
mouseIsOverSidePanel = true;
And your leave method in your SidePanel can be:
mouseIsOverSidePanel = false;
This is mostly pseudo code so it won't work without declaring the variables (obviously) but it should give you a basic idea of how to fix your problem.
i am trying to escalate touchDown and touchUp events from an actor Object to my applicationListener class. To do so, i called fire(event); in the InputListener of my Actor
this.addListener(new InputListener(){
public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
Gdx.app.log("Example", "touch started at (" + x + ", " + y + ")");
fire(event);
return true;
}
public void touchUp(InputEvent event, float x, float y, int pointer, int buttons){
Gdx.app.log("Example", "touch ended at (" + x + ", " + y + ")");
}
});
To handle the event in my ApplicationListener class (which contains the stage of the actors), i added an InputListener to the stage
Gdx.input.setInputProcessor(stage);
stage.addListener(new InputListener(){
public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
Gdx.app.log("FIRE!!!", "I CAUGHT A FIRED EVENT!");
event.stop();
return true;
}
public void touchUp(InputEvent event, float x, float y, int pointer, int buttons){
Gdx.app.log("FIRE!!!", "the fired event even touchupped.");
}
});
However when i touch my actor, i get a StackOverflowError as well as a ton of exceptions from several InputListeners (i assume that the event is not stopped properly and propagated to all actors in my scene). What am i missing here?
Also after firing the event i cant cast event.getTarget() (which is an Actor) to my Actor-Subclass anymore, which works just fine if i do this in the ActorSubclass itself. Meaning the following code creates an error when used in the ApplicationListener, but works in the MyActor class:
MyActor actor = (MyActor)event.getTarget();
Since the target is in fact a MyActor Object, how can i access it not only as Actor, but as MyActor?
As #chase said you are recursivelly calling the fire(even) method, as you can only set 1 InputProcessor (your stage) and so always the same method recieves the event.
You should instead use a InputMultiplexer:
add the Stage and your ApplicationListener as InputProcessor to the InputMultiplexer
Set the InputMulitplexer as the InputProcessor by calling Gdx.input.setInputProcessor(multiplexer);.
The InputMultiplexer will then give the event to the first InputProcessor and if it returns false, it will send the event to the next one.
So in your Stage you just need to return false.
But i don't understand why you are adding your Stage as a InputProcessor if you don't want it to handle inputs...
Anyways in scene2d you don't need to add an InputProcessor to the stage as it allready has one. Also the Actor allready has a boolean touchDown(float x, float y, int pointer) and other helpful methods.
A useful link: Scene2D wiki article
Aren't you just making a recursive call at this point by refiring the event every time you handle it?
Why not just return false from your listener?
I would like to use some of the more complex touch screen gestures that you can't access from
Gdx.input
I saw that to do this i must create a Gesture listener so i created the class GestureHandler and copied the code from the wiki. My gesture handler looks like this:
public class GestureHandler implements GestureListener {
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
return false;
}
}
My question is now that i have set up the gesture listener how can i use it. How can i get the info from these methods? Thank you for any help!
From the wiki:
A GestureDetector is an InputProcessor in disguise. To listen for
gestures, one has to implement the GestureListener interface and
pass it to the constructor of the GestureDetector. The detector is
then set as an InputProcessor, either on an InputMultiplexer or as
the main InputProcessor
I admit that is rather dense. But a bit farther down on the wiki you'll see:
Gdx.input.setInputProcessor(new GestureDetector(new MyGestureListener()));
To rephrase the above in hopefully less dense English: Your GestureHandler instance is passed to a Libgdx GestureDetector instance. That object will accumulate "raw" inputs and convert them into higher-level "gestures". To get the raw inputs, it needs to be installed where the raw inputs will be delivered to it. The most basic way to install it via Gdx.input.setInputProcessor, but you could also install it via an InputMultiplexer (but that's not worth getting into here).
I've created a simple test with a touchDown() event on an image actor. The event works on the stage but not on the actor.
Here is the code:
I set the InputProcessor in the constructor of the parent class (AbstractScreen).
Gdx.input.setInputProcessor(this.stage);
In the sub class:
private TextureAtlas atlas;
private Image boardImg;
public void show(){
super.show();
atlas = new TextureAtlas(Gdx.files.internal("data/packs/mainMenu.atlas"));
AtlasRegion board = atlas.findRegion("board");
boardImg = new Image(board);
boardImg.addListener(new InputListener(){
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
Gdx.app.log("aaaa", "down");
return true;
}
});
stage.addActor(boardImg);
stage.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("aaaa", "stage down");
return true;
}
});
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
boardImg.setPosition(stage.getWidth()/2 - boardImg.getWidth()/2, stage.getHeight()/4);
}
I'm testing both on the desktop and on the android (same results).
I get the "stage down" event but not the event of the actor. I've tried also without having the stage event.
Do all of these works:
boardImg.setTouchable(Touchable.enabled)
return false in stage listener or clear its listener.
do not call setInputProcessor(this.stage) in parent class instead call in child class.
I think the problem is because the touchDown() method of the stage returns true, and so the event will be "consumed" and won't be propagated to its children, the actors, and so the touchDown() method of boardImg will not be called.
Image doesn't receive touch events because it has no size.
Read documentation carefully:
Note that the actor must specify its bounds in order to receive input
events within those bounds.
Just know that boardImg = new Image(board) won't set width and height of actor for you. So you need to make it manualy. Assume you work with pixel perfect sizes:
boardImg = new Image(board);
boardImg.setWidth(board.getWidth());
boardImg.setHeight(board.getHeight());
That will do the trick. Good luck.