Creating the HUD (2/2)
Here are the functions of the HUD.java :
public void draw(){ //Oxygen level game.batch.setColor(0,0,1,1); game.assets.get("fontHUD.ttf", BitmapFont.class).draw( game.batch, "Oxygen", posXOxygen - new GlyphLayout(game.assets.get("fontHUD.ttf", BitmapFont.class), "Oxygen").width - Gdx.graphics.getWidth()/100, posYOxygen + new GlyphLayout(game.assets.get("fontHUD.ttf", BitmapFont.class), "Oxygen").height); game.batch.draw(skin.getRegion("WhiteSquare"), posXOxygen, posYOxygen, width * hero.getOxygenLevel()/GameConstants.MAX_OXYGEN, height); //Fuel level game.batch.setColor(1,0,0,1); game.assets.get("fontHUD.ttf", BitmapFont.class).draw( game.batch, "Fuel", posXOxygen - new GlyphLayout(game.assets.get("fontHUD.ttf", BitmapFont.class), "Fuel").width - Gdx.graphics.getWidth()/100, posYOxygen + new GlyphLayout(game.assets.get("fontHUD.ttf", BitmapFont.class), "Fuel").height - 2 * height); game.batch.draw(skin.getRegion("WhiteSquare"), posXOxygen, posYOxygen - 2 * height, width * hero.getFuelLevel()/GameConstants.MAX_FUEL, height); } public void win(){ GameConstants.GAME_PAUSED = true; imageTableBackground.setWidth(tableWin.getPrefWidth() + Gdx.graphics.getWidth()/20); imageTableBackground.setHeight(tableWin.getPrefHeight() + Gdx.graphics.getWidth()/20); tableWin.addAction(Actions.alpha(1, 0.25f)); imageTableBackground.addAction(Actions.sequence(Actions.moveTo( Gdx.graphics.getWidth()/2 - imageTableBackground.getWidth()/2, Gdx.graphics.getHeight()/2 - imageTableBackground.getHeight()/2), Actions.alpha(1, 0.25f))); } public void lose(){ GameConstants.GAME_PAUSED = true; loseLabel.setText(loseString); imageTableBackground.setWidth(tableLose.getPrefWidth() + Gdx.graphics.getWidth()/20); imageTableBackground.setHeight(tableLose.getPrefHeight() + Gdx.graphics.getWidth()/20); tableLose.addAction(Actions.alpha(1, 0.25f)); imageTableBackground.addAction(Actions.sequence(Actions.moveTo( Gdx.graphics.getWidth()/2 - imageTableBackground.getWidth()/2, Gdx.graphics.getHeight()/2 - imageTableBackground.getHeight()/2), Actions.alpha(1, 0.25f))); } public void outOfFuel(){ outOfFuelAlpha += 4 * Gdx.graphics.getDeltaTime(); outOfFuelLabel.addAction(Actions.alpha((float)(1 + Math.cos(outOfFuelAlpha))/2)); } public void pause(){ GameConstants.GAME_PAUSED = true; imageTableBackground.setWidth(tablePause.getPrefWidth() + Gdx.graphics.getWidth()/20); imageTableBackground.setHeight(tablePause.getPrefHeight() + Gdx.graphics.getWidth()/20); tablePause.addAction(Actions.alpha(1, 0.25f)); imageTableBackground.addAction(Actions.sequence(Actions.moveTo( Gdx.graphics.getWidth()/2 - imageTableBackground.getWidth()/2, Gdx.graphics.getHeight()/2 - imageTableBackground.getHeight()/2), Actions.alpha(1, 0.25f))); } public void buttonListener(){ nextButton.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new GameScreen(game)); } }); replayButton.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new GameScreen(game)); } }); replayButton2.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new GameScreen(game)); } }); replayButton3.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new GameScreen(game)); } }); menuButton.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new MainMenuScreen(game)); } }); menuButton2.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ game.setScreen(new MainMenuScreen(game)); } }); resumeButton.addListener(new ClickListener(){ @Override public void clicked(InputEvent event, float x, float y){ GameConstants.GAME_PAUSED = false; imageTableBackground.addAction(Actions.alpha(0, 0.15f)); tablePause.addAction(Actions.alpha(0, 0.15f)); } }); }
The functions :
- I created several functions that will be called when the corresponding event happens : win(), lose(), outOfFuel(), pause(). Basically, these functions will set the size and position of the imageTableBackground based on the size of the corresponding Table. It will then increase the alpha of the Image and theTable so it becomes visible and the player can interact with it. Note that the functions win(), lose() and pause() use a new boolean called "GameConstants.GAME_PAUSED". This boolean is stored in the GameConstants.java even though it is not a constant because I was too lazy to create a class only for it ! We set it to true to make the game stop when the game ends or is on pause.
- I created a draw() function that will be called in the render() loop of the GameScreen. This function will draw the oxygen level and fuel level bars.
- Finally I created a buttonListener() that will be called in the show() of the GameScreen . This function describes the action of each button.
In the GameScreen.java :
To use the HUD, we need to add it to the GameScreen.java :
- In the creator : Only add this line
hud = new HUD(game, stage, skin, mapReader.hero);
- In the render() : The render loop needs more modification, here is the new render() :
public void render(float delta) { Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); camera.displacement(mapReader.hero, tiledMap); camera.update(); if(!GameConstants.GAME_PAUSED){ if(Gdx.input.isKeyPressed(Keys.ESCAPE)){ hud.pause(); } world.step(GameConstants.BOX_STEP, GameConstants.BOX_VELOCITY_ITERATIONS, GameConstants.BOX_POSITION_ITERATIONS); mapReader.active(); if(mapReader.hero.getOxygenLevel() <= 0){ hud.loseString = "OUT OF OXYGEN !"; hud.lose(); } else if (mapReader.hero.getFuelLevel() <= 0) hud.outOfFuel(); } stage.act(); debugRenderer.render(world, camera.combined); //Drawing graphics game.batch.begin(); hud.draw(); game.batch.end(); stage.draw(); //Test Box2DLight rayHandler.setCombinedMatrix(camera); rayHandler.updateAndRender(); }
- In the show() : add this line
hud.buttonListener();
We also need to modify the ContactListener to display winTable and loseTable in the corresponding situation :
- In the beginContact() :
if(fixtureA.getUserData() != null && fixtureB.getUserData() != null) { //Finish the level if(fixtureA.getUserData().equals("Tom") && fixtureB.getUserData().equals("Exit")) hud.win(); else if(fixtureB.getUserData().equals("Tom") && fixtureA.getUserData().equals("Exit")) hud.win(); }
- And the new postSolve() :
public void postSolve(Contact contact, ContactImpulse impulse) { Body bodyA = contact.getFixtureA().getBody(); Body bodyB = contact.getFixtureB().getBody(); //Hero death by crushing if(bodyA.getUserData().equals("Tom") || bodyB.getUserData().equals("Tom")){ for(int i = 0; i < impulse.getNormalImpulses().length; i++){ if(impulse.getNormalImpulses()[i] > GameConstants.CRUSH_IMPULSE){ hud.loseString = "CRUSHED !"; hud.lose(); } } } }
And that's it! We now have a HUD!