How to create libgdx main menu screen [closed] - java

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);
}
}

Related

How to create a main menu using libgdx and java

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

problems with multiple cameras and viewports in libgdx

so I am doing what is suppose to be a simple game but I think I might be complicating things. I have a camera for the GameScreen and a viewPort which follow the position of the player and when it reaches to points on the sides, the camera stops following the player and stays in one point.
This by itself works fine, but then I wanted to add the pause menu and some other features in the game, creating a hud class with its own camera and viewport as well as a Stage and a shapeRenderer.
The problem comes when I create the instance of this hud inside my gameScreen, the camera that I am looking while I am playing looks like is the hudCam, which does not follow the player and basically does not let me see the player when it reaches the edges of the screen.
This is my GameScreen Class:
public class GameScreen implements Screen {
WowInvasion game;
ScrollingBackground background;
private OrthographicCamera gameCam;
private Viewport gameViewPort;
/*
Basically I wanna keep the same sprites running while in the menu, playing and till dead
therefore, I'll have a switch statement with cases on where the games at, inside the functions needed. That way I'll keep
the game has a background for the menu and there's no need for running a second screen.
*/
public static final int MAIN_MENU = 0;
public static final int GAME = 1;
private static int state = 1; //current state. starts with MAIN_MENU //DEBUGGING GAME SCREEN
//STAGES
private GameStage gameStage; //game ui
private menuStage mainMenu; //Main menu of the game
private Hud hud;
//Resources
private TextureAtlas atlas; //for the textures most
private Skin skin; //for the styles and fonts
//Sprites
private Player player;
//Shapes
private float progressPower; //for the power to build up
private final float POWER_CHARGED = 1000; //limit to get power
private final float DECREASING_POWER = 20; //limit to get power
public GameScreen(WowInvasion game){
this.game = game;
gameCam = new OrthographicCamera();
gameCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
gameViewPort = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, gameCam);
progressPower = 0f;
game.wowAssetManager.loadTexturesGameScreen(); // tells our asset manger that we want to load the images set in loadImages method
game.wowAssetManager.loadSkins(); //load the needed skins
game.wowAssetManager.manager.finishLoading(); // tells the asset manager to load the images and wait until finsihed loading.
skin = game.wowAssetManager.manager.get("ui/menuSkin.json");
}
#Override
public void show() {
game.batch.setProjectionMatrix(gameCam.combined);
background = new ScrollingBackground();
atlas = game.wowAssetManager.manager.get(WowAssetManager.GAME_ATLAS); //declaring atlas
mainMenu = new menuStage(gameViewPort, game.batch, skin, game); //pass it so that we only use one batch and one same viewport
gameStage = new GameStage(gameViewPort, game.batch, skin, game);
hud = new Hud(game.batch, skin);
player = new Player(atlas.findRegion("player"), (int) gameCam.viewportWidth / 2, (int) gameCam.viewportHeight / 2);
switch(state){
case MAIN_MENU:
Gdx.input.setInputProcessor(mainMenu);
break;
case GAME:
background.setFixedSpeed(false); //does not work in here
}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(state == GAME) {
background.setFixedSpeed(false);
player.update(delta, gameCam.viewportWidth, gameCam.viewportHeight); //updating player for movement
//really cheap way to charge power with velocity
if(progressPower != POWER_CHARGED) {
progressPower += Math.abs(player.getVelocity().x) + Math.abs(player.getVelocity().y);
progressPower -= DECREASING_POWER;
}
else
progressPower = POWER_CHARGED / 4;
}
mainMenu.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); //updating while making sure delta won't be more than 1/30f.
gameStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
game.batch.begin();
background.updateAndRender(delta, game.batch); //updating scrolling background
player.draw(game.batch);
game.batch.end();
mainMenu.draw(); //draw the menu stage
gameStage.draw(); //draw the ui stage for the game
hud.getStage().draw();
hud.renderRotateMeter();
updateCamera(0, WowInvasion.WIDTH);
System.out.println(player.getPosition().x);
}
public void updateCamera(float startX, float endX){
Vector3 position = gameCam.position;
//linear interpolation : a + (b - a) * lerp
//b = player position
//a = current camera position
//lerp = interpolation factor
position.x = gameCam.position.x + (player.getPosition().x - gameCam.position.x) * .1f;
//making the camera stay when the player gets to close to the sides
if(position.x < startX) {
position.x = startX;
}
if(position.x > endX){
position.x = endX;
}
gameCam.position.set(position);
gameCam.update();
}
#Override
public void resize(int width, int height) {
gameViewPort.update(width, height);
//hud.getViewport().update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
mainMenu.dispose();
gameStage.dispose();
game.dispose();
hud.dispose();
}
public static void setState(int state) {
GameScreen.state = state;
}
}
And this is my HUD:
public class Hud implements Disposable{
private Stage stage;
private Viewport viewport;
Button buttonPause, buttonResume;
private OrthographicCamera hudCam;
private ShapeRenderer sp; //like a batch for shapes
public Hud(SpriteBatch sb, Skin skin){
hudCam = new OrthographicCamera();
hudCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
viewport = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, hudCam);
stage = new Stage(viewport, sb);
sp = new ShapeRenderer();
Table table = new Table();
table.top();
//this makes the table the size of the stage
table.setFillParent(true);
buttonPause = new Button(skin, "pause");
buttonPause.setTransform(true);
buttonPause.addListener(new ClickListener(){ //listener to handle event
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
buttonResume = new Button(skin, "resume");
buttonResume.setTransform(true);
buttonResume.setScale(0.5f);
buttonResume.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
buttonResume.setVisible(false);
}
});
table.add(buttonPause);
table.row();
table.add(buttonResume);
stage.addActor(table);
}
public void renderRotateMeter(){
sp.setProjectionMatrix(hudCam.combined);
sp.begin(ShapeRenderer.ShapeType.Filled);
sp.setColor(Color.YELLOW);
sp.rect(hudCam.position.x,hudCam.position.y, WowInvasion.WIDTH / 2, 20);
sp.end();
}
public Viewport getViewport() {
return viewport;
}
public Stage getStage() {
return stage;
}
#Override
public void dispose() {
stage.dispose();
sp.dispose();
}
}
thanks in advance!
EDIT
so I tried passing the gameCam has a parameter to the hud and instead of making a new OrthographicCamera I used that one has the hudCamara as well and well, the movement with the player is perfect except now the thins from the Hud do not move at all..
It looks like you only set projectionMatrix to only HUD camera as seen in
sp.setProjectionMatrix(hudCam.combined);
Try to set it the same to other stuff outside of the HUD class prior to draw call too.
Another thing to keep in mind is that, when you involve using multiple Viewport and Camera in the game as most of the time it will be 1 Viewport matching with 1 Camera and work with another set as in your case. In draw call, you need to call apply() or apply(true) of Viewport class too to tell the system that you will draw based on which viewport thus in turn it will adhere to screen coordinate that was set up by viewport's attaching camera.
So assume you have 2 objects that needed to be called in different viewport consecutively, do it like the following code. The methods call is correct according to libgdx API but variable names are fictional.
// draw objA adhering to viewportA (thus cameraA) <-- assume it's player cam
sb.setProjectionMatrix(cameraA.combined);
viewportA.apply();
objA.draw();
// draw objB adhering to viewportB (thus cameraB) <-- assume it's HUD cam
sb.setProjectionMatrix(cameraB.combined);
viewportB.apply(true); // send in true as for HUD, we always want to center the screen
objB.draw();
In summary, 2 things to keep in mind when drawing objects that use multiple of camera and viewport in consecutive draw call.
Set projection matrix to either SpriteBatch or ShapeRenderer.
Call apply() or apply(true) of Viewport class to let it know you work with this viewport.

Libgdx Switching Screens and Viewports

I am having an issue when switching screens in libgdx. I am building a asteroids game clone. So first my MainMenuScreen class (which uses a Fitviewport) is rendered and then I call setScreen() to GameScreen (GameScreen doesn't use a Fitviewport) and that works except that the second screen renders as if its using a Fitviewport. If I resize the second screen then the whole window is used for rendering. Why is this happening? Here are some pictures:
MainMenuScreen class:
GameScreen class after switching screens, the screen has black bars on the side (I colored the boundary in red for you) which I don't want:
I want the GameScreen to use all the window area for rendering, and not have black bars like the MainMenu. I am not using any Fitviewport in GameScreen also.
Here are relevant parts of my MainMenuScreen class:
public class MainMenuScreen implements Screen
{
private static final String TAG = "MainMenu";
private static final int VIRTUAL_WIDTH = 400;
private static final int VIRTUAL_HEIGHT = 400;
MyGdxGame game;
...
public MainMenuScreen(MyGdxGame game)
{
this.game = game;
viewport = new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
stage = new Stage(viewport);
// Play button listener
btnPlay.addListener( new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
Gdx.app.log(TAG, "PLAY");
MainMenuScreen.this.game.setScreen(MainMenuScreen.this.game.gameScreen);
};
});
....
}
Here is my GameScreen class:
MyGdxGame game;
OrthographicCamera guiCam;
World world;
WorldRenderer renderer;
public GameScreen(MyGdxGame game, SpriteBatch batch)
{
this.game = game;
guiCam = new OrthographicCamera(400, 400);
guiCam.position.set(400 / 2, 400 / 2, 0);
world = new World();
renderer = new WorldRenderer(game, batch, world);
}
public void draw()
{
GL20 gl = Gdx.gl;
gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
}
#Override
public void show()
{
world.createLevel();
}
#Override
public void render(float delta)
{
draw();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
#Override
public void hide()
{
}
#Override
public void dispose()
{
}
The problem is this line of code:
public void resize(int width, int height)
{
viewport.update(width, height, true);
}
Whenever you update the viewport, you are also updating the underlying opengl viewport and this causes the black bars to persist to the second screen (https://github.com/libgdx/libgdx/wiki/Viewports). Thus if you want to reset it back to normal you must use the following line of code in your second screen show() method (https://github.com/libgdx/libgdx/wiki/Scene2d):
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

How to add child image to sprite in Libgdx as we can do in Cocos2d?

While i was learning about Libgdx i came across this problem of adding a child sprite to parent sprite in Libgdx as i did the same in Cocos2d it had no problem of doing it.
How can the same be achieved in Libgdx, so that i can perform operation on parent sprite and it will be followed by the child added to it.
EDIT : I have seen at https://github.com/libgdx/libgdx/wiki/Scene2d of scene2d, but they havn't mentioned how to make use of Group.
This is what i tried earlier but its coming white screen
public class TestScreen implements Screen{
private MainGame game;
private Sprite sprite;
public Group group;
private Stage stage;
private SpriteBatch batch;
public TextureAtlas atlas1;
public Skin skin;
public Image bg;
public Sprite sprite1;
public TestScreen(MainGame game)
{
this.game=game;
group = new Group();
batch = new SpriteBatch();
circle=AssestLoader.circle1;
}
#Override
public void render(float delta)
{
// TODO Auto-generated method stub
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(delta);
batch.begin();
stage.addActor(group);
batch.end();
}
#Override
public void show() {
// TODO Auto-generated method stub
atlas1 = new TextureAtlas("test/gamescreentest.pack");
skin = new Skin();
skin.addRegions(atlas1);
bg = new Image();
bg.setDrawable(skin, "playbg_hdpi");
bg.setHeight(460f);
bg.setWidth(460f);
group.addActor(bg);
}
#Override
public void hide() {}
#Override
public void resize(int width, int height) {}
#Override
public void pause() {}
#Override
public void resume() {}
#Override
public void dispose() {}}
Its coming white screen without image
You could use scene2d and actors (https://github.com/libgdx/libgdx/wiki/Scene2d). But this would require you to (maybe) rewrite parts of your application.
If your images are static and don't change I'd recommend you to draw the child ontop of the parent using a framebuffer. That'd be best in case of performance.
EDIT: The blog post at http://www.gamefromscratch.com/post/2013/12/11/LibGDX-Tutorial-3C-Scene-management.aspx has a very good example of groups.

Low framerate on simple libgdx example in desktop application

I just started learning libGDX, and was following the example from http://steigert.blogspot.in/2012/02/2-libgdx-tutorial-game-screens.html (the second link on libGdx help page).
As of now, I just display a logo of 512x512. There is nothing else happening in the application but when I run the application in desktop mode,I get a FPS of 15-16. When I remove the image, I get 60fps for the blank screen. For android its even worse, I get 3-4 fps in Galaxy SL - GT-i9003 (Temple Run runs on playable speed on the device).
My laptop plays World of Warcraft without any hiccups in high quality so its baffling that such a small app would only achieve 15fps.
public class SplashScreen extends AbstractScreen {
private Texture splashTexture;
private TextureRegion splashTextureRegion;
public SplashScreen(MyGDXGame game){
super(game);
}
#Override
public void show()
{
super.show();
// load the splash image and create the texture region
splashTexture = new Texture("splash.png");
// we set the linear texture filter to improve the stretching
splashTexture.setFilter( TextureFilter.Linear, TextureFilter.Linear );
// in the image atlas, our splash image begins at (0,0) at the
// upper-left corner and has a dimension of 512x301
splashTextureRegion = new TextureRegion( splashTexture, 0, 0, 512, 382 );
}
#Override
public void render(float delta ) {
super.render( delta );
// we use the SpriteBatch to draw 2D textures (it is defined in our base
// class: AbstractScreen)
batch.begin();
// we tell the batch to draw the region starting at (0,0) of the
// lower-left corner with the size of the screen
batch.draw( splashTextureRegion, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight() );
// the end method does the drawing
batch.end();
}
#Override
public void dispose()
{
super.dispose();
splashTexture.dispose();
}
}
Here is the relevant section of AbstractScreen class:
public class AbstractScreen implements Screen {
protected final MyGDXGame game;
protected final BitmapFont font;
protected final SpriteBatch batch;
public AbstractScreen(MyGDXGame game ){
this.game = game;
this.font = new BitmapFont();
this.batch = new SpriteBatch();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor( 0f, 0f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
}
...
}
And the desktop app:
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "First Game";
cfg.useGL20 = false;
cfg.width = 800;
cfg.height = 480;
new LwjglApplication(new MyGDXGame(), cfg);
}
MyGDXGame is as follows:
public class MyGDXGame extends Game {
private FPSLogger fpsLogger;
public SplashScreen getSplashScreen() {
return new SplashScreen( this );
}
#Override
public void create() {
fpsLogger = new FPSLogger();
}
#Override
public void dispose() {
super.dispose();
}
#Override
public void render() {
super.render();
setScreen(getSplashScreen());
fpsLogger.log();
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
super.resume();
}
I have read so many good things about libGdx, so this issue seems baffling to me. What am I doing wrong to get such a low frame rate?
I think setScreen(getSplashScreen()); in your render() method might be the problem. Move it to the create() method of MyGDXGame.
Right now you are switching the screen in every single frame and recreate a SpriteBatch every single time which is a very heavy object (see my comment to your question).

Categories

Resources