Java tutorial
/* Point & Hit: A fast paced Android game Copyright (C) 2015 Marien Raat This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jmstudios.pointandhit; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.jmstudios.pointandhit.UserPointer; public class GameScreen implements Screen, InputProcessor { public enum GameState { Running, Paused, GameOver, Calibrating }; GameState gameState; SpriteBatch batch; ShapeRenderer shapeRenderer; Texture img; UserPointer userPointer; TargetManager targetManager; BitmapFont scoreFont; Vector2 screenSize; OneShotGame game; // GameState calibrating float calibrationTime = 0.1f, calibrationTimeLeft; float roll, pitch, azimuth; int frames; // InputMultiplexer's InputMultiplexer gameRunningMultiplexer, gamePausedMultiplexer, gameOverMultiplexer; // Pause menu float scale; Stage pauseStage, gameOverStage, gameRunningStage; Table pauseTable, gameOverTable, gameOverButtonsTable; BitmapFont textFont; ImageButton resumeButton, retryButton, menuButton, pauseButton; Texture transparentShader, heartTex; Label gameOverText, scoreTextLabel, scoreLabel, highScoreTextLabel, highScoreLabel; ImageButton gameOverRetryButton, gameOverMenuButton; public GameScreen(final OneShotGame game) { this.game = game; this.scale = game.scale; batch = new SpriteBatch(); shapeRenderer = new ShapeRenderer(); scoreFont = new BitmapFont(Gdx.files.internal("fonts/deja_vu_sans_large.fnt")); scoreFont.setColor(Color.WHITE); scoreFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); scoreFont.setScale(scale); heartTex = new Texture(Gdx.files.internal("heart.png")); screenSize = new Vector2(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); setupMenus(); // Set up multiplexers gameRunningMultiplexer = new InputMultiplexer(); gameRunningMultiplexer.addProcessor(gameRunningStage); gameRunningMultiplexer.addProcessor(this); gamePausedMultiplexer = new InputMultiplexer(); gamePausedMultiplexer.addProcessor(pauseStage); gamePausedMultiplexer.addProcessor(this); gameOverMultiplexer = new InputMultiplexer(); gameOverMultiplexer.addProcessor(gameOverStage); gameOverMultiplexer.addProcessor(this); } public void setupMenus() { Texture buttonsTex = game.buttons; // Game running menu gameRunningStage = new Stage(); TextureRegion pauseButtonTex = new TextureRegion(buttonsTex, 512, 256, 128, 128); pauseButton = new ImageButton(new TextureRegionDrawable(pauseButtonTex)); pauseButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { pauseGame(); } }); Table pauseButtonTable = new Table(); pauseButtonTable.setPosition(screenSize.x - (pauseButton.getWidth() * scale), screenSize.y - (pauseButton.getHeight() * scale)); pauseButtonTable.add(pauseButton).size(pauseButton.getWidth() * scale); gameRunningStage.addActor(pauseButtonTable); // Set up font textFont = new BitmapFont(Gdx.files.internal("fonts/deja_vu_sans_medium.fnt")); textFont.setColor(Color.WHITE); textFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); textFont.setScale(scale); // Set up transparent shader Pixmap onePixTransparent = new Pixmap(1, 1, Pixmap.Format.RGBA8888); onePixTransparent.setColor(new Color(0, 0, 0, 0.6f)); onePixTransparent.fill(); transparentShader = new Texture(onePixTransparent); // Set up buttons TextureRegion resumeTex = new TextureRegion(buttonsTex, 0, 0, 256, 256), retryTex = new TextureRegion(buttonsTex, 256, 0, 256, 256), menuTex = new TextureRegion(buttonsTex, 512, 0, 256, 256); TextureRegionDrawable resumeDrawable = new TextureRegionDrawable(resumeTex), retryDrawable = new TextureRegionDrawable(retryTex), menuDrawable = new TextureRegionDrawable(menuTex); resumeButton = new ImageButton(resumeDrawable); retryButton = new ImageButton(retryDrawable); menuButton = new ImageButton(menuDrawable); // Click listeners resumeButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { gameState = GameState.Running; giveFocus(); } }); retryButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { retry(); } }); menuButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { goToMainMenu(); } }); // Set up pauseTable float padding = 20 * scale; this.pauseStage = new Stage(); Table wholePauseTable = new Table(); wholePauseTable.setFillParent(true); pauseTable = new Table(); pauseTable.defaults().pad(padding).padTop(padding * 3).padBottom(padding * 3); // Different screen sizes pauseTable.add(resumeButton).size(resumeButton.getWidth() * scale); pauseTable.add(retryButton).size(retryButton.getWidth() * scale); pauseTable.add(menuButton).size(menuButton.getWidth() * scale); wholePauseTable.add(pauseTable).fill(10, 1f); pauseStage.addActor(wholePauseTable); // Set up game over menu gameOverStage = new Stage(); gameOverTable = new Table(); gameOverStage.addActor(gameOverTable); // Labels Label.LabelStyle scoreLabelStyle = new Label.LabelStyle(textFont, Color.WHITE); Label.LabelStyle gameOverLabelStyle = new Label.LabelStyle(scoreFont, Color.WHITE); gameOverText = new Label("Game over", gameOverLabelStyle); scoreTextLabel = new Label("Score: ", scoreLabelStyle); highScoreTextLabel = new Label("Highscore: ", scoreLabelStyle); scoreLabel = new Label("null", gameOverLabelStyle); highScoreLabel = new Label("null", scoreLabelStyle); // Buttons gameOverRetryButton = new ImageButton(retryDrawable); gameOverMenuButton = new ImageButton(menuDrawable); gameOverRetryButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { retry(); } }); gameOverMenuButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { goToMainMenu(); } }); gameOverButtonsTable = new Table(); gameOverButtonsTable.defaults().pad(padding * 2); gameOverButtonsTable.add(gameOverRetryButton).left().size(gameOverRetryButton.getWidth() * scale); gameOverButtonsTable.add(gameOverMenuButton).right().size(gameOverMenuButton.getHeight() * scale); gameOverTable.setFillParent(true); gameOverTable.setDebug(false); gameOverTable.defaults().pad(padding * 2); gameOverTable.add(gameOverText).colspan(3).center(); gameOverTable.row(); gameOverTable.add(scoreLabel).colspan(3).center().pad(8 * padding); gameOverTable.row(); gameOverTable.add(highScoreLabel).colspan(3).center().padTop(0).padBottom(padding * 4); gameOverTable.row(); gameOverTable.add(gameOverButtonsTable).center().fill(10f, 1f).padTop(padding * 8); } protected void goToMainMenu() { game.setScreen(game.mainMenu); } protected void retry() { gameState = GameState.Running; show(); } public void giveFocus() { Gdx.input.setInputProcessor(gameRunningMultiplexer); } @Override public void show() { giveFocus(); Gdx.input.setCatchBackKey(true); userPointer = new UserPointer((int) (screenSize.x / 40), screenSize, game.preferences); targetManager = new TargetManager(2.1f, (int) (screenSize.x * 0.255f), screenSize, userPointer, this); // Calibration roll = Gdx.input.getRoll(); pitch = Gdx.input.getPitch(); azimuth = Gdx.input.getAzimuth(); frames = 1; calibrationTimeLeft = calibrationTime; gameState = GameState.Calibrating; } public void updateGame() { userPointer.update(); targetManager.update(); } @Override public void render(float delta) { if (gameState == GameState.Calibrating) { updateCalibrations(); renderUIOnly(); } else if (gameState == GameState.Running) { updateGame(); renderGame(); } else if (gameState == GameState.Paused) { renderGame(); renderPauseMenu(); } else if (gameState == GameState.GameOver) { renderGameOverMenu(); } } public void renderGame() { Color backgroundColor = targetManager.currentTheme.background; Gdx.gl.glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, 1f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Shape drawing shapeRenderer.begin(ShapeType.Filled); targetManager.draw(shapeRenderer); userPointer.draw(shapeRenderer, targetManager.currentTheme); shapeRenderer.end(); // Sprite drawing batch.begin(); targetManager.draw(batch); CharSequence scoreString = "" + targetManager.getScore(); scoreFont.draw(batch, scoreString, screenSize.x / 20, screenSize.y - screenSize.x / 20); drawHearts(targetManager.lifes, batch); batch.end(); gameRunningStage.act(); gameRunningStage.draw(); } public void renderUIOnly() { Color backgroundColor = targetManager.currentTheme.background; Gdx.gl.glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, 1f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); CharSequence scoreString = "" + targetManager.getScore(); scoreFont.draw(batch, scoreString, screenSize.x / 20, screenSize.y - screenSize.x / 20); drawHearts(targetManager.lifes, batch); batch.end(); gameRunningStage.act(); gameRunningStage.draw(); } public void renderPauseMenu() { batch.begin(); batch.draw(transparentShader, 0, 0, screenSize.x, screenSize.y); batch.end(); pauseStage.act(); pauseStage.draw(); } public void renderGameOverMenu() { // Clear screen Color backgroundColor = targetManager.currentTheme.background; Gdx.gl.glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, 1f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); gameOverStage.act(); gameOverStage.draw(); } public void gameOver() { gameState = GameState.GameOver; Pixmap gameOverButtonsBackground = new Pixmap(1, 1, Format.RGBA8888); Color gameOverButtonsBackgroundColor = targetManager.currentTheme.target.cpy(); gameOverButtonsBackgroundColor.a = 0.8f; gameOverButtonsBackground.setColor(gameOverButtonsBackgroundColor); gameOverButtonsBackground.fill(); TextureRegionDrawable gameOverButtonsBackgroundDrawable = new TextureRegionDrawable( new TextureRegion(new Texture(gameOverButtonsBackground))); gameOverButtonsTable.setBackground(gameOverButtonsBackgroundDrawable); scoreLabel.setText("" + targetManager.score); scoreLabel.setColor(targetManager.currentTheme.target.cpy().mul(1.2f)); int highscore = game.getHighScore(); if (targetManager.score > highscore) { game.setHighScore(targetManager.score); highscore = targetManager.score; } highScoreLabel.setText("Best: " + highscore); // Get HighScore highScoreLabel.setColor(targetManager.currentTheme.bullet); Gdx.input.setInputProcessor(gameOverMultiplexer); } public void pauseGame() { gameState = GameState.Paused; Gdx.input.setInputProcessor(gamePausedMultiplexer); Pixmap pauseMenuBackground = new Pixmap(1, 1, Format.RGBA8888); Color pauseMenuColor = targetManager.currentTheme.target.cpy(); pauseMenuColor.a = 0.8f; pauseMenuBackground.setColor(pauseMenuColor); pauseMenuBackground.fill(); pauseTable.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(pauseMenuBackground)))); } public void drawHearts(int hearts, SpriteBatch batch) { float padding = (screenSize.x / 20) * scale, heartSize = 64 * scale, xMid = screenSize.x / 2, y = screenSize.y - heartSize - padding; switch (hearts) { case 0: break; case 1: float x = screenSize.x / 2 - heartSize / 2; batch.draw(heartTex, x, y, heartSize, heartSize); break; case 2: float x2_1 = xMid - (padding / 2) - heartSize, x2_2 = xMid + (padding / 2); batch.draw(heartTex, x2_1, y, heartSize, heartSize); batch.draw(heartTex, x2_2, y, heartSize, heartSize); break; default: float x3_1 = xMid - (1.5f * heartSize) - padding, x3_2 = screenSize.x / 2 - heartSize / 2, x3_3 = xMid + (heartSize / 2) + padding; batch.draw(heartTex, x3_1, y, heartSize, heartSize); batch.draw(heartTex, x3_2, y, heartSize, heartSize); batch.draw(heartTex, x3_3, y, heartSize, heartSize); break; } } public void updateCalibrations() { roll += Gdx.input.getRoll(); pitch += Gdx.input.getPitch(); azimuth += Gdx.input.getAzimuth(); frames++; calibrationTimeLeft -= Gdx.graphics.getDeltaTime(); if (calibrationTimeLeft < 0) { userPointer.calibrate(roll / frames, pitch / frames, azimuth / frames); gameState = GameState.Running; } } @Override public void dispose() { // TODO: Make dispose function } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } @Override public void pause() { if (gameState == GameState.Running) { pauseGame(); } } @Override public void resume() { } @Override public void hide() { Gdx.input.setCatchBackKey(false); } @Override public boolean keyDown(int keycode) { if (keycode == Keys.BACK) { if (gameState == GameState.Running) { pauseGame(); } else if (gameState == GameState.Paused) { gameState = GameState.Running; giveFocus(); } else if (gameState == GameState.GameOver) { goToMainMenu(); } } return false; } @Override public boolean keyUp(int keycode) { // TODO Auto-generated method stub return false; } @Override public boolean keyTyped(char character) { // TODO Auto-generated method stub return false; } @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) { if (gameState == GameState.Running) { targetManager.screenTouchDown(); } else if (gameState == GameState.Paused) { if (screenY < pauseTable.getY() || screenY > pauseTable.getY() + pauseTable.getHeight()) { gameState = GameState.Running; giveFocus(); } } return true; } @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) { // TODO Auto-generated method stub return false; } @Override public boolean touchDragged(int screenX, int screenY, int pointer) { // TODO Auto-generated method stub return false; } @Override public boolean mouseMoved(int screenX, int screenY) { // TODO Auto-generated method stub return false; } @Override public boolean scrolled(int amount) { // TODO Auto-generated method stub return false; } }