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;
}
}
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 new to Java and I'm trying to make a Visual Novel type of game.
What I'm trying to do is display text from a text file line by line by pressing a space button, like in a usual novel.
I've overlooked different methods but nothing works out for me. I know there are Scanner and BufferedReader, but are they suitable for what I'm doing?
Right now all that happens is when I press "space" the whole text appears on the screen, and when I let go, it dissapears.
This is my game class:
public class NovelGame extends Game {
public static final int WIDTH = 1366;
public static final int HEIGHT = 768;
public SpriteBatch batch;
public String txtFileString;
public String lines[];
public BitmapFont bitmapFont;
#Override
public void create () {
batch = new SpriteBatch();
bitmapFont = new BitmapFont();
this.setScreen(new MainMenuScreen(this));
txtFileString = Gdx.files.internal("script.txt").readString();
String[] anArray = txtFileString.split("\\r?\\n");}
#Override
public void render () {
super.render();
}}
This is my game screen class:
public class MainGameScreen implements Screen{
private Texture img;
NovelGame game;
public MainGameScreen (NovelGame game) {
this.game = game;
}
#Override
public void show() {
img = new Texture("bck.jpg");
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // This cryptic line clears the screen.
game.batch.begin();
game.batch.draw(img, 0, 0);
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
game.bitmapFont.draw(game.batch, game.txtFileString,Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
}
game.batch.end();
}
I had an idea to display it using while and if, but can't exactly figure out how to do it.
EDIT: I found a way to display text, but now, once I run my game, it starts piling one on another endlessly after I press space.
Code:
public class MainGameScreen implements Screen{
private Texture img;
NovelGame game;
public MainGameScreen (NovelGame game) {
this.game = game;
}
#Override
public void show() {
img = new Texture("bck.jpg");
}
#Override
public void render(float delta) {
try {
BufferedReader br = new BufferedReader (new FileReader("C:\\Users\\hydra\\Documents\\JAVA_PROJECTS\\gamespace\\core\\assets\\startd.txt"));
while((game.strLine = br.readLine()) != null){
game.list.add(game.strLine);
}
br.close();
} catch (IOException e) {
System.err.println("Unable to read the file.");
}
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){
game.showText = true;
}
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // This cryptic line clears the screen.
game.batch.begin();
game.batch.draw(img, 0, 0);
if(game.showText) {
for(int i = 0; i < game.list.size(); i++) {
System.out.println(game.list.get(i));
game.bitmapFont.draw(game.batch, game.list.get(i), 100, 50);
}
}
game.batch.end();
}
Problem is here. Gdx.input.isKeyPressed returns true if only key is pressing currently.
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
game.bitmapFont.draw(game.batch, game.txtFileString,Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
}
To fix this add a boolean flag activate it after key is only just pressed:
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){
showText = true;
}
And in render method:
if (showText) {
game.bitmapFont.draw(game.batch, game.txtFileString,Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
}
I found out what I was doing wrong in the end. I put everything in render method, and that's why file was being read endlessly. I need to do it only once in the constructor class and then put it in the render method.
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.
Can anyone shed some light on this behaivor of the viewport or ortographic camera? I expect a rectangular viewport to be drawn but what I get instead is everything squeezed up in a square frame. I uploaded a picture to show you what's going on. The center of the green circle is being drawn on to the point(100,100) so clearly , it looks too disproportioned. The size of the red square is supposed to be 400x400 but judging by the way it looks, it isn't . The aspect ratio is completely off. I don't know what's causing this issue. Ignore the little mario in the center. that's being rendered by another camera soewhere else.
Does any one know what could be causing it?
/**
* Created by Omer on 11/24/2015.
*/
public class Play extends GameStateBase {
public static final int CAMERA_TYPE_SCREEN = 0;
public static final int CAMERA_TYPE_MAP = 1;
private Viewport SCREEN_VIEW;
private Viewport MAP_VIEW;
private OrthographicCamera SCREEN_CAM;
private OrthographicCamera MAP_CAM;
AssaultTrooper assaultTrooper;
GamePad GAME_PAD;
public Play(GameStateManager _gameStateManager) {
super(_gameStateManager);
SCREEN_CAM = new OrthographicCamera();
SCREEN_VIEW = new FitViewport(GameGraphics.VIRTUAL_WIDTH,GameGraphics.VIRTUAL_HEIGHT,SCREEN_CAM);
SCREEN_VIEW.apply();
SCREEN_CAM.translate(GameGraphics.VIRTUAL_WIDTH/2,GameGraphics.VIRTUAL_HEIGHT/2);
SCREEN_CAM.update();
MAP_CAM = new OrthographicCamera();
MAP_VIEW = new FitViewport(GameGraphics.VIRTUAL_HEIGHT,GameGraphics.VIRTUAL_HEIGHT,MAP_CAM);
MAP_VIEW.apply();
MAP_CAM.translate(GameGraphics.VIRTUAL_HEIGHT/2,GameGraphics.VIRTUAL_HEIGHT/2);
MAP_CAM.update();
RENDER_STATE.addCamera(CAMERA_TYPE_SCREEN,SCREEN_CAM);
RENDER_STATE.addCamera(CAMERA_TYPE_MAP,MAP_CAM);
GAME_PAD = new GamePad();
RenderStateManager.changeGameRenderState(RENDER_STATE);
GAME_PAD.setCameraType(CAMERA_TYPE_SCREEN);
GAME_PAD.addToRenderState();
assaultTrooper = new AssaultTrooper(GameSettings.TEAM_BLUE,new Location(200,200));
assaultTrooper.setCameraType(CAMERA_TYPE_MAP);
assaultTrooper.addToRenderState();
}
#Override
public void render(SpriteBatch _spriteBatch) {
try {
RenderStateManager.RENDERING_STATE.render(_spriteBatch);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void handleInput() {
}
#Override
public void update(float deltaTime) {
}
#Override
public void dispose() {
}
#Override
public void reSize(int _width, int _height) {
SCREEN_VIEW.update(_width,_height);
MAP_VIEW.update(_width,_height);
}
}
private ConcurrentHashMap<Long,Location> locations;
private ConcurrentHashMap<Long,Sprite> sprites;
private ConcurrentHashMap<Integer,OrthographicCamera> cameras;
private ConcurrentHashMap<Integer,List<Long>> cameraMapping;
public void render(SpriteBatch _spriteBatch) throws InterruptedException {
synchronized (this) {
for (int key : cameras.keySet()) {
_spriteBatch.setProjectionMatrix(cameras.get(key).combined);
_spriteBatch.begin();
if (cameraMapping.get(key) == null) {
_spriteBatch.end();
continue;
}
for (long MAPPER : cameraMapping.get(key)) {
sprites.get(MAPPER).draw(_spriteBatch);
}
_spriteBatch.end();
}
}
}
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.