I have a menu screen in libgdx and I had a text button that started a new game like this.
textButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
g.setScreen( new level1(g));
}
});
It looked like crap so I changed it to an image.
playbuttontexture = new Texture(Gdx.files.internal("data/playbutton.png"));
playbuttontexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion playbuttonregion = new TextureRegion(playbuttontexture, 0, 0, 512, 256);//powers of 2
playbutton = new Image(playbuttonregion);
playbutton.setSize(512,256);
playbutton.setBounds(width/2-playbutton.getWidth()/2, height/2-playbutton.getHeight()/2, 512, 256);
//playbutton.setOrigin(playbutton.getWidth()/2, playbutton.getHeight()/2);
playbutton.setPosition(width/2-playbutton.getWidth()/2, height/2-playbutton.getHeight()/2);
and
playbutton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
g.setScreen( new level1(g));
}
});
Now when I click it nothing happens? What am I doing wrong?
The problem here is that Image does not fire a changed(...) event anymore. This event is only fired by the TextButton you've used before when the status changes from clicked to not-clicked and the other way around. It can also be fired in other cases, since it is kind of a "generic" event, as the JavaDoc states, but that varies from actor to actor.
Change it to a ClickListener and use the clicked(...) method instead. This event should be fired by all actors in the scene2d.ui package.
for me this is what it looks like when I implemented the code ( I was having a similar issue. noone did a great job at pointing me to the right places to look. )
playbutton.addListener( new ClickListener(){
#Override
public void clicked (InputEvent event, float x, float y) {
//your code to do stuff when the button is clicked
}
});
Related
I am making a game in Android Studio using LibGDX, and I am attempting to add a pause button to the top corner of the main game screen. My game has been pausing fine thus far, but I have only been pausing when a key was pressed. Now I want to add a button, and I got the button to render in the top right corner, but when I press it it only works once. The first time I press it, my game pauses fine. But every time I try and pause it after that, it doesn't work. I have used extensive log statements and debugging and have found out that after pressing it once, the Listener doesn't even detect the button being pressed at all, so I am lead to believe that is where my issue is.
This is how I create my button in my HUD class, which is the class that prints the score onscreen at all times:
TextureAtlas buttonAtlas = new TextureAtlas(Gdx.files.internal("Buttons.pack"));
Skin skin = new Skin();
skin.addRegions(buttonAtlas);
ImageButton.ImageButtonStyle style = new ImageButton.ImageButtonStyle();
style.imageUp = skin.getDrawable("PauseButton");
style.imageDown = skin.getDrawable("PauseButton");
style.imageChecked = skin.getDrawable("PauseButton");
button = new ImageButton(style);
I then added a Listener to check if the button is clicked:
button.addListener(new ClickListener()
{
#Override
public void clicked(InputEvent event, float x, float y)
{
Gdx.app.log("","Button was pressed");
pauseGame();
}
});
The method pauseGame() that is called after the Listener detects the button being clicked:
public void pauseGame()
{
Gdx.app.log("","Game should be pausing");
screen.pauseGame();
}
screen is a class called PlayScreen that is the main game screen for my game, and its pauseGame() method works perfectly. The game before you press the pause button is as follows(You can see the pause button in the top right corner, please excuse the graphics, they are simply placeholders until I make and add my own graphics):
Game before pause
In my main PlayScreen class, this is my pauseGame method:
public void pauseGame()
{
gamePaused = true;
if(music.isPlaying())
{
musicType = type.NORMAL;
music.pause();
}
else if(barrageMusic.isPlaying())
{
musicType = type.BARRAGE;
barrageMusic.pause();
}
createPauseWindow();
}
And then in my render method, I call another method called update. In this method, I update my viewport, my HUD, and create new enemies. This is the only method that stops being called when gamePaused is true. The rest of my rendering and other necessary updates still take place. I have been trying to fix this problem for a long time but no matter how many different ways I rewrite the code to pause the game or make different listeners, the pause button only works one time and then never again.
Have you ever tried with touchDown method?
It might works.
button.addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
pause();
event.handle();
return true;
}
});
And try to change to a global variable base, a variable that is checked inside your render method and if it is true call the pause method. That to avoid call complex actions like pause from a listener, something like this:
button.addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
pause = true;
event.handle();
return true;
}
});
...
public void render(){
if (pause == true){
pauseGame();
}
...
}
It simplifies your listener and let you find easily your error.
I have a JavaFX Application based on vlcj and I want to observe or bind a float.
float position = mediaPlayer.getPosition(); // returns actual position
How can I observe or bind position to a slider? Position has no property.
Slider timeSlider = new Slider(0d, 100d, 0d);
timeSlider.setValue(position); // but position is permanently changing
Do you have any ideas? Thanks a lot. :)
You cannot use a binding here, but:
As I can see in MediaPlayer, you can add listeners:
void addMediaPlayerEventListener(MediaPlayerEventListener listener);
and MediaPlayerEventListener class has a
void positionChanged(MediaPlayer mediaPlayer, float newPosition); method which class is implemented by MediaPlayerEventAdapter.
Media play-back position changed.
Therefore this two way listening should work:
mediaPlayer.addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
#Override
public void positionChanged(MediaPlayer mediaPlayer, float newPosition) {
timeSlider.setValue(newPosition);
}
});
timeSlider.valueProperty().addListener((obs, oldval, newval) -> mediaPlayer.setPosition(newval));
(Haven't tried it)
I was able to draw my buttons, but nothing happens when I click/"touch" them, and I have no idea what I'm doing wrong. Can anyone please help? Shouldn't the textButtonStyle change to "ToothButton" when it's touched? Am I not supposed to use an InputListener for an Android app?
MainMenuButtons.java
public class MainMenuButtons extends Stage {
Stage buttons;
MMButton startButton, optionButton;
public MainMenuButtons(Viewport viewport) {
startButton = new MMButton(634,550, "Start");
optionButton = new MMButton(634,450, "Options");
buttons = new Stage(viewport);
buttons.addActor(startButton);
buttons.addActor(optionButton);
Gdx.input.setInputProcessor(this);
}
MMButton.java (Main Menu Button)
public class MMButton extends Actor{
TextButton button;
TextButton.TextButtonStyle textButtonStyle;
BitmapFont font;
Skin skin;
TextureAtlas buttonAtlas;
public MMButton(int x, int y, String name) {
font = new BitmapFont();
skin = new Skin();
buttonAtlas = new TextureAtlas(Gdx.files.internal("menuButton.atlas"));
skin.addRegions(buttonAtlas);
textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = skin.newDrawable("ToothButtonUp");
textButtonStyle.down = skin.newDrawable("ToothButton");
button = new TextButton(name, textButtonStyle);
button.setBounds(x, y, 246, 90);
button.setTouchable(Touchable.enabled);
button.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println("down");
return true;
}
public void touchUp(InputEvent event, float x, float y, int pointer, int button ) {
super.touchUp( event, x, y, pointer, button );
}
});
}
MainMenuScreen.java (I'm sorry for all the code I really just want this problem solved!) :(
OrthoCamera is a class I got online that simplified the use of a camera.
public class MainMenuScreen extends Screen{
private OrthoCamera camera;
MainMenuButtons buttons;
#Override
public void create() {
camera = new OrthoCamera();
buttons = new MainMenuButtons(new ScreenViewport());
}
#Override
public void update() {
camera.update();
buttons.draw();
}
#Override
public void render(SpriteBatch batch) {
batch.setProjectionMatrix(camera.combined);
buttons.draw();
}
#Override
public void resize(int width, int height) {
camera.resize();
buttons.getViewport().update(width,height,true);
}
Your problem is with the MainMenuButtons class. It has two stages. One (buttons) has the button actors added to it, and the other (this) is set as the input processor. That's no good.
There are two solutions.
Either...
Replace this line...
Gdx.input.setInputProcessor(this);
With this...
Gdx.input.setInputProcessor(buttons);
And don't bother extending stage.
Or (if you really want to extend stage)...
Get rid of the buttons variable altogether, and replace these lines...
buttons.addActor(startButton);
buttons.addActor(optionButton);
With this...
addActor(startButton);
addActor(optionButton);
I see a few issues.
You have a stage within a stage. The inner stage has your buttons in it, but it's not set as the input processor. Remove the inner stage and use the outer one directly. Or if you're trying to organize your code here, make your MainMenuButtons class not extend Stage (and give it a getStage() method so the game class can call act and draw on it).
You never call act on your stage, so it won't respond to or act on anything.
Your MMButton class contains an inner Button instance that is never added to the Stage, so the inner Button will never receive touch events, even though it has a listener. You could make the MMButton class extend Group instead of Actor, and add the inner Button to it via addActor(). But I think you are reinventing the wheel here. You don't need an MMButton class when you can use the existing TextButton class directly--it's already an Actor itself. From what I can see, MMButton is a redundant wrapper.
Sidenote: It is inadvisable to use separate texture atlases and fonts for each button. A texture atlas is meant to be shared by many objects to take advantage of sprite batching.
I'm using AndEngine and Box2d in android application.
How can I have just one event, attached to the "Game Scene", from where I can find out what is pressed, instead of putting an event on every button in "GameHud" and how to detect the hold of the buttons?
public class GameScene extends Scene{
public GameScene(){
GameHud hud = new GameHud(this,activity);
camera.setHUD(hud);
}
//catch the touch event here
}
public class GameHud extends HUD{
public GameHud(Scene scene, GameActivity activity){
Sprite leftArrow = new Sprite(75,75,leftArrowRegion,activity.getVertexBufferObjectManager())
{
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
//...
return true;
}
};
scene.registerTouchArea(this.leftArrow);
Sprite rightArrow = new Sprite(200, 75, rightArrowRegion, activity.getVertexBufferObjectManager())
{
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
//...
return true;
}
};
scene.registerTouchArea(this.rightArrow);
}
}
You can listen for touch events in the Scene with this:
setOnSceneTouchListener(new IOnSceneTouchListener() {
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
// do something with the touch event
return true; // or false if not handled
}
});
However, doing it this way will require you to calculate which, if any, button was clicked based on the (x, y) coordinates of the touch event. If you feel that this is a better approach rather than registering events on each button you are more than welcome to do that, but you will be redoing a lot of the logic that is already embedded in the engine.
If it is the logic of the touch events that you want to share between buttons, you can have each registered event call the same method with an id or something to differentiate the buttons. That will allow you to centralize the action logic and not have to repeat it for each button being pressed.
If neither of these approaches are what you are looking for, feel free to leave a comment on what is missing and I'll do my best to help you achieve it.
I am building a simple game with LIBGDX, and I have come across this irritating problem.
I have a MenuScreen.java class, which looks like this:
Here's the full class on pastebin
The important part is the imageButton's inputListener:
button.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
MineFinder.Log.debug("xpos: " + x + ", ypos: " + y);
game.setScreen(new GameScreen(game));
}
});
My problem is, that if this class is present (and GameScreen gets called from this) for some reason if I click to the ImageButton's position in GameScreen, it still handles the input. This is really irritating, because if a player clicks on that part of the screen the game gets reseted.
If i remove references to my MenuScreen.java file, and skip it alltogether the problem isn't present, so I am pretty sure that the problem is that the InputListener doesn't get "deleted"
Any ideas how to fix this?
Thanks!
The problem is that in your resize method. This line:
Gdx.input.setInputProcessor(stage);
sets the global input processor to be the stage. The input handling code doesn't really care about what is being rendered on the screen.
I think the easiest fix is to set the input processor in show and clear it in hide. Something like this:
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
}
#Override
public void hide() {
Gdx.input.setInputProcessor(null);
}
Alternatively, you could have your callbacks check to see if the button/stage/screen they are in is active, or unregister/re-register the callbacks in show/hide, depending on how you are using your Screens.