At this moment I have 2 screens: MainScreen (it's the main menu of the game) and GameScreen. I have a "button" (it's an image) that when the user clicks on it, the MainScreen switchs to the GameScreen.
The problem is that all the images of the MainScreen don't disappear when the second screen appears (the button and the main title). I have been working on this for days and I don't know what more to do.
Main class of the game:
public class MyGame extends Game {
#Override
public void create () {
Sounds.load();
Texts.load();
Buttons.load();
setScreen(new MainScreen(this));
}
#Override
public void dispose () {
super.dispose();
Sounds.dispose();
Texts.dispose();
Buttons.dispose();
}
}
MainScreen:
public class MainScreen implements Screen {
private MyGame game;
private Stage stage;
private OrthographicCamera camera;
private Viewport viewport;
public static Image tituloPrincipal, botonPlay;
public MainScreen(final MyGame game) {
this.game = game;
//stage
camera = new OrthographicCamera(Settings.SCREEN_WIDTH, Settings.SCREEN_HEIGHT);
viewport = new StretchViewport(Settings.SCREEN_WIDTH, Settings.SCREEN_HEIGHT, camera);
stage = new Stage(viewport);
//background
stage.addActor(new Image(Sprites.mainBackground));
//Title of the game
tituloPrincipal = new Image();
tituloPrincipal.setPosition(Settings.SCREEN_WIDTH * 1 / 6, Settings.SCREEN_HEIGHT * 4 / 12);
tituloPrincipal.setDrawable(new TextureRegionDrawable(new TextureRegion(Texts.tituloPrincipal)));
tituloPrincipal.setSize(Texts.tituloPrincipal.getWidth()/3,
Texts.tituloPrincipal.getHeight()/3);
stage.addActor(tituloPrincipal);
//Play Button
botonPlay = new Image();
botonPlay.setPosition(Settings.SCREEN_WIDTH * 4 / 10, Settings.SCREEN_HEIGHT / 16);
botonPlay.setDrawable(new TextureRegionDrawable(new TextureRegion(Buttons.playbutton)));
botonPlay.setSize(Buttons.playbutton.getWidth()/16,
Buttons.playbutton.getHeight()/18);
stage.addActor(botonPlay);
//Song
Sounds.musicMainScreen.play();
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
botonPlay.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new GameScreen(game));
dispose();
}
});
stage.draw();
stage.act(delta);
}
#Override
public void resize ( int width, int height){
}
#Override
public void pause () {
}
#Override
public void resume () {
}
#Override
public void hide () {
}
#Override
public void dispose () {
}
}
GameScreen:
public class GameScreen implements Screen {
private Game game;
private Stage stage;
public GameScreen(Game game) {
this.game = game;
stage = new Stage();
Gdx.input.setInputProcessor(stage);
deleteMainScreenSources();
//song
Sounds.musicGameScreen.play();
}
public void deleteMainScreenSources() {
Sounds.musicMainScreen.stop();
}
#Override
public void show() {
}
#Override
public void render(float delta) {
}
#Override
public void resize ( int width, int height){
}
#Override
public void pause () {
}
#Override
public void resume () {
}
#Override
public void hide () {
}
#Override
public void dispose () {
}
}
Button class:
public class Buttons {
public static Texture playbutton;
public static void load() {
playbutton = new Texture(Gdx.files.internal("playbutton.png"));
playbutton.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
}
public static void dispose() {
playbutton.dispose();
}
}
The class of the title it's like the class of the button.
Your render method is what draws your screen. If you are not aware, it is kind of a game loop , which gets executed non stop ( around 60/sec by default I believe). So all your drawing and redrawing goes here.Usually , you would be clearing your screen at first and then draw other images on the screen. Libgdx provide interfacing to opengl to clear the screen. In my case, I always clear screen at the very first line of render method and draw additional things on it so that it makes sure my stale content of the screens are gone.In your GameScreen , your render method is empty , so your previous screen is not yet wiped out. I believe adding clear and drawing your new stage in GameScreen will resolve your issue.
Make your code in GameScreen render something like this and try ,
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
Also, I would try to avoid creation of any new object in 'render` method for the same reason. Your addListener method in your menu screen can go in it's constructor. So that you don't create anonymous listener in every game loop execution. This may not impact by that much in your current scenario, but if you create some heavy object or some Sprites in this way in game loop, that can drag your game perfomance a lot.
Related
I'm programming a libgdx game, but it is not showing splash screen immediately after the game launches. I'm using asset manager to load resources in the background. does anyone know how this comes?
It only shows a black screen when game launches then after 5-6 seconds when assets loaded in the memory it shows splash screen for a second then he main screen.
Here are my classes.
public class SplashScreen implements Screen {
private SpriteBatch batch;
private Texture logo;
private BabyGame game;
private MyAssetManager myAssetManager;
public SplashScreen(BabyGame game) {
this.game = game;
myAssetManager = new MyAssetManager();
}
#Override
public void show() {
batch = new SpriteBatch();
logo = new Texture("bg.png");
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.8f, 0.8f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(logo,0,0,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
batch.end();
if (myAssetManager.update())
game.setScreen(new BabyOrange(game));
}
Here is Game class
public class BabyGame extends Game
{
AdService adService;
MyAssetManager assetManager;
public BabyGame(){
assetManager = new MyAssetManager();
}
#Override
public void create() {
setScreen(new SplashScreen(this));
}
}
and the asset class
public class MyAssetManager {
public AssetManager manager;
public MyAssetManager(){
manager = new AssetManager();
}
public void load(){
manager.load("background-orange.png",Texture.class);
manager.load("orange-phone.png",Texture.class);
manager.load("buttons.txt", TextureAtlas.class);
manager.load("bgAudio.mp3", Music.class);
manager.finishLoading();
}
public boolean update(){
return manager.update();
}
}
You can add Handler() Method in :
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(SplashActivity.this,MainActivity.class));
finish();
}
}, 1000);
And also please check the size of the images.
I'm making a simple 2D game in LibGDX. This is my first project with it.
On my phone everything works fine, nothing bad (6.0.1), but on other phones (no matter what version) it doesn't work. It's clear that the render method doesn't work, but I don't know why. I've tried to add super.render(); but it made it red, so it's not working or I've made some mistake.
This is a menu screen, what comes first. It works fine, than I play and die, than I call it again and it crashes.
public class MenuScreen implements Screen {
private DualisAutosapp game;
private OrthographicCamera camera;
...
public MenuScreen(DualisAutosapp game)
{
super();
Gdx.app.log("Menu","Started");
this.game = game;
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.app.log("Menu","Camera");
logoTexture = new Texture(Gdx.files.internal("background.png"));
logoTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
logo = new Sprite(logoTexture);
Gdx.app.log("Menu","Background");
startTexture = new Texture(Gdx.files.internal("start.png"));
startTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
start = new Sprite(startTexture);
Gdx.app.log("Menu","Start");
carChooseTexture = new Texture(Gdx.files.internal(prefs.getString("playercar", "player/mazda2.png")));
carChooseTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
carChoose = new Sprite(carChooseTexture);
Gdx.app.log("Menu","Car");
font = new BitmapFont(Gdx.files.internal("font/joystix_monospace.fnt"), Gdx.files.internal("font/joystix_monospace.png"), false);
batch = new SpriteBatch();
Gdx.app.log("Menu","batch");
calculateSpriteLocation(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
Gdx.app.log("Menu","calculate");
}
#Override
public void show() {
}
#Override
public void resize(int width, int height) {
camera = new OrthographicCamera();
camera.setToOrtho(false,Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
calculateSpriteLocation(width,height);
}
#Override
public void render (float delta) {
Gdx.app.log("Menu","render");
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
...
}
#Override
public void resume() {
Gdx.app.log("Menu","Rizjúm");
carChooseTexture = new Texture(Gdx.files.internal(prefs.getString("playercar", "player/mazda2.png")));
carChooseTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
carChoose = new Sprite(carChooseTexture);
}
#Override
public void hide() {
}
private void calculateSpriteLocation(int width, int height)
{
logo.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
logo.setPosition(width/2-logo.getWidth()/2, height/2-logo.getHeight()/2);
start.setSize(Gdx.graphics.getWidth()/3.6f, Gdx.graphics.getHeight()/6.4f);
start.setPosition(width/2-start.getWidth()/2, height/2-start.getHeight()/2);
carChoose.setSize(Gdx.graphics.getWidth()/3.6f, Gdx.graphics.getHeight()/6.4f);
carChoose.setPosition(width/2-carChoose.getWidth()/2, height/10-carChoose.getHeight()/2);
}
}
Everything is ok until the log of the render where it crashes.
EDIT
Game Class
public class DualisAutosapp extends Game {
#Override
public void create () {
showMenuScreen();
}
public void switchScreen(Screen newScreen){
Screen previousScreen = getScreen();
setScreen( newScreen );
if (previousScreen != null)
{
previousScreen.dispose();
}
}
public void showMenuScreen()
{
switchScreen(new MenuScreen(this));
}
public void showGameScreen()
{
switchScreen(new GameScreen(this));
}
public void showCarChangeScreen() {
switchScreen( new CarChange(this));
}
}
First of all I'll recommend you to follow Life cycle method of Game/Screen of Libgdx API. If you not override lifecycle method of Game then it call Screen corresponding method.
You're initialize your objects whenever you want but it's not a good way. It's better to initialize all your screen object inside show method of Screen Interface.
Create object's of all screens inside Game class at once and only use that object in setScreen(screen) method.
#Override
public void show() {
..//create objects
}
Use dispose() method and destroy objects that you created in show().
Method resize() can be used to update viewport of camera with device size.
Use pause() and resume() according to your requirement like music pause but not for object initialization.
Well,i think you should not pass Game class to screen constructors every time, and you could try something like this for screen management.
import com.badlogic.gdx.Screen;
public enum MyScreens {
GAME_SCREEN {
public Screen getScreenInstance() {
return new GameScreen();
}
},
MAIN_MENU {
public Screen getScreenInstance() {
return new MainMenu();
}
},
SPLASH_SCREEN {
public Screen getScreenInstance() {
return new SplashScreen();
}
};
public abstract Screen getScreenInstance();
}
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.utils.IntMap;
public class ScreenManager {
private static ScreenManager instance;
private Game game;
private IntMap<Screen> screens;
private ScreenManager() {
screens = new IntMap<Screen>();
}
public static ScreenManager getInstance() {
if (instance == null) {
instance = new ScreenManager();
}
return instance;
}
public void initialize(Game game) {
this.game = game;
}
public void show(MyScreens screen) {
if (game == null) {
return;
}
if (!screens.containsKey(screen.ordinal())) {
screens.put(screen.ordinal(), screen.getScreenInstance());
}
game.setScreen(screens.get(screen.ordinal()));
}
public void dispose(MyScreens screen) {
if (!screens.containsKey(screen.ordinal())) {
return;
}
screens.remove(screen.ordinal()).dispose();
}
public void dispose() {
for (Screen screen : screens.values()) {
screen.dispose();
}
screens.clear();
instance = null;
}
}
I'm developing a new application with libgdx and in my source code i'm using the shaperenderer class but since I've bought my new tablet (Acer Iconia One 10 B3-A20), my application always crash without displaying any errors after calling the "shaperenderer.end()" method . Even when I create a simple class as the following one, have I missing something?
public class Test implements Screen {
private ShapeRenderer shapeRenderer = new ShapeRenderer();
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.rect(30,30,200,200);
shapeRenderer.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
shapeRenderer.dispose();
}
}
Thanks
EDIT:
After placing some breakpoints into the "shaperenderer.end()"method i have noticed that the program crash after calling the "mesh.render()" method, and particularly when it call the "bind" method of the Mesh class (for binding the shaders).
Is it normal?
You need to create a camera first on your show method:
OrthographicCamera camera;
[...]
camera = new OrthographicCamera();
camera.setToOrtho(false);
and on render method set the projectionMatrix before draw:
camera.update();
shapeRenderer.setProjectionMatrix(camera.combined);
In my game I have currently two screens. The MenuScreen and the GameScreen. Through the Play option in the menu the player can switch to the GameScreen and start the Gameplay and with Escape he can get back to the MenuScreen. I dispose the used Assets when I switch to the other Screen in the hide() method and load the needed Assets for the new Screen in the constructor of the Screen I switch to. The problem is that the Textures and Sound Effects aren't rendered/played when I switch back.
For example when I start the game in the MenuScreen, then switch to the GameScreen everything is fine. But when I switch back to the MenuScreen the MenuScreen is just a black window. When I then switch to the GameScreen again it's black too except for the BitmapFont.
Maybe there is a fundemental flaw in the way I handle this. I tried to leave out as much unnecessary things as I can from the code I post here, but I fear that it's still too much.
RessourceLoader Class:
public class RessourceLoader {
public static AssetManager manager;
public static void create() {
manager = new AssetManager();
}
public static void loadMenuScreen() {
manager.load("gfx/menuBackground.png", Texture.class);
}
public static void getMenuScreen() {
menuBackground = manager.get("gfx/menuBackground.png", Texture.class);
}
public static void disposeMenuScreen() {
menuBackground.dispose();
}
public static void loadGameScreen() {
// load GameScreen Assets through AssetManager
}
public static void getGameScreen() {
// get GameScreen Assets through AssetManager
}
public static void disposeGameScreen() {
// dispose all GameScreen Assets
}
public static void dispose() {
manager.dispose();
}
}
MenuScreen Class:
public class MenuScreen implements Screen {
// Game starts in the MenuScreen
// Instance of game
private PHGame game;
// Orthographic camera
private OrthographicCamera cam;
public MenuScreen(PHGame phGame) {
game = phGame;
RessourceLoader.loadMenuScreen();
RessourceLoader.manager.finishLoading();
RessourceLoader.getMenuScreen();
cam = new OrthographicCamera();
cam.setToOrtho(true, 640, 480);
game.batcher.setProjectionMatrix(cam.combined);
}
#Override
public void render(float delta) {
// Fills background with black to avoid flickering
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Begin Drawing
game.batcher.begin();
// Draw Menu
// Stop drawing
game.batcher.end();
// Pressing Space confirms currently selected menu item
if (GameKeys.isPressed(GameKeys.SPACE)) {
game.setScreen(new GameScreen(game));
}
// Update Key Presses
GameKeys.update();
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
RessourceLoader.disposeMenuScreen();
}
}
GameScreen Class:
public class GameScreen implements Screen {
// Instance of game
private PHGame game;
private GameWorld world;
private GameRenderer renderer;
private float runTime;
public GameScreen(PHGame phGame) {
game = phGame;
RessourceLoader.loadGameScreen();
RessourceLoader.manager.finishLoading();
RessourceLoader.getGameScreen();
world = new GameWorld(game, this);
renderer = new GameRenderer(world, game);
}
#Override
public void render(float delta) {
// runTime is the amount of time the game is running
runTime += delta;
// Updates the Game World
world.update(delta);
// Renders everything
renderer.render(runTime);
// Update Key Presses
GameKeys.update();
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
RessourceLoader.disposeGameScreen();
}
}
GameRenderer Class:
public class GameRenderer {
// Instance of PHGame
PHGame game;
// Instance of Game World
private GameWorld world;
// Orthographic Camera
private OrthographicCamera cam;
// If true hitbox's will be shown
private boolean showHitbox;
// Game Objects
private Player player;
public GameRenderer(GameWorld world, PHGame game) {
this.game = game;
this.world = world;
player = world.getPlayer();
cam = new OrthographicCamera();
cam.setToOrtho(true, 640, 480);
showHitbox = false;
game.batcher.setProjectionMatrix(cam.combined);
}
public void render(float runTime) {
// draw objects and hud
}
}
If there are any questions regarding my problem I'll try to answer then as good as I can.
Refer to the github article 'managing your assets'. AssetManagers should not be static. 'This typically would cause black/missing textures or incorrect assets.'
After you dispose your asset manager it can no londer be used. Instead use manager.unload to unload assets. manager.unload("gfx/menuBackground.png");
EDIT:
I also didn't see any overriden show() methods. If you want your assets back you will need to load your assets in the screen's show method every time.
So i want to create a mainmenu for my game and i'm stuck on what to do next i have all the art done and it's all in layers and packed in a .pack
public class MainMenu implements Screen {
CrazyZombies game;
Stage stage;
BitmapFont font;
TextureAtlas MainMenu;
Texture road;
Skin skin;
SpriteBatch batch;
public MainMenu(CrazyZombies game){
this.game = game;
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(0.09f, 0.28f, 0.2f, 1);
stage.act(delta);
batch.begin();
stage.draw();
batch.end();
}
#Override
public void resize(int width, int height) {
if(stage == null)
stage = new Stage(width, height, true);
stage.clear();
Gdx.input.setInputProcessor(stage);
}
#Override
public void show() {
batch = new SpriteBatch();
skin = new Skin();
MainMenu = new TextureAtlas("data/mainmenu/MainMenu.pack");
}
#Override
public void hide() {
dispose();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
batch.dispose();
skin.dispose();
MainMenu.dispose();
stage.dispose();
}
}
If anyone could give me some guidelines or tutorials on what to do now it would be great i've looked in a lot of places but they have not given me the required answers.
Have a look at this tutorial which sums up what you want exactly:
LibGDX: Using a Splash Screen or Menu
i think it will be easy if u use scene2D that will handle all the complexity and help you to create a nice looking UI with a little bit of code .
you may need to check this link
https://github.com/libgdx/libgdx/wiki/Scene2d.ui
Basically, you need to
create a skin, and
we need to add buttionTextureStyle to it.
Don't forget to add fonts, it took me a hour to figure out that fonts are not set by default like other parameters of buttonTextureStyle
and then you create a button with created skin
and then add that button to the stage.