Handling Screens of Libgdx App on Android - libgdx

This my way to deal with screens
I have class GameMain extends Game I created instance of it in each screen so I can use something like this gameMain.setScreen()
My question is How to move properly from one screen to another ?
I have the following :
In GameMain I setScreen(new SplashScreen(this))
In splash screen I setScreen(new MenuScreen(this)) in hide() of splash I call its dispose() and so on as when player click play button in menu screen I setScreen() to new playScreen I also call dispose() in hide() and when he returns to Menu I setScreen(new Menu)
Is what I am doing wrong ?

What I normally do is I have in my main Game class a function for example called setPlayScreen(), and in that method I do something like:
public void setPlayScreen(params){
//Do something with params
setScreen(new PlayScreen())
}
If you have your dispose() inside your screens hide() method you shouldn't have any problems.

Related

Why doesn't UINavigationController change orientation when I push a controller with different supported orientations?

How my code is set up:
I use a navigation controller, with a delegate that controls the orientation:
class NavDelegate: UINavigationControllerDelegate {
func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
print("Checking orientation")
if topViewController != nil {
return topViewController!.supportedInterfaceOrientations
}
return .portrait
}
...
}
The main view controller of my app is named MainController, and it's portrait-only:
class MainController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
...
}
I have another controller PhotoController, which supports all four orientations:
class PhotoController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
...
}
I push the PhotoController on top of the MainController, using pushViewController().
The problem:
Each controller by itself handles orientations correctly — MainController stays in portrait as I rotate the phone to all four orientations, and PhotoController rotates to all four orientations.
But this scenario doesn't work correctly:
Put the phone in landscape, with main controller on screen.
The controller is in portait (as expected).
Push the PhotoController on the stack.
I expect the PhotoController to open in landscape, based on the device orientation, but it remains in portrait. If I manually rotate the phone back and forth, the controller rotates with the phone. Obviously, the user should never have to do this, rotate the phone back and forth to get the controller to rotate.
When I tap the button in MainController that pushes PhotoController, navigationControllerSupportedInterfaceOrientations() isn't invoked.
What else I tried:
Overriding shouldAutorotate to return true in PhotoController.
... and in MainController.
Overriding supportedInterfaceOrientations in UINavigationController instead of using the delegate.
Checking UINavigationController.visibleViewController instead of .topViewController. This didn't work because the topviewController turns out to be an iOS private class UISnapshotModalViewController, not my class, so calling supportedInterfaceOrientation() on it presumably doesn't return the right value.
None of these work.
The solution turned out to be to invoke UIViewController. attemptRotationToDeviceOrientation() in viewWillAppear() or viewDidAppear().
In the former case, the animation of pushing the controller occurs concurrently with the device rotation animation, which looks odd. In the latter case, the rotation happens after the controller transition animation completes. Which also looks odd, though in a different way.

Game Over Screen with Libgdx [Switching 2 screens]

I have 2 implemented screen, MainScreen and OverScreen in create() of MainClass. In MainScreen I implemented game, in the end of game, I want to show OverScreen, in OverScreen, user clicks into it, and it brings MainScreen back. How to switch 2 screen?
You can pass your GameClass object to your current screen in the constructor and then in your touchDown() method of your InputProcessor you can call gameClass.setScreen();
Lets suppose GameClass is the name of your class that extends Game. Then the constructor of your MainScreen would look like this:
GameClass game;
public class MainScreen(GameClass game){
this.game = game;
}
In your game class, you will pass "this" as argument.
setScreen(new MainScreen(this));
Now you can call this anywhere to change screen:
game.setScreen(new OverScreen());

GameStateManager LibGDX

I started a project with libgdx and I have a GameStateManager for my GameStates Menu and Play.
If I run the project it shows the Menu and then I can click a button to open the Play GameState.
The Problem is, that when I ended the Game it should show the Menu State again, but I get a black screen. I tested if the render() method is started (with System.out...) and the render() method in Menu is starting.
I am not shure why I get a black screen when I "reopen" the Menu state. Maybe its not working because I use Box2D in Play but I dont know.
Here some code:
This is the method in Play which should open the Menu if the player is at the end:
public void playerEnded() {
gsm.setState(GameStateManager.MENU);
}
Maybe you can tell me, if I have to end box2d things or so.
I hope someone can help me, and if you want more code - no problem.
Your custom GameStateManager should extend this class:
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Game.html
To change screens you should be using Game.setScreen(Screen screen)
Each different screen should be an implementation of Screen.
So the way it works in my libGDX projects is such that GameScreen extends Screen, and MenuScreen extends Screen. That way I can change what draws on what screen.
This all goes back to interfaces and polymorphism, so if you don't get those concepts, just give it a quick google and you'll get an idea what you need to do.
Chances are that your are defining a
Stack<GameState> gameStates
in your GameStateManager to manage your GameStates.
If so, you could do some reading on using a Stack. Anyway, here's what could do to solve your problem:
I'm assuming you have the following structure in your GamestateManager;
public void setState(int state){
popState();
pushState(state);
}
public void pushState(int state){
gameStates.push(getState(state));
}
public void popState(){
GameState g = gameStates.pop();
g.dispose();
}
private GameState getState(int state){
if(state == MENU) return new Menu(this);
if(state == PLAY) return new Play(this);
return null;
}
When you click your start button in your Menu-GameState, you'll want to launch the Play-GameState.
Now, instead of using the setState method, which removes the top state (pop) and then pushes the new state. Try using only the pushState method. This will put your new Play-GameState on top of your Menu-GameState in the GameState-Stack.
When you're done playing, you can pop your Play-GameState and the Menu-GameState should reappear. But this time it won't instantiate a new Object, but reuse the one you used when you started the game.
// in the Menu-GameState:
public void startPlay() {
gsm.pushState(GameStateManager.PLAY);
}
// in the Play-GameState:
public void playerEnded() {
gsm.popState();
}
This won't affect gameplay performance as you would render and update your game with only the GameState that is on top of the Stack, like this:
public void update(float dt) {
gameStates.peek().update(dt);
}
public void render() {
gameStates.peek().render();
}
The peek method takes the GameState from the top of the Stack, but leaves it there.
The only downside is that the Menu-Gamestate would stay in-memory during your Play-State.
Also, if this method works, you could still do it your way, but you should check the way your Menu-GameState is instantiated and identify problems when it's instantiated twice.
I implemented a similar StageManager in my game. If you are using viewports/cameras in your game, then it is likely that when you go back to your menu state, the viewport is still set to the Game state's viewport.
For my app, I had my State class have an activate() method which would be called whenever a state became the active state:
public void activate(){
stage.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}

How do you handle stage Event.RESIZE in an Actionscript3 application?

This has long bothered me.
When using stage resize, you could say something like this:
public class Preload extends MovieClip
{
protected var main:Main;
public function preloader()
{
this.main = new Main();
this.addChild(this.main);
stage.addEventListener(Event.RESIZE, this.onResize);
}
protected function onResize(e:Event): void
{
this.main.x = stage.stageWidth>>1;
this.main.y = stage.stageHeight>>1;
}
}
What about if Main needs to also resize? I have many systems which respond to a resize event and I do not know if I should simply add a stage Event.RESIZE listener to every screen or if this should be controlled from a single location.
For example, add this.main.resize() to the onResize listener above then implement an IResizable interface on my screens for example?
What is best practice?
EDIT: Or should resize be part of something more generic, like invalidate()
For performance it's better to have only 1 Event.RESIZE listener in your document class. Then propagate the event to all your sub classes and children with functions, or even better with the wonderful Signals framework by Robert Penner.
If you need to scale your document class the easiest way is to put all your content inside a Sprite and scale that instead.

Detecting completion of GWT Deck Panel Animation

I have a Deck Panel with AnimationEnabled(true). I want to know when the animation completes when i change the deck in order to perform other tasks.
I guess the answer would be there is no way to do it
Did you try subclassing DeckPanel and overriding onComplete()?
public MyDeckPanel extends DeckPanel{
#Override
protected void onComplete(){
super.onComplete();
//What you want to do once the animation completes
}
}