Hello the following code is from my main class trying to call another class i made which implements screen.
if (grumpface.whiteballoon.getBoundingRectangle().overlaps(spriterect)) {
System.out.println("hey");
setScreen(new GameOverScreen());
}
;
here is the class i am calling.
class GameOverScreen implements Screen{
private Stage stage;
// Called automatically once for init objects
#Override
public void show() {
stage = new Stage();
float delta = Gdx.graphics.getDeltaTime();
stage.setDebugAll(true); // Set outlines for Stage elements for easy debug
BitmapFont white = new BitmapFont(Gdx.files.internal("hazey.fnt"), false);
LabelStyle headingStyle = new LabelStyle(white, Color.WHITE);
Label gameoverstring = new Label("game ovaaaa!", headingStyle);
gameoverstring.setPosition(100, 100);
stage.addActor(gameoverstring);
}
// Called every frame so try to put no object creation in it
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
System.out.println("hey");
stage.act(delta);
stage.draw();
}
even though i am not returning any stack errors, my program still will not switch screen whenever the event is performed. i can tell the gameoverscreen class is getting called, because whenever the event happens the System.out.println("hey"); is triggered and starts in the console. however, there is no color clear or label drawing like there should be.
Don't use Show() like that. You should initialize your objects in your constructor. maybe try to set screen like that :
((com.badlogic.gdx.Game) Gdx.app.getApplicationListener())
.setScreen(new GameScreen());
We need to see more code to help you
ps i can't comment, but the link : https://code.google.com/p/libgdx-users/wiki/ScreenAndGameClasses is outdated, check it : https://github.com/libgdx/libgdx/wiki
Related
i'm making a game in libgdx but i'm new and i donĀ“t know if my code is the correct form or the best way to do it.
i'm trying to make the basis of the game:
a screen manager to implement a Menu,
an option screen
a loading screen
a game screen
a pause Screem
a game over screen
In the loading screen I like to do something like Dragon Ball when the loading screen allow us to make goku eat rice, the pause screen needs to draw some statistics and options something like Megaman or Castlevania, the menu do something when the player touch a button something like move the camera or open a door, or move to another "scenario" showing another options, and the game over screen needs to previously gives the player the opportunity to win some life to not lose the game.
I try to make this in this form:
I have the main class of the game with the constructor, and the overriden metods create(), render(), resize() and dispose(), the variables for a camera, a viewport, a Spritebatch, a int to store the current screen, and a manager for the screens.
public class BOS_Project extends Game {
OrthographicCamera camera;
Viewport viewport;
SpriteBatch batch;
AssetManager manager = new AssetManager();
int actualScreen = 0;
public BOS_Project(){
camera = new OrthographicCamera();
camera.setToOrtho(false, screenWidth, screenHeight);
viewport = new FitViewport(screenWidth, screenHeight);
}
#Override
public void create(){
batch = new SpriteBatch();
}
#Override
public void render(){
actualScreen = 1;
ScreenManager.getInstance().showScreen(1, this);
super.render();
}
#Override
public void resize(int width, int height){
viewport.update(width, height);
}
#Override
public void dispose(){
batch.dispose();
}
}
Also the class ScreenManager is singleton, and
public class ScreenManager{
private static ScreenManager instance;
private Game game;
Screen screen;
private ScreenManager(){
super();
}
public static ScreenManager getInstance(){
if(instance == null){
instance = new ScreenManager();
}
return instance;
}
public void initialize(Game game){
this.game = game;
}
public void showScreen(int currentscreen, BOS_Project game){
if(currentscreen == 1){
if(screen!=null)
screen.dispose();
screen = new LoadingScreen(game, game.actualScreen);
game.setScreen(screen);
}else if(currentscreen == 2){
if(screen!=null)
screen.dispose();
screen = new GameScreen(game);
game.setScreen(screen);
}else{
if(screen!=null)
screen.dispose();
screen = new MenuScreen(game);
game.setScreen(screen);
}
}
The other classes are the MenuScreen, GameScreen and Loading Screen.
Loading Screen:
public LoadingScreen(BOS_Project game2, int screen2){
game = game2;
screen = screen2;
game.manager.load("button.png", Texture.class);
game.manager.finishLoadingAsset("button.png");
sprite1 = new Sprite(game.manager.get("button.png", Texture.class));
sprite1.setPosition(0, 0);
//This is a method to load the assets for the especific screen
game.load(screen);
}
#Override
public void render(float delta){
if(game.manager.getProgress()==1) {
if (time < 3) {
Gdx.app.log("Loading: ", "90.0");
}
}else {
Gdx.app.log("Loading: ", String.valueOf(game.manager.getProgress() * 100));
}
game.manager.update();
batch = game.batch;
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
sprite1.draw(batch);
if(game.manager.getProgress()==1 && time > 3){
if(screen==1) {
ScreenManager.getInstance().showScreen(2, game);
}else{
ScreenManager.getInstance().showScreen(3, game);
}
}else{
time += delta;
}
batch.end();
super.render(delta);
}
The Menu and Game classes are similar to loading, only call the assets and draw some sprite on the render method.
This code function well to change screens but I don't know if is the correct form, and another big question is how to manage the pause screen, because I manage this only storing a variable if the variable is pause the render method draw something, if not draw the normal game, but if I want to change the options and images of the pause I need to check variables to know what the pause needs to draw.
if(pause){
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
spritePause.draw(batch);
batch.end();
}else if(game){
batch.begin();
spriteGame.draw(batch);
batch.end();
}
So, am i doing it right? or what would you recommend me? Some examples or maybe specific tutorials to achieve this would be great.
There is not only one correct way of managing screens. Libido gives you the freedom to do it exactly how you please. You can extend the Screen class to make screens for the different needs of your project. You can manage your screens as states and manage them with a state manager.
Regarding the Pause and Game Over screen, you can do that in different ways too.
You can have a dedicated screen to switch to or you can have a Pause and GameOver state in your Game state/screen and show the Pause/GameOver elements on top of your gamescreen while the game is still in the background.
So there is not a single correct way of doing it. The correct way is what works for your game.
For some inspiration:
pixnbgames.com : How to manage screens
Brent Aureli : Game State Manager
As #IronMonkey has answered, there is no "correct" way.
I do it with one GameScreen class only, and have a lot of different states inside the GameScreen class. The GameScreen class is very simple and short (100-200 LOC), and is responsible for switching between states. States are similar to the GameScreen class, but they can be entered and exited without the need to instantiate new objecs.
class GameScreen extends ScreenAdapter implements Disposable {
GameState menuState;
GameState playState;
GameState currentState;
public GameScreen(final MyGame game) {
menuState = new MenuState(this);
playState = new PlayState(this);
}
public void setState(GameState state) {
if(currentState == state) return;
// states have a method 'exit' where you can pause them or finalize something
if(currentState != null)
currentState.exit();
currentState = state;
// also states have 'enter' where you can unpause or init something when entering
currentState.enter();
}
public void render(float delta) {
currentState.render(delta);
}
}
First, this is very resource efficient, because the needed states are created only once when the game is started. Second, because you never destroy the states, but just change them and call enter/exit, they always retain perfectly their current state, i.e. variables, objects and everything and when you go back to a state, it is exactly as it was before you left it.
GameState is interface and you are free to implement it as you wish.
public interface GameState
{
public void enter();
public void exit();
public void update(float delta);
public void render(SpriteBatch batch, float delta);
public String toString();
public void dispose();
}
I have a very basic program, that is supposed to display a label and a text field. I am able to display the text. For the textfield, I can create it without error, but when I add it to the stage and run the program I have this error :
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.scenes.scene2d.ui.TextField.draw(TextField.java:301)
at com.badlogic.gdx.scenes.scene2d.Group.drawChildren(Group.java:111)
at com.badlogic.gdx.scenes.scene2d.Group.draw(Group.java:58)
at com.badlogic.gdx.scenes.scene2d.Stage.draw(Stage.java:128)
at com.pace.converter.MainMenuScreen.render(MainMenuScreen.java:52)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.pace.converter.MyGdxGame.render(MyGdxGame.java:21)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
As I don't know how to put line numbers in the code block of my comments, here are the lines pointed by the error :
MainMenuScreen.java: 52 is
stage.draw();
MyGdxGame.java: 21 is
super.render();
I don't understand why I have this NullPointerException as I created the TextField before adding it to the stage.
And here is my complete code :
Main activity :
public class MyGdxGame extends Game {
SpriteBatch batch;
AssetManager assets;
#Override
public void create () {
batch = new SpriteBatch();
assets = new AssetManager();
this.setScreen(new LoadingScreen(this));
}
#Override
public void render () {
super.render();
}
public void dispose () {
batch.dispose();
}
}
Main menu screen :
public MainMenuScreen(final MyGdxGame gam) {
game = gam;
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
skin = new Skin(Gdx.files.internal("skin.json"));
stage = new Stage();
labelStyle = new LabelStyle(game.assets.get("font1.ttf", BitmapFont.class), Color.WHITE);
labelTest = new Label("Test", labelStyle);
textFieldTest = new TextField("Test", skin);
stage.addActor(labelTest);
stage.addActor(textFieldTest);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.281f, 0.602f, 0.844f, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.setProjectionMatrix(camera.combined);
stage.act();
stage.draw();
}
First off all you need to check some things which could be null.. wrap your code in try-catch blocks
I don't know what is stage but check if it has been initialized or not ?
If stage is not null
then check in your Main menu Screen
skin = new Skin(Gdx.files.internal("skin.json")); // is the skin null ? if the file 'skin.json' couldn't be found then this would be null.. check this
textFieldTest = new TextField("Test", skin); // If skin is null, you're adding it here
as for the super.render(); is it even supposed to be called here ?
I'm not entirely sure what I'm doing wrong. I have written this code multiple times before without problems. The problem is that the physics world just does not seem to be updating and I don't know why! Right now I have a gameScene class which extends a normal scene, this is the onCreate method:
#Override
public void create() {
ParallaxBackground background = new ParallaxBackground(0, 0, 0);
background.attachParallaxEntity(new ParallaxEntity(0, new Sprite(0, 0, res.BasicBackground, res.vbom)));
this.setBackground(background);
test = new Sprite(0, 0, res.GrassRegion, res.vbom);
FixtureDef fix = PhysicsFactory.createFixtureDef(10f, 0f, 10f);
Body bod = PhysicsFactory.createBoxBody(physicsWorld, test, BodyType.DynamicBody, fix);
attachChild(test);
physicsWorld = new PhysicsWorld(new Vector2(SensorManager.GRAVITY_EARTH, SensorManager.GRAVITY_EARTH), false);
physicsWorld.registerPhysicsConnector(new PhysicsConnector(test, bod, true, true));
this.registerUpdateHandler(physicsWorld);
}
(I removed a lot of the unnecessary things) I just have a basic test sprite to make sure that the physics is working (which it is not). The app runs without any errors, its just that the sprite will not move, leading me to think that its a problem with the physics world being update.
As you can see, I'm setting the gravity to be accelerating in both the X and Y directions. I did this because I thought maybe it wasn't working in one direction for some reason. I'm thinking that maybe I have to set the scene to update in the main activity? But I don't remember having to do that with any of my other apps. Any help is appreciated thank you :)
No, this.registerUpdateHandler(physicsWorld); will do just fine. Try adding this:
physicsWorld = new PhysicsWorld(new Vector2(0, AHC.WORLD_GRAVITY), false) {
#Override
public void onUpdate(float pSecondsElapsed) {
super.onUpdate(pSecondsElapsed);
}
};
And put a breakpoint or Log.i(TAG, "hey"); inside onUpdate to check if it hits it
EDIT:
Try registering a "normal" UpdateHandler, you can do it in 2 ways:
public class YourGameActivity implements IUpdateHandler{
...
private void yourSetupMethod(){
registerUpdateHandler(this);
}
#Override
public void reset() {}
#Override
public void onUpdate(float pSecondsElapsed) {
Log.i(TAG, "hey");
}
}
or you can create a class that implements IUpdateHandler and then:
public class YourGameActivity{
private MyClassThatImplementsIUpdateHandler mInstance;
...
private void yourSetupMethod(){
registerUpdateHandler(mInstance);
}
}
It's the same.
Try it and see if it logs something, if for some reason you can't see the log use a breakpoint just to be sure.
For organization's sake, I use multiple scenes for my game and rather than having each scene have a constructor that receives a Viewport (my game is scalable), I would like to set each stage's viewport separate of the constructor, then after the viewport is set, add the actors. In the main class, it would happen like this:
public void setStage(Stage s)
{
if(currentStage != null)
currentStage.dispose();
currentStage = s;
currentStage.setViewport(view);
}
To make this go fluidly, each stage has an init method that is called within an overriden setViewport:
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
init();
}
However, all this gives me is a black screen... I have tried updating the camera and viewport, but no avail (note that the actors are having their render methods called).
Why am I getting this black screen and how do I fix it? If it's not possible I'll just revert to using the constructor.
If I understood correctly you want to do this:
Stage stage1 = new Stage();
stage1.getViewport().update(width, height);
rather than this:
Stage stage1 = new Stage (new StretchViewport(width, height)); // It doesn't have to be StretchViewport
In the first case (what you are trying to do) a ScalingViewport will be costructed automatically for you with dimensions of the Gdx.graphics and an orthographic camera and acts like a StretchViewport. Why not using the second case directly where you pass the viewport you want. You can always alter your viewport whenever you want by calling stage1.getViewport().update(width, height);
or by calling stage1.setViewport(width, height, false); in older Libgdx versions.
Viewport has changed recently so if you can extend Viewport class to Override the update method maybe you can achieve what you want:
public class ViewportExtendClass extends StretchViewport{
public ViewportExtendClass(float worldWidth, float worldHeight) {
super(worldWidth, worldHeight);
}
#Override
public void update (int screenWidth, int screenHeight, boolean centerCamera) {
super.update(screenWidth, screenHeight, centerCamera);
// DO YOUR INITIALIZATION HERE
}
}
From your main class you create new stage :
Stage stage1 = new Stage (new ViewportExtendClass (width, height));
and then you call :
stage1.getViewport().update(width, height);
Like this you can alter stage viewport and re initialize your assets.
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
this.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
Camera c = this.getViewport().getCamera();
c.position.set(c.viewportWidth/2, c.viewportHeight/2, 0);
init();
}
This works, but you should also be able to update the Viewport like that at the begin of your application, if you continue to use the same one. I set the position like that instead of centering because some of my Stages will be larger than the screen.
I'm experiencing a problem using LibGDX.
I have a Screen and in its render method I have:
public class LoadingScreen implements Screen{
private OrthographicCamera guiCam;
private TankChallenge tankChallenge;
private SpriteBatch batcher;
private GL10 OpenGL;
public LoadingScreen(TankChallenge tankChallenge) {
this.tankChallenge=tankChallenge;
Gdx.graphics.setTitle("RobotChallange Beta - Loading");
float AR = Gdx.graphics.getHeight()/Gdx.graphics.getWidth();
guiCam = new OrthographicCamera(10,10 * AR);
guiCam.position.set(10f/2,AR*10f/2,0);
batcher = new SpriteBatch();
OpenGL = Gdx.graphics.getGL10();
//loadAssets();
}
#Override
public void render(float delta) {
OpenGL.glClearColor(1, 0.5f, 1, 1);
OpenGL.glClear(GL10.GL_COLOR_BUFFER_BIT);
System.out.print("e");
guiCam.update();
Sprite sp = new Sprite();
sp.setColor(1f,1f,0, 1);
sp.setSize(100,100);
sp.setOrigin(20, 0);
batcher.setProjectionMatrix(guiCam.combined);
batcher.begin();
batcher.disableBlending();
sp.draw(batcher);
batcher.end();
}
I call this by setting it in the implementes ApplicationListener class. I know it is arriving the LoadingScreen because Title is actually set to "RobotChallenge Beta - Loading".
I found a solution for both problems. I added to the Game extending class this:
public void render() {
super.render();
}
Thanks to this the problem is solved and I don't need to override the SetScreen method. Thanks!
Immediately after setting this as your screen, you need to call super.render() in your Game extending class. For instance, I use the following method in my main Game extending class for setting the screen:
#Override
public void setScreen(Screen screen)
{
super.setScreen(screen);
super.render();
}
This seems to kick off render() being called.
Just remove #Override render() in your Game extending class, that fixes the problem. Overriding setScreen method causes flickering you mentioned.