LibGdx ImageButton playing sound - libgdx

I have created an imageButton with three drawable images;
one is button-up,button-down and button checked.Its purpose is to ON and OFF sound for the game.once sound is OFF,checked image should be displayed.
I have written the code like this:
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),
new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture3));
stage.addActor(soundButton);
soundButton.setPosition(Constants.WORLD_WIDTH / 4 + 300f, Constants.WORLD_HEIGHT / 4, Align.bottomLeft);
soundButton.addListener(new ChangeListener(){
#Override
public void changed(ChangeEvent event, Actor actor) {
if(!game.soundBool)
game.soundBool=true;
else
game.soundBool=false;
}
});
Here soundBool is initially false and game sounds will play when it is false.
once I make it true,sounds should not play.This boolean is working well.
Problem is that once I checked the button(sound OFF) sound is getting OFF permanantly.Again Button click is not working as expected.
How do I change the code to work it well?

Have you checked how often the changed() method is called? Use Gdx.app.log() for logging. Or try using a different Listener, like ClickedListener for the button.
You could also make you own Button, class MyButton extends Button to keep a cleaner code. Here is how I solved it.

Related

Sound button to make sound ON or OFF does not changing button image

I have a sound button in my menu screen.It has two images.one is normal and other is checked(indicating sound is OFF).
I am using a boolean variable to get the state of this button.If it is true,sound will play else sound will be OFF.I am using it to control in-game sounds.
public boolean soundBool=true;
created soundButton like this:Here soundTexture1 is normal image(ON) and soundTexture2 has a cross mark(OFF).
private void drawSoundButton() {
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),
new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture2));
stage.addActor(soundButton);
soundButton.setPosition(UiConstants.SOUND_X, UiConstants.SOUND_Y, Align.bottom);
soundButton.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
if (!game.buttonClickSoundBool)
buttonClickSound.play();
soundButton.scaleBy(0.025f);
if(game.soundBool)
game.soundBool=false;
else
game.soundBool=true;
}
});
}
I am calling all sounds with play() only when this soundBool is true.
Now when I click this button,crossmark will come,sound will be off and works fine in terms of sound.
Whenever I come back to menu,the image with cross mark should be displayed because the sound is OFF.But it does not shows the cross mark image.It shows the first image.But functionality is fine.If I click,sound will go ON.
It would be helpful if someone explains how to solve this.
Use setChecked(boolean status); on soundButton according to the status of soundBool.
private void drawSoundButton() {
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture2));
soundButton.setChecked(!soundBool); // setChecked according to boolean status
stage.addActor(soundButton);
soundButton.setPosition( UiConstants.SOUND_X,UiConstants.SOUND_Y,Align.bottom);
...
}
Also don't forget to save status of soundBool in preference so that you can restore that value, when you come back in your game.

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.

libgdx Table can't get ChangeListener for a click to fire?

I have a table added to a stage, and I can't get a click listener to fire for it:
Table table = new Table();
table.setX(0);
table.setY(0);
table.setWidth(300);
table.setHeight(300);
table.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
System.out.println("click");
}
});
stage.addActor(table);
I've set a background nine patch on the table, and it's rendering just fine. Clicking has no effect. If I add something like a label or a button to the table, then set the same ChangeListener to those widgets, the listener fires just fine.
Is there some special handling that Table needs for this to work?
Thanks
--------- Update -------------------
The only way I could get this to work was by using an EventListener to block all interaction on the Table instance:
table.addListener(new EventListener() {
#Override
public boolean handle(Event event) {
return true;
}
});
All the events would fire as expected here.
I also tried setting the table to touchable, but still the ChangeListener would not fire:
table.setTouchable(Touchable.enabled);
table.setListener(....);
So I guess I'm going to stick with the EventListener approach.
The Table in libgdx is not touchable by default, in its constructor setTouchable(Touchable.childrenOnly);(Take a look at the source) is called, which means, that this Actor (the `TableĀ“) won't get any input events, but its children will (Look at the javadoc).
So to enable input events for the Table and not only for its children, you need to call setTouchable(Touchable.enabled).
I hope this solves your problem.

GameStateManager LibGDX

I started a project with libgdx and I have a GameStateManager for my GameStates Menu and Play.
If I run the project it shows the Menu and then I can click a button to open the Play GameState.
The Problem is, that when I ended the Game it should show the Menu State again, but I get a black screen. I tested if the render() method is started (with System.out...) and the render() method in Menu is starting.
I am not shure why I get a black screen when I "reopen" the Menu state. Maybe its not working because I use Box2D in Play but I dont know.
Here some code:
This is the method in Play which should open the Menu if the player is at the end:
public void playerEnded() {
gsm.setState(GameStateManager.MENU);
}
Maybe you can tell me, if I have to end box2d things or so.
I hope someone can help me, and if you want more code - no problem.
Your custom GameStateManager should extend this class:
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Game.html
To change screens you should be using Game.setScreen(Screen screen)
Each different screen should be an implementation of Screen.
So the way it works in my libGDX projects is such that GameScreen extends Screen, and MenuScreen extends Screen. That way I can change what draws on what screen.
This all goes back to interfaces and polymorphism, so if you don't get those concepts, just give it a quick google and you'll get an idea what you need to do.
Chances are that your are defining a
Stack<GameState> gameStates
in your GameStateManager to manage your GameStates.
If so, you could do some reading on using a Stack. Anyway, here's what could do to solve your problem:
I'm assuming you have the following structure in your GamestateManager;
public void setState(int state){
popState();
pushState(state);
}
public void pushState(int state){
gameStates.push(getState(state));
}
public void popState(){
GameState g = gameStates.pop();
g.dispose();
}
private GameState getState(int state){
if(state == MENU) return new Menu(this);
if(state == PLAY) return new Play(this);
return null;
}
When you click your start button in your Menu-GameState, you'll want to launch the Play-GameState.
Now, instead of using the setState method, which removes the top state (pop) and then pushes the new state. Try using only the pushState method. This will put your new Play-GameState on top of your Menu-GameState in the GameState-Stack.
When you're done playing, you can pop your Play-GameState and the Menu-GameState should reappear. But this time it won't instantiate a new Object, but reuse the one you used when you started the game.
// in the Menu-GameState:
public void startPlay() {
gsm.pushState(GameStateManager.PLAY);
}
// in the Play-GameState:
public void playerEnded() {
gsm.popState();
}
This won't affect gameplay performance as you would render and update your game with only the GameState that is on top of the Stack, like this:
public void update(float dt) {
gameStates.peek().update(dt);
}
public void render() {
gameStates.peek().render();
}
The peek method takes the GameState from the top of the Stack, but leaves it there.
The only downside is that the Menu-Gamestate would stay in-memory during your Play-State.
Also, if this method works, you could still do it your way, but you should check the way your Menu-GameState is instantiated and identify problems when it's instantiated twice.
I implemented a similar StageManager in my game. If you are using viewports/cameras in your game, then it is likely that when you go back to your menu state, the viewport is still set to the Game state's viewport.
For my app, I had my State class have an activate() method which would be called whenever a state became the active state:
public void activate(){
stage.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}

Why is my button instance forgetting its textfield text and event listener?

I'm working on an assignment due at midnight tomorrow and I'm about to rip my hair out. I am fairly new to ActionScript and Flash Builder so this might be an easy problem to solve. I think I know what it is but I do not know for sure...
I'm developing a weather application. I designed the GUI in Flash CS5. The interface has 2 frames. The first frame is the menu which has a zipcode input and a button instance called "submit". On the second frame, it has another button instance called "change" which takes you back to the first frame, menu.
In Flash Builder 4, I wrote a class to extend that GUI called Application. When Main.as instantiates it, the constructor function runs. However, this was my first problem.
public class Application extends InputBase {
public function Application() {
super();
// Y U NO WORK???
this.gotoAndStop(1);
this.change.tfLabel.text = "Change";
}
}
When I ran debug it tossed a #1009 error saying it could not access the property or method of undefined object. It is defined on frame 2 in Flash CS5. I think this is the problem... Isn't ActionScript a frame based programming language? Like, you cannot access code from frame 2 on frame 1? But, I'm confused by this because I'm not coding on the timeline?
Anyway, I thought of a solution. It kinda works but its ugly.
public class Application extends InputBase {
public function Application() {
super();
// Y U NO WORK???
this.gotoAndStop(1); // when app is first ran, it will stop on the first frame which is the menu frame
setButton(this.submit, "Submit", 1);
setInput(this.tfZipCode);
}
private function submitZip(e:MouseEvent):void {
this.nextFrame();
setButton(this.change, "Change", 2);
}
private function menu(e:MouseEvent):void {
this.prevFrame();
setButton(this.submit, "Submit", 1); // if I comment this out, the submit button will return to the default text label and it forgets it event.
}
private function setButton(button:ButtonBase, string:String="", action:uint=0):void {
button.buttonMode = true;
button.mouseChildren = false;
button.tfLabel.selectable = false;
button.tfLabel.text = string;
switch (action) {
case 1:
button.addEventListener(MouseEvent.CLICK, submitZip);
break;
case 2:
button.addEventListener(MouseEvent.CLICK, menu);
break;
default:
trace("Action code was invalid or not specified.");
}
}
}
Its not my cup of tea to run the set button function every time one of the button instances are clicked. Is this caused by frames or something else I maybe looking over?
I believe you have two keyframes & both have an instance of the button component called button.
If you are working on the timeline try putting the button in a separate layer, with only one key frame.
Something like the following:
Ensures that you are referencing the same button every time & not spawning new ones on each frame.