How to change gamestates in LibGdx using stacks - android

I am making a game in android like flappy bird and I am able to go from the menu state to the playState but when the game is over and when I try to get the menu state back it just gives me the background or sometimes a white screen.
public class FlappyDemo extends ApplicationAdapter {//ApplicatoonListener
public static final int width=480;
public static final int height=800;
public static final String title="Flappy Bird";
public GameStateManager gsm;
/*private*/public SpriteBatch spriteBatch;
public void create () {
spriteBatch=new SpriteBatch();
gsm=new GameStateManager();
gsm.push(new MenuState(gsm));
Gdx.gl.glClearColor(1,1,1,1);
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gsm.update(Gdx.graphics.getDeltaTime());
gsm.render(spriteBatch);
}
}
public abstract class State {
OrthographicCamera cam;
Vector3 mouse;
GameStateManager gsm;
public State(GameStateManager gsm){
this.gsm=gsm;
mouse=new Vector3();
cam = new OrthographicCamera();
}
public abstract void handleInput();
public abstract void update(float dt);
public abstract void render(SpriteBatch sb);
public abstract void dispose();
}
public class GameStateManager {
private Stack<State> states;
public GameStateManager(){
states=new Stack<State>();
}
public void push(State state){
states.push(state);
}
public void pop(){
states.pop();
}
public void set(State state){
states.pop().dispose();
states.push(state);
}
public void update(float dt){
states.peek().update(dt);
}
public void render(SpriteBatch sb){
states.peek().render(sb);
}
}
public class MenuState extends State {
Texture background;
Texture playBtn;
public MenuState(GameStateManager gsm) {
super(gsm);
background=new Texture("bg.png");
playBtn=new Texture("buttonflappy.jpg");
}
#Override
public void handleInput() {
if(Gdx.input.isTouched()) {
gsm.push(new PlayState(gsm));
}
}
#Override
public void update(float dt) {
handleInput();
}
#Override
public void render(SpriteBatch sb) {
sb.begin();
sb.draw(background,0,0, 1100,1800);
sb.draw(playBtn,1100/2, 1800/2);
sb.end();
}
#Override
public void dispose() {
playBtn.dispose();
background.dispose();
}
}
so first I call the push method and pass it the MENUSTATE and than in the menustate I call the push method and pass it the PlayState to start the game and in the PLayState I have got the gameplay, cameras,viewports. Now when I say that if the bird hits the tube or the ground the menustate should be called again all I get is a green screen which is the background of the playstate.
if (tube.collide(bird.getBirdBound())) {
gsm.set(new MenuState(gsm));
}
if (bird.getPosition().y <= ground.getHeight() + offset) {
gsm.set(new MenuState(gsm));
}
this is the calling method to the gamestate manager when the game ends and the menustate should be called.
So can anyone tell me how can I get the menustate back instead of getting the background color i.e green.
Really appreciate if anyone could help.

You do not clear the previously rendered color to the framebuffer. I see you only call glClearColor on create. Try this render method:
#Override
public void render () {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gsm.update(Gdx.graphics.getDeltaTime());
gsm.render(spriteBatch);
}

I finally got it the problem was that I was not changing the camera position. SO what I did was that in the menustate I used the camera and set its position cam.setToOrtho(false,1100,1800) the position where I had drawn the background and updated the camera so now when in the playstate I poped the current state and went back to to the menustate my camera was pointing at the menustate insted of the green color.

Related

FATAL EXCEPTION: GLThread on 1st launch

I made an app, that works good, but something strange happens. When you install the app for the 1st time, open it and put onPause, lock your phone and then you resume it clicking on icon, when it is loaded, click on BACK button (Gdx.app.exit();), It gives me the following exception:
E/AndroidRuntime: FATAL EXCEPTION: GLThread 1723
java.lang.NullPointerException
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:459)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1524)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
After you launch the app again, and it works properly.
So, trying to figure out this error, I made a new project with gdx-setup.jar. I didn't change AndroidLauncher, neither gradle. Only in manifest I changed landscape to portrait. And I have only 4 classes with almost no code and the problem is still there. May be somebody know what happens. I will appreciate any help. Thanks!
My code:
Main class.
public class TenPuzzle extends Game {
#Override
public void create () {
setScreen(new SplashScreen(this));
}
}
SpalashScreen.java
public class SplashScreen extends Screens{
public SplashScreen(TenPuzzle ten) {
super(ten);
Gdx.app.log("1010", "SPLASH");
}
#Override
public void draw(float delta) {
game.setScreen(new MainMenuScreen(game));
}
#Override
public void update(float delta) {
}
}
MainMenuScreen.java
public class MainMenuScreen extends Screens {
public MainMenuScreen(TenPuzzle ten) {
super(ten);
Gdx.app.log("1010", "Main menu screen");
}
#Override
public void draw(float delta) {}
#Override
public void update(float delta) {}
public boolean keyDown(int keycode) {
if(keycode == Input.Keys.BACK){
Gdx.app.exit();
}
return false;
}
}
and Screens.java
public abstract class Screens extends InputAdapter implements Screen {
public static float SCREEN_WIDTH = 575;
public static float SCREEN_HEIGHT = 1024;
public TenPuzzle game;
public OrthographicCamera oCam;
public SpriteBatch batcher;
public Stage stage;
public static float diffViewportStage;
public Screens(TenPuzzle game) {
this.game = game;
stage = new Stage(new ExtendViewport(Screens.SCREEN_WIDTH,
Screens.SCREEN_HEIGHT, 768, 1224));
oCam = new OrthographicCamera(stage.getWidth(), stage.getHeight());
oCam.position.set(stage.getWidth()/ 2,stage.getHeight()/2f, 0);
InputMultiplexer input = new InputMultiplexer(this, stage);
Gdx.input.setInputProcessor(input);
Gdx.input.setCatchBackKey(true);
}
#Override
public void render(float delta) {
update(delta);
oCam.update();
stage.act(delta);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
draw(delta);
stage.draw();
}
public abstract void draw(float delta);
public abstract void update(float delta);
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void show() {
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
stage.dispose();
}
#Override
public boolean keyDown(int keycode) {
return super.keyDown(keycode);
}
}
Ok, I found the solution. I have no problem in my code, the problem was the Android bug described here: Re-launch of Activity on Home button, but...only the first time

Using GLTextureView instead of GLSurfaceView in WallpaperService

I'm trying to create video wallpaper using MediaPlayer. Also I want to use own shaders to apply visual effects on video. I've figured out that it is possible if use TextureView. Here is an example which works perfect, but for Activity only. I need the same functionality for WallpaperService. So, I tried to replace GLSurfaceView by GLTextureView class. I had a class which works great:
public final class GLWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new WallpaperEngine();
}
private final class WallpaperEngine extends Engine implements
SharedPreferences.OnSharedPreferenceChangeListener {
// Slightly modified GLSurfaceView.
private WallpaperGLSurfaceView mGLSurfaceView;
private SharedPreferences mPreferences;
private EngineCore mRenderer;
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
mRenderer = new EngineCore();
mRenderer.setContext(GLWallpaperService.this);
mGLSurfaceView = new WallpaperGLSurfaceView(GLWallpaperService.this);
mGLSurfaceView.setEGLContextClientVersion(2);
mGLSurfaceView.setRenderer(mRenderer);
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mGLSurfaceView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mGLSurfaceView.onDestroy();
mGLSurfaceView = null;
mRenderer = null;
}
#Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
mGLSurfaceView.onResume();
} else {
mGLSurfaceView.onPause();
}
}
/**
* Lazy as I am, I din't bother using GLWallpaperService (found on
* GitHub) project for wrapping OpenGL functionality into my wallpaper
* service. Instead I am using GLSurfaceView and trick it into hooking
* into Engine provided SurfaceHolder instead of SurfaceView provided
* one GLSurfaceView extends.
*/
private final class WallpaperGLSurfaceView extends GLSurfaceView {
public WallpaperGLSurfaceView(Context context) {
super(context);
}
#Override
public SurfaceHolder getHolder() {
return WallpaperEngine.this.getSurfaceHolder();
}
/**
* Should be called once underlying Engine is destroyed. Calling
* onDetachedFromWindow() will stop rendering thread which is lost
* otherwise.
*/
public void onDestroy() {
super.onDetachedFromWindow();
}
}
}
}
And I got new one by replacing GLSurfaceView on GLTextureView:
public final class GLTextureWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new WallpaperEngine();
}
private final class WallpaperEngine extends Engine {
// Slightly modified GLSurfaceView.
private WallpaperGLTextureView mGLTextureView;
private EngineRenderer mRenderer;
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
mRenderer = new EngineRenderer();
mRenderer.setContext(GLTextureWallpaperService.this);
mGLTextureView = new WallpaperGLTextureView(GLTextureWallpaperService.this);
mGLTextureView.setEGLContextClientVersion(2);
mGLTextureView.setRenderer(mRenderer);
mGLTextureView.setRenderMode(GLTextureView.RENDERMODE_CONTINUOUSLY);
mGLTextureView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mGLTextureView.onDestroy();
mGLTextureView = null;
mRenderer = null;
}
#Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
mGLTextureView.onResume();
} else {
mGLTextureView.onPause();
}
}
/**
* Lazy as I am, I din't bother using GLWallpaperService (found on
* GitHub) project for wrapping OpenGL functionality into my wallpaper
* service. Instead I am using GLSurfaceView and trick it into hooking
* into Engine provided SurfaceHolder instead of SurfaceView provided
* one GLSurfaceView extends.
*/
private final class WallpaperGLTextureView extends GLTextureView {
public WallpaperGLTextureView(Context context) {
super(context);
}
//THIS IS NOT EXIST IN GLTEXTUREVIEW CLASS!!!
/*
#Override
public SurfaceHolder getHolder() {
Log.e("getHolder", "getHolder");
return WallpaperEngine.this.getSurfaceHolder();
}
*/
//TRIED TO CHANGE getHolder() BY THIS ONE - NO RESULTS!
#Override
public SurfaceTexture getSurfaceTexture() {
Log.e("getSurfaceTexture", "getSurfaceTexture");
return (SurfaceTexture) WallpaperEngine.this.getSurfaceHolder();
}
public void onDestroy() {
super.onDetachedFromWindow();
}
}
}
}
Renderer class:
public class EngineRenderer implements GLTextureView.Renderer {
Context context;
public void setContext(Context context){
this.context=context;
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.e("ds", "-onSurfaceCreated--");
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.e("ds", "-onSurfaceCreated--");
}
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClearColor(1, 0, 0, 1);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
#Override
public void onSurfaceDestroyed(GL10 gl) {
}
}
I don't get any errors, just black screen. Renderer class is not drawn! It seems to me that GLTextureView doesn't have getHolder() function.
What should I do? Maybe there is another way to implement my goal.

Stage doesn't get drawn

I created a super class with nothing in the render method:
public class SuperClass implements InputProcessor {
public SuperClass(MyGame game) {
}
public void render() {
}
// InputProcessor overriden methods here
}
In a subclass I override the render method:
public class SubClass extends SuperClass {
Stage stage;
public SubClass(MyGame game) {
super(game);
stage = new Stage(0, 0, false);
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
Gdx.input.setInputProcessor(stage);
Image image = new Image(new Texture(Gdx.files.internal("bg.png")));
image.setPosition(0, 0);
image.setWidth(800);
image.setHeight(480);
stage.addActor(image);
}
#Override
public void render() {
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
}
But the stage doesn't get drawn. I know this because I expect to see the background image but its just a blank screen.
What am I doing wrong here?
You should be calling your SuperClass render method in your MyGame render method.
Is your render() method being called each game loop?
What I do normally is to create an Object which extends Game and set a Screen.
class MyGame extends Game {
#Override
public void create() {
setScreen(new MainScreen());
}
}
In the MainScreen class which implements Screen interface I can create my stage:
class MainScreen implements Screen {
Stage stage = new Stage(0, 0);
#Override
public void dispose() {
stage.dispose();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void resize(int width, int height) {
}
#Override
public void resume() {
}
#Override
public void show() {
stage = new Stage(0, 0, false);
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
Gdx.input.setInputProcessor(stage);
Image image = new Image(new Texture(Gdx.files.internal("bg.png")));
image.setPosition(0, 0);
image.setWidth(800);
image.setHeight(480);
stage.addActor(image);
}
}
With this code the render() method should be called in each game loop.
The line in the SubClass constructor should be:
stage = new Stage(800, 480, false);
or you can also do this:
stage = new Stage()
but then you have to set the viewport, stage.setViewport(float, float, boolean) in resize(float, float).

Canvas animations

I've looked around for help on this but i can't find any answers. Currently, when i want to animate a ball, within a surfaceview, i call a method that:
Sets an animation variable in the surfaceview to a custom class extending AnimationModule (which extends AnimationSet) which changes properties of the ball on every draw
This is then called on every draw until the AnimationModule reaches its maxCount at which point it calls its inherited AnimationListener.onAnimationEnd
The surfaceview receives this callback and then declares the animation variable null so that it doesn't call it on every draw any more
This is working sort of alright at the moment but feels really bad and clunky - I'd really like to be using a tried and tested method that others use as i'm very new to animations.
The other issue with this is that I have to use animations that extend view.animation, so ScaleAnimation, TranslateAnimation etc. It's all well and good for moving the ball around the screen, but when i come to more complicated things like animating it's perspective with canvas.polyToPoly I have to create a new class extending view.animation just for that case or make do without it.
AnimationModule class:
public abstract class AnimationModule extends AnimationSet{
protected AnimationListener listener;
protected CreatureView attacker;
protected CreatureView defender;
protected BattleCanvas canvas;
protected long increment=0;
protected long individualIncrement=0;
protected float interpolation=0;
private boolean finished=false;
private ArrayList<Animation> animations = new ArrayList<Animation>();
private int currentAnimation=0;
private long totalTime=0;
public interface OnAnimationFinishedListener{
public void OnAnimationFinished();
}
public AnimationModule(boolean shareInterpolator){
super(shareInterpolator);
init();
}
public void setCanvas(BattleCanvas canvas){
this.canvas=canvas;
}
public void setCreatures(CreatureView attacker, CreatureView defender){
this.attacker=attacker;
this.defender=defender;
Log.i("anim","attacker :"+String.valueOf(attacker.getCreature().getBaseName()));
}
public AnimationModule(boolean shareInterpolator, AnimationController controller){
super(shareInterpolator);
}
private void init(){
setFillAfter(true);
}
public boolean isFinished(){
return finished;
}
#Override
public void addAnimation(Animation a){
Log.i("Animation","adding animation");
animations.add(a);
computeDuration();
//super.addAnimation(a);
finished=false;
}
#Override
public void setAnimationListener(AnimationListener a){
super.setAnimationListener(a);
this.listener=a;
}
#Override
public boolean getTransformation(long increment, Transformation transform){
//super.getTransformation(increment, transform);
if(animations.size()>currentAnimation)
animations.get(currentAnimation).getTransformation(individualIncrement, transform);
return true;
}
public void draw(){
}
public void update(){
if(animations.size()>0){
Log.i("Animation",String.valueOf(individualIncrement));
Log.i("Animation",String.valueOf((animations.get(currentAnimation).getRepeatCount()+1)));
Log.i("Animation",String.valueOf(animations.get(currentAnimation).getDuration()));
if(individualIncrement>animations.get(currentAnimation).getDuration()*(animations.get(currentAnimation).getRepeatCount()+1)){
if(animations.size()>currentAnimation+1){
currentAnimation++;
individualIncrement=0;
}else{
finished();
return;
}
}
Log.i("module","on animation "+String.valueOf(currentAnimation));
increment();
if(increment>=getDuration()){
finished();
}
}
}
protected long computeDuration(){
long duration=0;
Iterator<Animation> iterator = animations.iterator();
while (iterator.hasNext()) {
Animation a = iterator.next();
duration=duration+a.computeDurationHint();
}
totalTime=duration;
setDuration(duration);
Log.i("Animation","duration set to "+String.valueOf(duration));
return duration;
}
private void finished(){
finished=true;
if(listener!=null)
listener.onAnimationEnd(this);
}
private void increment(){
increment++;
individualIncrement++;
if(getDuration()!=0){
float far = increment/getDuration();
interpolation=far;
}
else
interpolation=0;
}
}
example animation extending AnimationModule:
class BiteAnimation extends AnimationModule{
private float fromSy;
private float fromSx;
private ColorAnimation flash;
public BiteAnimation(boolean shareInterpolator){
super(shareInterpolator);
}
#Override
public void setCanvas(BattleCanvas canvas){
super.setCanvas(canvas);
fromSy=defender.getSy();
fromSx=defender.getSx();
ScaleAnimation scale = new ScaleAnimation(fromSx,fromSx,fromSy,fromSy/2, defender.size/2, defender.size/2);
scale.setDuration(50);
scale.setRepeatMode(2);
scale.setRepeatCount(1);
addAnimation(scale);
flash = new ColorAnimation(defender.getAdd(), Color.WHITE, ColorAnimation.TYPE_ADD, defender);
flash.setDuration(50);
flash.setRepeatMode(2);
flash.setRepeatCount(1);
}
#Override
public void update() {
super.update();
Transformation t = new Transformation();
Log.i("Animation","increment: "+String.valueOf(individualIncrement));
getTransformation(individualIncrement, t);
defender.getMatrix().postConcat(t.getMatrix());
flash.getTransformation(individualIncrement, null);
}
}
as you can see, the custom animationModule just applies it's transformation to the objet it's transforming's canvas(in this case a defender). This canvas is then used when drawing the defender on the surfaceview.
Like i said, this feels really awful and i could do with some help on how i should implement object animations.

InputProcessor of libgdx does not fire

I'm trying to get a simple libgdx project running on Android. Everything is fine, but my InputProcessor does not fire its events.
I implemented everything according to this tutorial:
http://code.google.com/p/libgdx-users/wiki/IntegratingAndroidNativeUiElements3TierProjectSetup#Code_Example
The first call of "showToast" works fine and is shown on my screen => The showToast-Method does work. Unfortunately, I can't fire any of the InputProcessor events. Even the debugger does not stop there, so they are definitely not called.
Edit: Here is the complete code. I only omitted the Calculator Class, since it works fine and should not be of any conern here. If anyone disagrees with that I can always add it, of course.
Surface Class in libgdx main project (Main class so to say)
public class Surface implements ApplicationListener {
ActionResolver actionResolver;
SpriteBatch spriteBatch;
Texture texture;
Calculator calculator;
public Surface(ActionResolver actionResolver) {
this.actionResolver = actionResolver;
}
#Override
public void create() {
spriteBatch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("ship.png"));
calculator = new Calculator(texture);
actionResolver.showToast("Tap screen to open Activity");
Gdx.input.setInputProcessor(new InputProcessor() {
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
actionResolver.showToast("touchDown");
actionResolver.showMyList();
return true;
}
// overriding all other interface-methods the same way
});
}
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
calculator.update();
spriteBatch.begin();
calculator.draw(spriteBatch);
spriteBatch.end();
}
// Overriding resize, pause, resume, dispose without functionality
}
ActionResolver interface in libgdx main project
public interface ActionResolver {
public void showMyList();
public void showToast(String toastMessage);
}
Implementation of the ActionResolver interface within my Android project
public class ActionResolverImpl implements ActionResolver {
Handler uiThread;
Context appContext;
public ActionResolverImpl(Context appContext) {
uiThread = new Handler();
this.appContext = appContext;
}
#Override
public void showMyList() {
appContext.startActivity(new Intent(this.appContext, MyListActivity.class));
}
#Override
public void showToast(final String toastMessage) {
uiThread.post(new Runnable() {
#Override
public void run() {
Toast.makeText(appContext, toastMessage, Toast.LENGTH_SHORT).show();
}
});
}
}
Android Activity for inizializing the Suface-Class
public class AndroidActivity extends AndroidApplication {
ActionResolverImpl actionResolver;
#Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
actionResolver = new ActionResolverImpl(this);
initialize(new Surface(actionResolver), false);
}
}
I also implemented the InputProcessor in my Surface-class, but this should not (and did not) make any difference. Any ideas, what I'm missing?

Categories

Resources