GameStateManager LibGDX - 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());
}

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 ImageButton playing sound

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.

libgdx - wait to complete an action of an actor

My problem is I want an actor to do an action (in this case a fade) and just after the end of the action, switch to the game screen. But the action is finished not complete, but quickly changed the game screen.
I want to wait to complete this action before changing the screen .. And in general, I wonder how I can make waiting instructions in the game, because it is sometimes good to want to allow some time before anything happens.
myActor.addAction(Actions.fadeIn(2));
setScreen(AnotherScreen);
Use the static imports for actions, way easier.
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
Actor.addAction(sequence(fadeOut(2f), run(new Runnable() {
public void run () {
System.out.println("Action complete!");
}
});
Put the code you want to run in the runnable.
For more info,
https://github.com/libgdx/libgdx/wiki/Scene2d#actions
What you have to do is create an Action subclass and override Action#act where you will call setScreen(AnotherScreen);.
Then, use Actions#sequence to wrap both actions into a single SequenceAction object.
Action switchScreenAction = new Action(){
#Override
public boolean act(float delta){
setScreen(AnotherScreen);
return true;
}
};
myActor.addAction(Actions.sequence(
Actions.fadeIn(2)
, switchScreenAction
));
For more info, check out: https://github.com/libgdx/libgdx/wiki/Scene2d#complex-actions

Graphics plain 2D objects are not rendered while an action occurred

I am designing a game in Swing. Currently I am designing the maze for this game. The maze is generated by using Depth First Search algorithm. In my main JFrame, I have some JPanel. One JPanel, named mazePanel contains the maze. There are some other JPanel also, which contains the JButton for controlling. Following is the mazePanel code.
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class MazePanel extends JPanel {
private MazeGenerator mazeGenerator;
private boolean startNewMaze = false;
public MazePanel() {
setBorder(BorderFactory.createTitledBorder("Maze"));
setToolTipText("This is the maze");
}
public void addNewMaze() {
startNewMaze = true;
mazeGenerator = new MazeGenerator();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (startNewMaze) {
mazeGenerator.generate(g);
startNewMaze = false;
}
}
}
There is one JButton, which calls the method mazePanel.addNewMaze() and set the Boolean startNewMaze to true. After setting the startNewMaze, maze should be generated. i.e. mazeGenerator.generate(g) is inside if() condition. Method mazeGenerator.generate(g) recursively draw the random maze. That is why I don’t want to run this method not more than once.
Up to this everything is looking fine. But while I am running the main JFrame and clicks on the JButton, maze is not rendered in the mazePanel. Sometimes when I minimize and maximize the JFrame, maze rendered (might be because of repaint() occur). Even if I comment mazeGenerator.generate(g) inside if() condition and put some g.drawString(). The string is not rendered while action performed (i.e.Pressing JButton).
Where is the problem? Please help.
Thank you.
So basically you have a JPanel which contains nothing, you call a method unknown to Swing and expects the paintComponent method is magically called when you change the state of a private field.
You already discovered that minimizing and maximizing again solves your problem due to a repaint. That should be sufficient information to know you have to trigger a repaint yourself when you press that button.
If you would have followed the suggestion from #kleopatra to, and I quote,
change the state and then trigger the revalidation/painting
you would already have solved your problem

removing mouse events/controls from swing components with glasspane

I have a client-server application and i am using swing in the client side. My swing client has one main window (jframe) and lots of panels, toolbars and menubar in it.
I want to remove all client action/mouse events (or simply grab and do nothing) while client is waiting response from server by means of glasssPane.
Here is the code i wrote:
private final static MouseAdapter mouseAdapter = new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("MouseClicked..!");
}
};
private static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
and
public static void startWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(WAIT_CURSOR);
root.getGlassPane().addMouseListener(mouseAdapter);
root.getGlassPane().setVisible(true);
}
public static void stopWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(DEFAULT_CURSOR);
root.getGlassPane().setVisible(false);
}
but i am not able to manage the grab mouse events. Changing cursors at the glassPane is working fine but either i am not able to add mouseAdapter or am not able to make glasssPane become to the top level component.
Any idea?
Thanks.
I realized that my code is working but my problem is threading related. My code was something like:
startWaitCursor();
work(); // server request that takes time
stopWaitCursor();
and changed it to:
startWaitCursor();
SwingUtilities.invokeLater(new Runnable() {
poblic void run() {
try
{
work(); // server request
}
finally
{
stopWaitCursor();
}
by doing this modification i could see the settings i made in the startWaitCursor() method while client is waiting response from the server.
But stil there is a small problem. In startWaitCursor() method i desabled key, mouse and focus events for the glass pane but events are still captured by main frame even glassPane is displayed.
addMouseListener(new MouseAdapter() {});
addMouseMotionListener(new MouseMotionAdapter() {});
addKeyListener(this);
setFocusTraversalKeysEnabled(false);
After server response reached to client and stopWaitCursor() method is invoked the events handled in the main frame.
If i disable the main frame of my application while client is waiting than cursor is not being changed to wait_cursor, if i am not disable the main frame then cursor is being changed but the events are queued.
cheers...
After digging swing threads issues couple of days, i finally found the real answer: SwingWorker
Now my final code is something like,
startWaitCursor();
SwingWorker worker = new SwingWorker() {
public Object doInBackground()
{
doWork(); // time consuming server request
return null;
}
public void done()
{
stopWaitCursor();
}
};
worker.execute();
In startWaitCursor() method i set the glasspane visible (with alpha valued background), display a message to warn the user time consuming job is doing, set the cursor to wait_cursor (hourglass) and consume all the key, mouse events. That is it.
And by using SwingWorker my client is actually responsive (it is working as if no server request is made) but since i display the glasspane and consume all key and mouse events it feels like irresponsive.
What a relief.. SwingWorker rocks...
cheers..