Ive been playing around with libgdx for the past couple of days and I wanted to see if someone could give a simple example of how a main menu screen is created with a start button and exit button.
LibGDX suggests to use its "scene2d" component if you need to build a UI.
The simplest example can be found on LibGDX's Wiki right in the article about scene2d:
https://libgdx.com/wiki/graphics/2d/scene2d/scene2d
Actually, the first code example from the wiki will do - it is a bit modified by me and shoud be added to your implementation of Screen or Game:
private Stage stage;
#Override
public void create () {
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
// Insert your UI elements here, for example:
Skin skin = new Skin(Gdx.files.internal("skin.json")); // https://libgdx.com/wiki/graphics/2d/scene2d/skin
Table menuContainer = new Table();
TextButton playButton = new TextButton("Play", skin);
playButton.addListener(new ClickListener() {
#Override
public void clicked (InputEvent event, float x, float y) {
// Called when player clicks on Play button
}
});
menuContainer.add(playButton);
TextButton exitButton = new TextButton("Exit", skin);
exitButton.addListener(new ClickListener() {
#Override
public void clicked (InputEvent event, float x, float y) {
// Called when player clicks on Exit button
}
});
menuContainer.add(exitButton);
}
#Override
public void resize (int width, int height) {
// See below for what true means.
stage.getViewport().update(width, height, true);
}
#Override
public void render () {
float delta = Gdx.graphics.getDeltaTime();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta);
stage.draw();
}
#Override
public void dispose () {
stage.dispose();
}
Related
My first problem is that the textfield is not showing up and the second is that the button is not responding. My idea is when image 'vault1' is touched the textfield should show 5.
This is what I have come up with and I can't figure out what I am doing wrong.
(I have only cut out neseccary code)
public void render(float delta) {
drawSprite("vault1", 600, 450);
}
public void show() {
Gdx.input.setInputProcessor(stage);
skin = new Skin(Gdx.files.internal("ui/menuSkin.json"), new TextureAtlas("ui/atlas.pack"));
vaultInput = new TextField("", skin);
vaultInput.setPosition(300, 250);
vaultInput.setSize(300, 40);
vaultInput.setText(text2);
vault1Button = new Image(vault1);
vault1Button.addListener(new ClickListener() {
public boolean touchDown(InputEvent e, float x, float y, int point, int button) {
System.out.println("133");
vaultInput.setText(score);
return false;
}});
}
private void drawSprite(String name, float x, float y) {
Sprite sprite = textureAtlas.createSprite(name);
sprite.setPosition(x, y);
sprite.draw(batch);
vault1 = sprite;
}
It's hard to tell when you've left out code but you are adding the stage to the input processor:
Gdx.input.setInputProcessor(stage);
The stage and actors added to the stage is now the only things that responds to input. But you are never adding anything to the stage and neither drawing the stage, you are drawing your sprites seperately in the drawSprite method.
If you instead add your button to the stage all you need to do is call stage.draw():
public void render(float delta) {
stage.draw();
stage.act(delta);
}
public void show() {
Gdx.input.setInputProcessor(stage);
skin = new Skin(Gdx.files.internal("ui/menuSkin.json"), new TextureAtlas("ui/atlas.pack"));
vaultInput = new TextField("", skin);
vaultInput.setPosition(300, 250);
vaultInput.setSize(300, 40);
vaultInput.setText(text2);
vault1Button = new Image(vault1);
vault1Button = new Image(vault1);
vault1Button.addListener(new ClickListener() {
public boolean touchDown(InputEvent e, float x, float y, int point, int button) {
System.out.println("133");
vaultInput.setText(score);
return false;
}});
vaultInput.setPosition(x1, y1);
vault1Button.setPosition(x2, y2);
stage.addActor(vaultInput);
stage.addActor(vault1Button);
}
Everything added to the stage will be drawn when calling stage.draw()
The value of the vault1 field is still null when show() is called. So your actual button that you added your listener to has zero size and nothing to draw.
Also, since render() is called continuously in the game loop, you are creating new sprites to draw on every frame and reassigning the vault1 variable every frame.
You need to create your image for the button in show() and add the button to the stage. Then you only need to draw the stage.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm new to java and libgdx and I want to create a main menu screen, Can someone give me a simple example?
What you are asking is very broad, it involves many elements like creating buttons, skins, setting up Tables, etc. Anyway you should use Screens for this, add a stage and add actors to the stage. Eventually you need to add Listeners to your button actors to switch screens. Here is one I made for you:
public class TestScreen implements Screen{
private SpriteBatch batch;
protected Stage stage;
private Viewport viewport;
private OrthographicCamera camera;
private TextureAtlas atlas;
protected Skin skin;
public TestScreen()
{
atlas = new TextureAtlas("skin.atlas");
skin = new Skin(Gdx.files.internal("skin.json"), atlas);
batch = new SpriteBatch();
camera = new OrthographicCamera();
viewport = new FitViewport(Constants.WorldWidth, Constants.WorldHeight, camera);
viewport.apply();
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
stage = new Stage(viewport, batch);
}
#Override
public void show() {
//Stage should controll input:
Gdx.input.setInputProcessor(stage);
//Create Table
Table mainTable = new Table();
//Set table to fill stage
mainTable.setFillParent(true);
//Set alignment of contents in the table.
mainTable.top();
//Create buttons
TextButton playButton = new TextButton("Play", skin);
TextButton optionsButton = new TextButton("Options", skin);
TextButton exitButton = new TextButton("Exit", skin);
//Add listeners to buttons
playButton.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
((Game)Gdx.app.getApplicationListener()).setScreen(new PlayScreen());
}
});
exitButton.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
Gdx.app.exit();
}
});
//Add buttons to table
mainTable.add(playButton);
mainTable.row();
mainTable.add(optionsButton);
mainTable.row();
mainTable.add(exitButton);
//Add table to stage
stage.addActor(mainTable);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(.1f, .12f, .16f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
viewport.update(width, height);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
skin.dispose();
atlas.dispose();
}
}
The way I call this is by changing the initial class a bit.
//Let the class extend from game
public class MyGame extends Game()
{
//Delete everything in it and leave a create() with a single line
#Override
public void create() {
setScreen(new MenuScreen());
}
}
Of course to make the above code work you need to setup a Skin and Atlas for drawing the buttons. You could however just add a image and a font and create your buttons manually. Anyway, I just answered a question where I go in depth on creating a Skin and Atlas.
Edit Although an example of a menu class has been asked the user asker actually just needed to know how to switch from screen to screen. A bit awkward but luckely writing the above code just took a couple of minutes ;).
You can always access the ApplicationListener from anywhere using Gdx.app.getApplicationListener. You can cast this to Game to access setScreen.
((Game)Gdx.app.getApplicationListener()).setScreen(new GameScreen());
Or you could pass along the initial Game object or applicationListener by hand. Make sure the new screen accepts the game object.
public class MenuScreen
{
private Game gameObject;
public MenuScreen(Game gameObject)
{
this.gameObject = gameObject;
}
private void someMethod()
{
//Switches to a new MenuScreen...
//useless in most cases but you get the idea
gameObject.setScreen(new MenuScreen(gameObject);
}
}
I am using Screen-2D to build a button. I want give the button a function when it is click a sprite will be drawn how can i do this. This isn't all all my code but enough to show what am talking about.
public void create () {
buttonStyle = new TextButtonStyle();
buttonStyle.up = skin.getDrawable("button");
buttonStyle.over = skin.getDrawable("buttonpressed");
buttonStyle.down = skin.getDrawable("buttonpressed");
buttonStyle.font = font;
button = new TextButton("START", buttonStyle);
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
button.addListener(new InputListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
drawTile(200,50);
return true;
}
});
}
// method used to draw a sprite when passing certain coordinates
public void drawTile(int x , int y) {
spriteBatch.draw(sprite, x , y );
}
public void render () {
Gdx.gl.glClearColor(1f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
spriteBatch.begin();
spriteBatch.draw(background, 0, 0);
drawGrid();
spriteBatch.draw(startButton, 0, 0);
stage.draw();
spriteBatch.end()
}
You got the right idea. See this example:
button.addListener(new ChangeListener() {
#Override
public void changed (ChangeEvent event, Actor actor) {
drawTile(200,50);
}
});
https://github.com/libgdx/libgdx/wiki/Scene2d.ui#changeevents
I think you need to read more tutorials about how LibGDX and Scene2D works : Event processing is done before your render method, so any drawing will be erased when you clear screen.
A right approach would be to add a sprite (as Drawable) to a widget group when click firing. Then stage rendering will renderer all your component including your sprites.
Comparaing to MVC pattern : The stage is your model, you modifiy your model when events occurs and the render method is the view of your model (draw your model).
I am having issues with libgdx sound inside a ClickListener for my button.
I am getting the error Syntax error on token "PlayButtonSound", Identifier expected after this token
SoundManager:
import utils.Constants;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
public class SoundManager {
private static Sound buttonSound = Gdx.audio.newSound(Constants.buttonSound);
private static Music song = Gdx.audio.newMusic(Constants.song);
public static void PlayMusic() {
song.setLooping(true);
song.setVolume(0.2f);
song.play();
}
public static void PlayButtonSound() {
buttonSound.play();
}
public void DestryoAudio() {
buttonSound.dispose();
song.dispose();
}
}
And MainMenu:
public class MainMenu implements Screen {
private Stage stage;
private Sprite sprite;
private TextureRegion menuBackgroundImg;
private TextureAtlas menuButton;
private Skin skin;
private BitmapFont font;
private Table table;
private TextButton playButton;
#Override
public void show() {
// Set stage
stage = new Stage();
Gdx.input.setInputProcessor(stage);
SoundManager.PlayMusic();
// Set menu baggrund
menuBackgroundImg = new TextureRegion(new Texture(Gdx.files.internal(Constants.menuBackgroundImg)));
sprite = new Sprite(menuBackgroundImg);
sprite.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Set menuknapper
menuButton = new TextureAtlas(Constants.menuButton);
skin = new Skin(menuButton);
// Set font
font = new BitmapFont(Constants.font, false);
// Set table
table = new Table(skin);
table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Create button styling
TextButtonStyle textButtonStyle = new TextButtonStyle();
textButtonStyle.up = skin.getDrawable("menuButtonUp");
textButtonStyle.down = skin.getDrawable("menuButtonPressed");
textButtonStyle.pressedOffsetX = 1;
textButtonStyle.pressedOffsetY = -1;
textButtonStyle.font = font;
textButtonStyle.fontColor = Color.BLACK;
// Create buttons
playButton = new TextButton(Constants.play, textButtonStyle);
playButton.addListener(new InputListener() {
SoundManager.PlayButtonSound(); // This is the error
});
// Button padding
playButton.pad(20, 100, 20, 100);
// Setting the table
table.add(playButton).row();
// Setting stage actor
stage.addActor(table);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Tegn baggrund
stage.getBatch().begin();
sprite.draw(stage.getBatch());
stage.getBatch().end();
// Tegn resten
stage.act(delta);
stage.draw();
}
...
#Override
public void dispose() {
stage.dispose();
menuButton.dispose();
skin.dispose();
font.dispose();
}
}
I can't really grasp what I am doing wrong and a search for the error gives vague answers that dosen't really solves my issue.
P.S. I have imported SoundManager but left it out due to length of the code snippet.
You need to implement one of the InputListener interface methods, most likely touchDown(InputEvent event, float x, float y, int pointer, int button).
Check out the API for InputListener. It lists all the methods and gives a pretty good example.
playButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
SoundManager.PlayButtonSound();
return false;
}
});
I've got a GameScreen where I have 100 "dots" randomly bounce around the screen. I'm currently adding a UI button in order to rotate the screen; one on the left and one on the right. The button works, however, the button is "linked" to the camera because as the screen rotates (the playing field for the dots spins because the camera rotates), the button rotates with it. I want the button(s) to be fixed to the device screen, and not rotate with the underlying field of dots.
Do I have to unproject the button somehow, or create a separate stage for any UI elements (buttons, statusbar title alone the top, etc)? Many thanks.
Here's my code:
public class GameScreen implements Screen {
final jGdxDots game;
final MyGestureListener myGestureListener;
OrthographicCamera camera;
private Skin skin;
final int NUMBER_OF_DOTS = 100;
int dotTotal;
private Stage stage;
FPSLogger fpsLogger;
float cameraRotate = 0f;
public GameScreen(final jGdxDots gam) {
this.game = gam;
fpsLogger = new FPSLogger();
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480); //boolean = YDOWN or YUP axis.
//create stage
stage = new Stage(Gdx.graphics.getWidth(),Gdx.graphics.getHeight(),true);
//set stage to handle the inputs
//Gdx.input.setInputProcessor(stage);
stage.setCamera(camera);
//stage.setViewport(800, 480, true);
//multiplex the gesture listeners (both for stage and my listener)
myGestureListener = new MyGestureListener();
GestureDetector gd = new GestureDetector(myGestureListener);
InputMultiplexer im = new InputMultiplexer(gd, stage); // Order matters here!
Gdx.input.setInputProcessor(im);
//UI button
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
final TextButton button = new TextButton("Rotate", skin, "default");
button.setWidth(100f); //200f
button.setHeight(100f); //20f
button.setPosition(10f, 10f);
button.addListener(new ClickListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
// TODO Auto-generated method stub
cameraRotate = 1f;
return super.touchDown(event, x, y, pointer, button);
}
#Override
public void touchUp(InputEvent event, float x, float y,
int pointer, int button) {
// TODO Auto-generated method stub
super.touchUp(event, x, y, pointer, button);
cameraRotate = 0f;
}
});
stage.addActor(button);
spawnDots(stage);
}
private void spawnDots(Stage theStage) {
//Rectangle raindrop = new Rectangle();
for (int i=0; i < NUMBER_OF_DOTS; i++) {
DotActor dot = new DotActor();
dot.setOrigin(8,8); //(dot.getWidth()/2, dot.getHeight()/2);
dot.vector.set(MathUtils.random(1,4), MathUtils.random(1,4));
dot.actorX = MathUtils.random(0, 800 - dot.getWidth());
dot.actorY = MathUtils.random(0, 480 - dot.getHeight());
stage.addActor(dot);
}
dotTotal = NUMBER_OF_DOTS;
}
#Override
public void dispose() {
stage.dispose();
}
#Override
public void render(float delta) {
//clear screen
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//logger
fpsLogger.log();
//camera.zoom += 0.005f;
camera.rotate(cameraRotate); //(1.0f);
camera.update();
//run act() method of each actor
stage.act(Gdx.graphics.getDeltaTime());
//run each actor's draw() method who are members of this stage
stage.draw();
}
}
I had this problem too. Create a separate stage, or you might just want to draw directly with a sprite batch in a 'renderer' class
Mine looks something like this:
public OverlayRenderer()
{
this.spriteBatch = new SpriteBatch();
this.loadTextures();
}
public void render(String _message)
{
this.spriteBatch.begin();
this.spriteBatch.draw(TEXTURES.UI, 0, 0);
....
}
and directly after your
stage.draw();
line, I would add
overLayRenderer.render();