diff --git a/frontend/android/AndroidManifest.xml b/frontend/android/AndroidManifest.xml index a31d082ec1e82f0d323f663a815c40ac63b7c849..b0212e88ad8d4b29038c3f851290e49ecb34ad36 100644 --- a/frontend/android/AndroidManifest.xml +++ b/frontend/android/AndroidManifest.xml @@ -18,7 +18,7 @@ <activity android:name="com.game.tankwars.AndroidLauncher" android:label="@string/app_name" - android:screenOrientation="fullSensor" + android:screenOrientation="landscape" android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout" android:exported="true"> <intent-filter> diff --git a/frontend/assets/menu-textures.atlas b/frontend/assets/menu-textures.atlas index eefba7954bb4313999cd11a8b3877bd43c77c9f2..23a3c9761a3a5be2727d2350d4129568ff94eac6 100644 --- a/frontend/assets/menu-textures.atlas +++ b/frontend/assets/menu-textures.atlas @@ -53,6 +53,13 @@ logo orig: 134, 40 offset: 0, 0 index: -1 +transparent-white-box + rotate: false + xy: 907, 1009 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 typing-cursor rotate: false xy: 2, 2 diff --git a/frontend/assets/menu-textures.png b/frontend/assets/menu-textures.png index 7781c29d8792adc05f5e4f081b3a5828211ed536..c5ba22ba5b4830efdc5441dd056fd6dac89a2b3a 100644 Binary files a/frontend/assets/menu-textures.png and b/frontend/assets/menu-textures.png differ diff --git a/frontend/core/src/com/game/tankwars/TankWarsGame.java b/frontend/core/src/com/game/tankwars/TankWarsGame.java index 7ef42679e50284b36e07c8ab0589db9a656c271d..2e86cff9a98de774ec67e1f01e572798a3b07ef3 100644 --- a/frontend/core/src/com/game/tankwars/TankWarsGame.java +++ b/frontend/core/src/com/game/tankwars/TankWarsGame.java @@ -3,46 +3,16 @@ */ package com.game.tankwars; -import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Game; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Input; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.Sprite; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Interpolation; -import com.badlogic.gdx.graphics.OrthographicCamera; -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.freetype.FreeTypeFontGenerator; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.physics.box2d.Body; -import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; -import com.badlogic.gdx.physics.box2d.World; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.ScreenUtils; -import com.game.tankwars.model.Box2dWorld; -import com.game.tankwars.model.Bullet; -import com.game.tankwars.model.Tank; import com.game.tankwars.view.LoginScreen; -import com.game.tankwars.view.MainMenuScreen; public class TankWarsGame extends Game { - public static int VIEWPORT_WIDTH = 80; - public static int VIEWPORT_HEIGHT = 50; - - private SpriteBatch batch; - private BitmapFont font; + public static int VIEWPORT_WIDTH = 320; + public static int VIEWPORT_HEIGHT = 240; @Override public void create() { - batch = new SpriteBatch(); - font = new BitmapFont(); this.setScreen(new LoginScreen(this)); } @@ -62,7 +32,5 @@ public class TankWarsGame extends Game { @Override public void dispose () { ResourceManager.getInstance().dispose(); - batch.dispose(); - font.dispose(); } } diff --git a/frontend/core/src/com/game/tankwars/controller/LoginController.java b/frontend/core/src/com/game/tankwars/controller/LoginController.java index 37830ddaf42c972655d0bada905645d48289f9c5..845b3facb31fae8197cc82edfc7e014f5a9915b7 100644 --- a/frontend/core/src/com/game/tankwars/controller/LoginController.java +++ b/frontend/core/src/com/game/tankwars/controller/LoginController.java @@ -6,9 +6,8 @@ import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextField; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; -import com.game.tankwars.ResourceManager; import com.game.tankwars.TankWarsGame; -import com.game.tankwars.view.GameScreen; +import com.game.tankwars.view.MainMenuScreen; /** * Todo: Login user on backend @@ -24,7 +23,7 @@ public class LoginController { private final TextButton loginButton; private final TextField usernameField; - public LoginController(final TankWarsGame tankWarsGame, final TextButton loginButton, final TextField usernameField, final Stage stage) { + public LoginController(final TankWarsGame tankWarsGame, TextButton loginButton, TextField usernameField, Stage stage) { this.tankWarsGame = tankWarsGame; this.loginButton = loginButton; this.usernameField = usernameField; @@ -34,6 +33,10 @@ public class LoginController { } public void setEventListeners() { + /* + * Calls the handleInput method when the login button is pressed, + * passing the username typed in the username field as an argument. + */ loginButton.addListener(new InputListener() { @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { @@ -42,11 +45,11 @@ public class LoginController { } }); + /* + * Unfocus text field and remove keyboard when enter is pressed, + * and move camera back to original position. + */ usernameField.addListener(new InputListener() { - /** - * Unfocus text field and remove keyboard when enter is pressed, - * and move camera back to original position. - */ @Override public boolean keyDown(InputEvent event, int keycode) { super.keyDown(event, keycode); @@ -60,11 +63,11 @@ public class LoginController { } }); + /* + * Move camera down when text field is clicked + * to make the field appear above the keyboard. + */ usernameField.addListener(new ClickListener() { - /** - * Move camera down when text field is clicked - * to make the field appear above the keyboard. - */ @Override public void clicked(InputEvent event, float x, float y) { super.clicked(event, x, y); @@ -77,9 +80,7 @@ public class LoginController { public void handleInput(String username) { System.out.println(username); - // TODO: Move clear line to MainMenuController when the main menu is operational - ResourceManager.getInstance().clear(); - tankWarsGame.setScreen(new GameScreen(tankWarsGame)); + tankWarsGame.setScreen(new MainMenuScreen(tankWarsGame)); } } diff --git a/frontend/core/src/com/game/tankwars/controller/MainMenuController.java b/frontend/core/src/com/game/tankwars/controller/MainMenuController.java index f07836cb05399a96cf4dc90497d46a8e382615b7..38d14ea44e9a39069d7abf17d4ab51fd13562f1c 100644 --- a/frontend/core/src/com/game/tankwars/controller/MainMenuController.java +++ b/frontend/core/src/com/game/tankwars/controller/MainMenuController.java @@ -1,64 +1,84 @@ package com.game.tankwars.controller; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.BitmapFont; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.game.tankwars.ResourceManager; import com.game.tankwars.TankWarsGame; -import com.game.tankwars.model.MenuButton; import com.game.tankwars.view.GameScreen; import com.game.tankwars.view.LeaderboardScreen; +import com.game.tankwars.view.LoginScreen; +/** + * Sets the event listeners for the buttons + * on the MainMenuScreen + */ public class MainMenuController { private final TankWarsGame tankWarsGame; - private String username; - private final Array<MenuButton> menuButtons; + private final TextButton findGameButton, highScoreButton, settingsButton, logoutButton; - - public MainMenuController(final TankWarsGame tankWarsGame, final BitmapFont font) { + public MainMenuController(final TankWarsGame tankWarsGame, TextButton findGameButton, + TextButton highScoreButton, TextButton settingsButton, + TextButton logoutButton) { this.tankWarsGame = tankWarsGame; + this.findGameButton = findGameButton; + this.highScoreButton = highScoreButton; + this.settingsButton = settingsButton; + this.logoutButton = logoutButton; - fetchUser(); - - this.menuButtons = new Array<>(); - } - - public Array<MenuButton> setMenuButtons(Texture buttonTexture, BitmapFont font) { - this.menuButtons.add(new MenuButton(buttonTexture, font, "Find Game")); - this.menuButtons.add(new MenuButton(buttonTexture, font, "Leaderboard")); - this.menuButtons.add(new MenuButton(buttonTexture, font, "Settings")); - this.menuButtons.add(new MenuButton(buttonTexture, font, "Log out")); - - return menuButtons; + setEventListeners(); } + private void setEventListeners() { + /* + * Transition to GameScreen + * Clear Resource Manager to dispose all menu-related textures + * TODO: Transition to FindGameScreen and then no longer clear ResourceManager + */ + findGameButton.addListener(new InputListener() { + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + ResourceManager.getInstance().clear(); + tankWarsGame.setScreen(new GameScreen(tankWarsGame)); + return true; + } + }); - public void handleInput(Vector3 touchPos) { - - for (int i = 0; i < menuButtons.size; i++) { - MenuButton menuButton = menuButtons.get(i); - if (touchPos.x >= menuButton.getX() && touchPos.x <= menuButton.getX() + menuButton.getWidth() && - touchPos.y >= menuButton.getY() && touchPos.y <= menuButton.getY() + menuButton.getHeight()) { - - switch (i) { - case 0: tankWarsGame.setScreen(new GameScreen(tankWarsGame)); break; - case 1: tankWarsGame.setScreen(new LeaderboardScreen(tankWarsGame)); break; - case 2: System.out.println("Settings button: Not yet functional"); break; - case 3: System.out.println("Log out button: Not yet functional"); break; - } + /* + * Transition to LeaderboardScreen + */ + highScoreButton.addListener(new InputListener() { + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + tankWarsGame.setScreen(new LeaderboardScreen(tankWarsGame)); + return true; } - } - } + }); - /** - * TODO: Fetch user from backend. For now it only creates a dummy username to pass to the screen - */ - private void fetchUser() { - this.username = "Commander"; - } + /* + * Transition to SettingsScreen (Dummy button for now) + * TODO: Implement the SettingsScreen class and add the transition + */ + settingsButton.addListener(new InputListener() { + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + System.out.println("Settings screen: yet to be implemented"); + return true; + } + }); - public String getUsername() { - return username; + /* + * Transition to LoginScreen + * Log out the user + * TODO: Log out the user - must be done after login functionality is implemented + */ + logoutButton.addListener(new InputListener() { + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + tankWarsGame.setScreen(new LoginScreen(tankWarsGame)); + return true; + } + }); } } diff --git a/frontend/core/src/com/game/tankwars/view/LoginScreen.java b/frontend/core/src/com/game/tankwars/view/LoginScreen.java index 0e5051580e8ebba1aa99ab17243f7a5018a74012..d59d545b072b57f19e517cce5d29b0134e440306 100644 --- a/frontend/core/src/com/game/tankwars/view/LoginScreen.java +++ b/frontend/core/src/com/game/tankwars/view/LoginScreen.java @@ -2,25 +2,15 @@ package com.game.tankwars.view; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.Event; -import com.badlogic.gdx.scenes.scene2d.InputEvent; -import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.TextField; -import com.badlogic.gdx.scenes.scene2d.ui.Value; -import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; -import com.badlogic.gdx.scenes.scene2d.utils.FocusListener; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.ScreenUtils; import com.badlogic.gdx.utils.viewport.ExtendViewport; @@ -37,7 +27,6 @@ import com.game.tankwars.controller.LoginController; public class LoginScreen implements Screen { private final TankWarsGame tankWarsGame; private Stage stage; - private TextField usernameField; public LoginScreen(final TankWarsGame tankWarsGame) { this.tankWarsGame = tankWarsGame; @@ -45,7 +34,7 @@ public class LoginScreen implements Screen { @Override public void show() { - stage = new Stage(new ExtendViewport(320, 240), new SpriteBatch()); + stage = new Stage(new ExtendViewport(tankWarsGame.getViewportWidth(), tankWarsGame.getViewportHeight()), new SpriteBatch()); Gdx.input.setInputProcessor(stage); Skin skin = ResourceManager.getInstance().loadAndGetMenuAssets(); @@ -60,7 +49,7 @@ public class LoginScreen implements Screen { Label loginLabel = new Label("Log in", skin.get("header", Label.LabelStyle.class)); Label usernameLabel = new Label("Username", skin.get("default", Label.LabelStyle.class)); - usernameField = new TextField("", + TextField usernameField = new TextField("", skin.get("default", TextField.TextFieldStyle.class)); usernameField.setAlignment(Align.center); TextButton loginButton = new TextButton("Log in", @@ -126,6 +115,7 @@ public class LoginScreen implements Screen { @Override public void hide() { Gdx.input.setInputProcessor(null); + dispose(); } diff --git a/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java b/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java index 5f665eca1c8d107a7da082fbd28ae1af64cf14c4..08bdda59b6053737b193c24e98d39291c0fc0b03 100644 --- a/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java +++ b/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java @@ -3,116 +3,105 @@ package com.game.tankwars.view; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.Screen; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.BitmapFont; -import com.badlogic.gdx.graphics.g2d.GlyphLayout; -import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.utils.ScreenUtils; -import com.badlogic.gdx.utils.viewport.FitViewport; -import com.badlogic.gdx.utils.viewport.Viewport; +import com.badlogic.gdx.utils.viewport.ExtendViewport; +import com.game.tankwars.ResourceManager; import com.game.tankwars.TankWarsGame; import com.game.tankwars.controller.MainMenuController; -import com.game.tankwars.model.MenuButton; +/** + * Main menu screen with buttons leading to the different screens in the application. + * + * The following transitions from the buttons are supported by the MainMenuController: + * Find game button transitions to GameScreen + * Highscore button transitions to LeaderboardScreen + * Settings button transitions to no screen as of now + * Log out button transitions to log in screen + */ public class MainMenuScreen extends InputAdapter implements Screen { private final TankWarsGame tankWarsGame; - private final SpriteBatch batch; - private final BitmapFont font; - private final Viewport viewport; - private final MainMenuController controller; - private final Sprite logo; - private final Texture welcomeBox; - private final Texture background; - private final Texture menuButtonTexture; - private final GlyphLayout welcomeLayout, usernameLayout; - - private final Array<MenuButton> menuButtons; - - private final Vector3 touchPos; - - private float heightPercentile; - - /** - * Main menu - * Only supports portrait mode - */ - public MainMenuScreen(final TankWarsGame tankWarsGame, final SpriteBatch batch, final BitmapFont font, final OrthographicCamera camera) { - this.tankWarsGame = tankWarsGame; - this.batch = batch; - this.font = font; - this.font.getData().setScale(0.55f); - - // TODO: Add landscape support, both on startup and on rotation - viewport = new FitViewport(camera.viewportWidth, camera.viewportHeight, camera); - heightPercentile = viewport.getWorldHeight() / 100; - controller = new MainMenuController(this.tankWarsGame, this.font); - - logo = new Sprite(new Texture("tankwars-logo.png")); - logo.setScale(1.3f); - logo.setPosition(-logo.getWidth() / 2, 32 * heightPercentile); - - welcomeBox = new Texture("main-menu-welcome-box.png"); - welcomeLayout = new GlyphLayout(font, "Welcome to duty"); - usernameLayout = new GlyphLayout(font, controller.getUsername()); + private Stage stage; - background = new Texture("menu-background.png"); - - menuButtonTexture = new Texture("menu-button-2.png"); - menuButtons = controller.setMenuButtons(menuButtonTexture, font); - for (int i = 0; i < menuButtons.size; i++) { - menuButtons.get(i).setPosition(0, -(12 * i - 4) * heightPercentile); - } - - touchPos = new Vector3(); + public MainMenuScreen(final TankWarsGame tankWarsGame) { + this.tankWarsGame = tankWarsGame; } @Override public void show() { - Gdx.input.setInputProcessor(this); + stage = new Stage(new ExtendViewport(tankWarsGame.getViewportWidth(), tankWarsGame.getViewportHeight()), new SpriteBatch()); + Gdx.input.setInputProcessor(stage); + + Skin skin = ResourceManager.getInstance().loadAndGetMenuAssets(); + + Drawable background = skin.getDrawable("camo-background-landscape"); + + Image logo = new Image(skin.getDrawable("logo")); + Drawable headerBox = skin.getDrawable("dark-menu-header"); + Label loginLabel = new Label("Main Menu", skin.get("header", Label.LabelStyle.class)); + + Drawable panelBackground = skin.getDrawable("transparent-white-box"); + TextButton findGameButton = new TextButton("Find game", + skin.get("default", TextButton.TextButtonStyle.class)); + TextButton highScoreButton = new TextButton("Highscore", + skin.get("default", TextButton.TextButtonStyle.class)); + TextButton settingsButton = new TextButton("Settings", + skin.get("default", TextButton.TextButtonStyle.class)); + TextButton logoutButton = new TextButton("Log out", + skin.get("default", TextButton.TextButtonStyle.class)); + + //--- Layout + Table rootTable = new Table(); + rootTable.setFillParent(true); + + float logoWidth = stage.getWidth() / 4f; + + Table headerTable = new Table(); + headerTable.background(headerBox); + headerTable.add(logo).width(logoWidth). + height(logo.getHeight() / logo.getWidth() * logoWidth).expandX(); + headerTable.add(loginLabel).expandX(); + + float buttonWidth = 3 * stage.getWidth() / 7f; + float buttonHeight = 32; + + Table panelTable = new Table(); + panelTable.background(panelBackground); + panelTable.row().expandY(); + panelTable.add(findGameButton).width(buttonWidth).expandX().height(buttonHeight); + panelTable.add(highScoreButton).width(buttonWidth).expandX().height(buttonHeight); + panelTable.row().expandY(); + panelTable.add(settingsButton).width(buttonWidth).expandX().height(buttonHeight); + panelTable.add(logoutButton).width(buttonWidth).expandX().height(buttonHeight); + + rootTable.background(background); + rootTable.add(headerTable).fillX().height(2 * stage.getHeight() / 7f).top(); + rootTable.row().expandY(); + rootTable.add(panelTable).fillX().height(3 * stage.getHeight() / 7f).bottom(); + + stage.addActor(rootTable); + new MainMenuController(this.tankWarsGame, findGameButton, highScoreButton, settingsButton, logoutButton); } @Override public void render(float delta) { ScreenUtils.clear(0, 0, 0, 1); - batch.setProjectionMatrix(viewport.getCamera().combined); - - batch.begin(); - batch.draw(background, -background.getWidth() / 2f, -background.getHeight() / 2f); - - logo.draw(batch); - - batch.draw(welcomeBox, -welcomeBox.getWidth() / 2f, 12 * heightPercentile, - viewport.getWorldWidth(), welcomeBox.getHeight()); - font.draw(batch, welcomeLayout, -welcomeLayout.width / 2, - 12 * heightPercentile + welcomeBox.getHeight() * 4f/5f); - font.draw(batch, usernameLayout, -usernameLayout.width / 2, - 12 * heightPercentile + welcomeBox.getHeight() * 4f/5f - 2 * welcomeLayout.height); - - for (MenuButton menuButton : menuButtons) { - batch.draw(menuButton.getTexture(), menuButton.getX(), menuButton.getY()); - font.draw(batch, menuButton.getContent(), menuButton.getContentX(), menuButton.getContentY()); - } - batch.end(); - } - - @Override - public boolean touchDown(int screenX, int screenY, int pointer, int button) { - touchPos.set(screenX, screenY, 0); - viewport.unproject(touchPos); - controller.handleInput(touchPos); - return true; + stage.act(delta); + stage.draw(); } @Override public void resize(int width, int height) { - viewport.update(width, height); - heightPercentile = viewport.getWorldHeight() / 100; + stage.getViewport().update(width, height); } @Override @@ -128,13 +117,11 @@ public class MainMenuScreen extends InputAdapter implements Screen { @Override public void hide() { Gdx.input.setInputProcessor(null); + dispose(); } @Override public void dispose() { - logo.getTexture().dispose(); - welcomeBox.dispose(); - background.dispose(); - menuButtonTexture.dispose(); + stage.dispose(); } }