I have a very simple Libgdx game, its my first one, and in this game i have a main java file(obviously). This file extends Game and looks like this.
package com.jawdroppergames.penalty;
import com.badlogic.gdx.Game;
public class Penalty extends Game{
public MainGame main_screen;
#Override
public void create(){
Assets.load();
main_screen = new MainGame(this);
setScreen(main_screen);
}
}
And in MainGame.java
private Penalty maingame;
public MainGame(Penalty game){
this.maingame = game;
camera = new OrthographicCamera();
camera.setToOrtho(true,1080,1920);
main_batch = new SpriteBatch();
ball_batch = new SpriteBatch();
}
as well as more code obviously
This works perfectly and opens the MainGame class. Now what i want to do is open ANOTHER screen from within MainGame. Ive tried using the same code and changing the necessary names of files etc, and this calls the show method but doesnt render the actual screen, it calls show() but not render(). Any help?
oh, and MainScreen does extend Game
this should work for u..
game.setScreen(new PlayScreen(game));//playscreen is the another screen
and why are you using two sprite batches, you should avoid this.
Related
I am currently developing a tower defence game for a university project.
At higher waves there are hundreds of enemies moving arround. My problem is that it's getting very inperforment at about 300+ enemies moving simultaneously.
Every enemy is a children of a Pane which is displayed in my scene.
I've got a method in my EnemyGraphics class which updates the positon by calling the update method:
public class EnemyGraphics extends ImageView implements EventObserver {
...
#Override
public void update() {
Platform.runLater(() -> {
relocate(enemy.getxCoordinate(), enemy.getyCoordinate());
});
}
}
I guess it's getting laggy because every enemy is updating its location on its own every time it moves by calling update().
Is there a way that I can set new coordinates for my ImageView object, without redrawing the scene and in the main FX-Thread creating a timer which redraws the entire scene in a certain interval? Or is there a other solution / method I can call to move images performantly over the pane?
Ok I've found my mistake. Everytime my enemyLogic class compute a new position it called the enemyGraphic object to update its position. During testing I've removed the functionality of the method in the enemyGraphics class but not the call.
To update the postions of all the enemys I've written a method in my GUIcontroller class:
private void startUpdateTicker() {
final AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long timestamp) {
updateEnemies();
}
};
timer.start();
}
public synchronized void updateEnemies() {
for (EnemieGUI enemy : enemyList) {
enemy.relocate(enemy.getEnemie().getxCoordinate(), enemy.getEnemie().getyCoordinate());
}
}
I've been struggling with how to use and set up Viewports in LibGDX for quite some time. I want to be able to render everything like its on a display that is 1920x1080 and have it scale to fit the display its on, and I need some help getting to work like that.
This is what I want it to look like (taken from a computer with a 1920x1080 monitor), but when I run the same code on my laptop which is 1440x800, it looks like this. I apologize for the poor photo of a screen, I couldn't get it to take a screenshot of the game running for whatever reason, but it shows that the top of the display remains unused, and that not everything is being fit to the display. This is the main code running the show:
public class Main extends Game {
...
public void create() {
...
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
//last
this.setScreen(new MainMenu(this));
}
public void render() {
super.render(); //important!
}
...
}
And then the MainMenu class
public class MainMenu implements Screen{
...
public MainMenu(final Main game) {
this.game = game;
cam = new OrthographicCamera();
cam.setToOrtho(false, 1920, 1080);
...
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.025f, .025f, 0.025f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
game.batch.setProjectionMatrix(cam.combined);
...
if(Gdx.input.isKeyPressed(Keys.ESCAPE)) {
Gdx.app.exit();
}
}
...
}
How would I implement a Viewport or something of the like to get it to look the same on the smaller screen as it does on the larger? Any help is really appreciated! If you want to see the code that I left out for brevity, its all on my GitHub. Thanks again!
That didn't take me long, hopefully someone will learn from me though, ha ha.
Turns out when you use the camera with fixed height and width like that, it does fill up the whole monitor, but the cameras width DOES NOT equal the value returned by Gdx.graphics.getWidth(). Because of this all my code was rendering like it was being compressed because it was referencing the width returned by Gdx.graphics, and not the camera.viewportWidth.
Lesson learned: Gdx.graphics.getWidth() can and will change depending on device and cam.veiwportWidth wont. Oops!
I am trying out Libgdx, and I have an actor which performs some action whenever we click on it. So far it is working fine. Now I want to add light to the actor. After doing some research I came across Box2DLights. When I tried adding it to my project onClick Actor which was working fine does not seem to work. I am pretty sure this is due to rayhandler/Box2DLights because that is the only change I am making. here is the minimal change that I made to include Box2DLights.
public class GameScreen implements Screen {
private RayHandler rayHandler;
private World world;
public GameScreen(Game game) {
this.game = game;
world = new World(new Vector2(0, 0), true);
rayHandler = new RayHandler(world);
rayHandler.setAmbientLight(0.1f, 0.1f, 0.1f, 1f);
rayHandler.setBlurNum(3);
}
#Override
public void show() {
viewport = new FitViewport(1080, 720);
stage = new Stage(viewport);
rayHandler.setCombinedMatrix(stage.getCamera().combined);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
//some custom rendering logic, but nothing related to rayHandler, excluding this for brevity.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
rayHandler.updateAndRender();
}
Now When I debugged, I realised the the onClick is
working little below the actual actor
, that means somehow the coordinates sifted(I know weird).
Can you please help?
Thanks #Mikhail Churbanov for your response here.
If somebody else stumbles on this again here is the solution which worked.
viewport = new FitViewport(1080, 720);
rayHandler.useCustomViewport(viewport.getScreenX(),
viewport.getScreenY(),
viewport.getScreenWidth(),
viewport.getScreenHeight());
The explaination is box2lights doesn't auto-acquire custom viewports, and restores the 'default one' after the updateAndRender called - your need to set your custom 'fitted' viewport to rayHandler so that it would restore it correctly- using the rayHandler.useCustomViewport(...) method.
All credits to #mikahi churbanov
Here is my OOP setup:
Class MainGame extends Game:
...
public void create () {
assets = new Assets(); // my custom Assets object (constructor creates manager and AssetDescriptors
assets.load(); // loads Asset Descriptors into manager
assets.getManager().finishLoading();
batch = new SpriteBatch();
setScreen(new PlayScreen(this, assets));
}
...
public void dispose () {
assets.dispose(); // disposes asset manager
super.dispose();
batch.dispose();
}
Class PlayScreen implements Screen:
public PlayScreen(MainGame game, Assets assets) {
this.assets = assets;
this.game = game;
background = assets.getManager().get(assets.getBackground());
hero = new HeroSprite(290, 1100, this, assets);
// Create Game camera and Hub also
}
public void render(float delta) {
// Clear screen
// Use game batch to draw to screen
}
public void dispose() {
assets.dispose();
}
Class HeroSprite:
public HeroSprite(int x, int y, PlayScreen screen, Assets assets){
this.assets = assets;
this.screen = screen;
// Animation Textures
heroWalking = assets.getManager().get(assets.getWalking()); // This is an Asset Descriptor
walkAnime = new Animation(heroWalking) // my own custom animation class which takes the spritesheet and returns the appropriate frames
...
}
// This does not contain a dispose method
Sorr if there's a lot of code there I tried to minimize as much as possible. My main question is if I am disposing correctly?
It seems ok, my game runs fine. But when I quit the game and re-enter a black screen shows. This happens both on Desktop and Android.
A solution that works is to clear the memory on Android using Super Cleaner App. Since it's a memory issue I figures it has something to do with me disposing incorrectly.
EDIT : Revealing my Assets Class
public class Assets {
private AssetManager manager;
private AssetDescriptor<Texture> background;
private AssetDescriptor<Texture> wood;
public AssetManager getManager() {
return manager;
}
public AssetDescriptor<Texture> getBackground() {
return background;
}
public AssetDescriptor<Texture> getWood() {
return hero;
}
public Assets(){
manager = new AssetManager();
background = new AssetDescriptor<Texture>("textures/static/bg.png", Texture.class);
hero = new AssetDescriptor<Texture>("textures/static/hero.png", Texture.class);
...
}
public void load(){
manager.load(background);
manager.load(hero);
...
}
public void dispose(){
manager.dispose();
}
}
Screen.dispose() does not get called automatically, you should manually call dispose when you exit a screen and not needing the assets anymore. But obviously when you need them again you need to load them again and you need a new AssetManager for that. So if your assets won't take up that much you should just keep it in memory.
On exit however you need to dispose. Game.dispose() does get called automatically. Here you should call getScreen().dispose() and have everything needing disposing in the dispose() method of the effective Screen.
Since currently it does not look like you are disposing between screens it might be because you have a static AssetManager, you should show your Assets() class.
I was doing some tests and I realized that on my Nexus 5, when I hit the back key (or the home) -that is, when there's a change of context- and I go back to my game, the openGL context is lost.
There are no textures anymore (they show as black) or skins for the UI (the buttons are white).
I thought it was automanaged by libgdx automatically, right? So why is this happening?
The way I'm creating the textures is via TextureAtlas, like
TextureAtlas atlas;
TextureRegion bg;
atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
bg = atlas.findRegion("bg");
And then it's used with the batch.draw(bg, x, y, w, h);
I also tried creating the TextureRegion loading directly a Texture instead of a TextureAtlas (just in case but it should be the same) and I get the same result...
Anyone?
Edit: more specific code:
Screen class basics:
public class MainMenuScreen extends ScreenManager.Screen {
private Game game;
private InputMultiplexer inputMultiplexer = new InputMultiplexer();
private MainMenuUi screenUi;
private MainMenuView screenView;
private TextureAtlas atlas;
public MainMenuScreen(ConbiniGame game) {
this.game = game;
atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
screenUi = new MainMenuUi(game);
screenView = new MainMenuView(atlas);
inputMultiplexer.addProcessor(screenUi.getInputProcessor());
inputMultiplexer.addProcessor(screenView.getInputProcessor());
Gdx.input.setInputProcessor(inputMultiplexer);
}
// ...
}
MainMenuView class where the TextureAtlas is being used...
public class MainMenuView {
private Stage stage;
private OrthographicCamera camera;
private Viewport viewport;
private TextureAtlas atlas;
TextureRegion bg;
public MainMenuView(TextureAtlas atlas) {
atlas = atlas;
bg = atlas.findRegion("bg");
camera = new OrthographicCamera();
camera.setToOrtho(false);
viewport = new FitViewport(1080, 1920, camera);
stage = new Stage(viewport);
}
public void update(float delta) {
stage.act(delta);
}
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.getBatch().begin();
stage.getBatch().draw(bg, 0, 0, stage.getCamera().viewportWidth, stage.getCamera().viewportHeight);
stage.getBatch().end();
stage.draw();
}
public InputProcessor getInputProcessor() {
return stage;
}
}
The code is just to show the use of the texture, with other parts removed
You didn't provide enough information, but your problem is likely caused by using static in your code. Don't do that.
When you press the back button your app is closed. When you press the home button then your app is paused. Note that this are two different things. Therefor you might experience the problem not always when using the home button. This because while your app is paused, that android might decide to close it (to free memory), but it is not guaranteed to do so.
Either way, this is not related to the opengl context being lost. It is just closed. If the context would be really lost then libgdx (and later versions of android) will recover it for you.
When you close your app and then immediately start it again then Android might reuse the same VM for that instance of your app. This also means that any static variables will have the value they had from the previous run of your app. If any of those variables include (may be indirectly) any resources, then those resources won't be valid anymore.
tl;dr never use static in android applications.
The most common mistake (without seeing your code this is just guessing) is to access assets by using a singleton. E.g. MyGame.getInstance().assets.get("atlas",...); don't do that, it will (because of above reason) fail. Instead pass a reference to your MyGame instance to whichever classes needs it (e.g. your Screen: new MenuScreen(this);).
I ran into the same problem when making my first LibGDX game - a Flappy Bird clone - and it turned out the problem was not with the Texture at all, but with a MEMBER Vector2/Vector3 variable that I used for velocity.
To make the bird fall from a given height, I'd declared:
1. a member int variable for gravity (initialised to -15),
2. a Vector2 member variable for bird position, initialised to (50, 300), and
3. another Vector2 member variable for velocity, initialised to 0,0
Now, in the update() method, I passed gravity as a value to velocity's y-axis parameter using velocity.add(0, gravity)
Then I scaled it, using velocity.scl(dt)
Then I added that velocity to position and then unscaled it again, using velocity. scl(1/dt).
This last line was what caused the bug, but since it was essential for the functionality of my game, I couldn't afford to delete.
My solution was to change the velocity variable from a member variable to a local variable, and the textures stopped disappearing when game was paused.
Actually it's OK to use Singleton or other static paterns for texture management. The only thing you should do to escape black-rectangle problem is:
make static content depending of Game entity:
private static TextureStore sStore = null;
private static MyGdxGame sGame;
static public TextureStore getStore()
{
if(sStore==null||sGame!=MyGdxGame.getGame())
{
sStore = new TextureStore();
sGame = MyGdxGame.getGame();
}
return sStore;
}
And in game entity
#Override
public void create()
{
sGame = this;
...