diff --git a/app/src/main/java/org/vibecoders/moongazer/Constants.java b/app/src/main/java/org/vibecoders/moongazer/Constants.java index 4040289..4fc6b71 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Constants.java +++ b/app/src/main/java/org/vibecoders/moongazer/Constants.java @@ -16,12 +16,4 @@ public class Constants { public static final int WINDOW_WIDTH = 1280; public static final int WINDOW_HEIGHT = 720; public static final String WINDOW_TITLE = "Moongazer"; - public static final Texture TEXTURE_WHITE = new Texture(new Pixmap(1, 1, Pixmap.Format.RGBA8888) {{ - setColor(Color.WHITE); - fill(); - }}); - public static final Texture TEXTURE_BLACK = new Texture(new Pixmap(1, 1, Pixmap.Format.RGBA8888) {{ - setColor(Color.BLACK); - fill(); - }}); } diff --git a/app/src/main/java/org/vibecoders/moongazer/Game.java b/app/src/main/java/org/vibecoders/moongazer/Game.java index 7dbd0cb..c7ab57e 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Game.java +++ b/app/src/main/java/org/vibecoders/moongazer/Game.java @@ -7,6 +7,8 @@ import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import java.util.ArrayList; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.vibecoders.moongazer.managers.Assets; @@ -14,8 +16,8 @@ import org.vibecoders.moongazer.scenes.*; public class Game extends ApplicationAdapter { private static final Logger log = LoggerFactory.getLogger(Game.class); - public static State state = State.INTRO; - public static Transition transition = null; + public State state = State.INTRO; + public Transition transition = null; SpriteBatch batch; // UI stage public Stage stage; @@ -23,7 +25,8 @@ public class Game extends ApplicationAdapter { // Scenes Scene currentScene; Scene introScene; - public static Scene mainMenuScene; + public Scene mainMenuScene; + public ArrayList gameScenes; @Override public void create() { @@ -38,7 +41,9 @@ public class Game extends ApplicationAdapter { root.setFillParent(true); stage.addActor(root); // Scene initialization + gameScenes = new ArrayList<>(); currentScene = introScene = new Intro(this); + gameScenes.add(introScene); // By the end of the intro, the main menu scene will be created and assigned to Game.mainMenuScene } @@ -54,7 +59,7 @@ public class Game extends ApplicationAdapter { stage.draw(); return; } - switch (Game.state) { + switch (this.state) { case INTRO: currentScene = introScene; break; @@ -67,6 +72,20 @@ public class Game extends ApplicationAdapter { default: log.warn("Unknown state: {}", state); } + + for (var scene : gameScenes) { + // log.trace("Checking scene visibility: {}", scene.getClass().getSimpleName()); + if (scene != currentScene && scene.root.isVisible()) { + log.trace("Hiding scene: {}", scene.getClass().getSimpleName()); + scene.root.setVisible(false); + } + } + + if (!currentScene.root.isVisible()) { + log.trace("Showing current scene: {}", currentScene.getClass().getSimpleName()); + currentScene.root.setVisible(true); + } + batch.begin(); currentScene.render(batch); batch.end(); diff --git a/app/src/main/java/org/vibecoders/moongazer/Main.java b/app/src/main/java/org/vibecoders/moongazer/Main.java index 9013301..a49e8e3 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Main.java +++ b/app/src/main/java/org/vibecoders/moongazer/Main.java @@ -2,6 +2,8 @@ package org.vibecoders.moongazer; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration.GLEmulation; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.vibecoders.moongazer.Constants.*; @@ -20,6 +22,7 @@ public class Main { */ public static void main(String[] args) { Lwjgl3ApplicationConfiguration cfg = new Lwjgl3ApplicationConfiguration(); + cfg.setOpenGLEmulation(GLEmulation.GL32, 3, 2); cfg.setTitle(WINDOW_TITLE); cfg.setWindowedMode(WINDOW_WIDTH, WINDOW_HEIGHT); cfg.useVsync(true); diff --git a/app/src/main/java/org/vibecoders/moongazer/managers/Assets.java b/app/src/main/java/org/vibecoders/moongazer/managers/Assets.java index b4d6772..dee003b 100644 --- a/app/src/main/java/org/vibecoders/moongazer/managers/Assets.java +++ b/app/src/main/java/org/vibecoders/moongazer/managers/Assets.java @@ -5,6 +5,8 @@ import org.slf4j.Logger; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.assets.loaders.FileHandleResolver; import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGeneratorLoader; @@ -19,9 +21,21 @@ public class Assets { private static final ArrayList loadedFonts = new ArrayList<>(); private static boolean startLoadAll = false; private static boolean loadedAll = false; + private static Texture textureWhite; + private static Texture textureBlack; public static T getAsset(String fileName, Class type) { - return assetManager.get(fileName, type); + try { + if (!assetManager.isLoaded(fileName, type)) { + log.warn("Asset not loaded: {}", fileName); + assetManager.load(fileName, type); + assetManager.finishLoadingAsset(fileName); + } + return assetManager.get(fileName, type); + } catch (Exception e) { + log.error("Failed to load asset: {}", fileName, e); + throw new RuntimeException("Asset loading failed: " + fileName, e); + } } /** @@ -71,6 +85,9 @@ public class Assets { assetManager.setLoader(com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver)); assetManager.setLoader(BitmapFont.class, ".ttf", new FreetypeFontLoader(resolver)); + // Load all assets here + assetManager.load("textures/main_menu/background.png", Texture.class); + assetManager.load("textures/main_menu/title.png", Texture.class); } public static boolean isLoadedAll() { @@ -83,8 +100,7 @@ public class Assets { public static void waitUntilLoaded() { assetManager.finishLoading(); - if (startLoadAll) { - log.info("All assets loaded."); + if (startLoadAll) {; loadedAll = true; } } @@ -93,7 +109,37 @@ public class Assets { return assetManager; } + public static Texture getWhiteTexture() { + if (textureWhite == null) { + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + pixmap.setColor(Color.WHITE); + pixmap.fill(); + textureWhite = new Texture(pixmap); + pixmap.dispose(); // Important: dispose pixmap after creating texture + } + return textureWhite; + } + + public static Texture getBlackTexture() { + if (textureBlack == null) { + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + pixmap.setColor(Color.BLACK); + pixmap.fill(); + textureBlack = new Texture(pixmap); + pixmap.dispose(); + } + return textureBlack; + } + public static void dispose() { assetManager.dispose(); + if (textureWhite != null) { + textureWhite.dispose(); + textureWhite = null; + } + if (textureBlack != null) { + textureBlack.dispose(); + textureBlack = null; + } } } diff --git a/app/src/main/java/org/vibecoders/moongazer/scenes/Intro.java b/app/src/main/java/org/vibecoders/moongazer/scenes/Intro.java index b5cbcb5..a0ca145 100644 --- a/app/src/main/java/org/vibecoders/moongazer/scenes/Intro.java +++ b/app/src/main/java/org/vibecoders/moongazer/scenes/Intro.java @@ -29,6 +29,8 @@ public class Intro extends Scene { startTime = System.currentTimeMillis() + 500; log.info("Starting to load all remaining assets..."); Assets.loadAll(); + game.mainMenuScene = new MainMenu(game); + game.gameScenes.add(game.mainMenuScene); } /** @@ -38,12 +40,12 @@ public class Intro extends Scene { @Override public void render(SpriteBatch batch) { if (System.currentTimeMillis() > endTime + 2000 && endTime != 0) { - if (Game.transition == null) { + if (game.transition == null) { Assets.waitUntilLoaded(); - Game.mainMenuScene = new MainMenu(game); - Game.transition = new Transition(this, Game.mainMenuScene, State.MAIN_MENU, 1000); + log.info("All assets loaded successfully."); + game.transition = new Transition(game, this, game.mainMenuScene, State.MAIN_MENU, 1000); } - batch.draw(TEXTURE_BLACK, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + batch.draw(Assets.getBlackTexture(), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); return; } ScreenUtils.clear(Color.BLACK); diff --git a/app/src/main/java/org/vibecoders/moongazer/scenes/MainMenu.java b/app/src/main/java/org/vibecoders/moongazer/scenes/MainMenu.java index 06c720a..6f7e19c 100644 --- a/app/src/main/java/org/vibecoders/moongazer/scenes/MainMenu.java +++ b/app/src/main/java/org/vibecoders/moongazer/scenes/MainMenu.java @@ -11,15 +11,19 @@ import org.vibecoders.moongazer.managers.Assets; import org.vibecoders.moongazer.Game; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; -/** - * Main menu scene. - */ public class MainMenu extends Scene { - Label textLabel; + private Label newGameLabel; + private Label loadGameLabel; + private Label settingsLabel; + private Label quitGameLabel; + + private Texture backgroundTexture; + private Texture titleTexture; public MainMenu(Game game) { super(game); @@ -82,14 +86,24 @@ public class MainMenu extends Scene { game.root.addActor(settingsButton.getActor()); game.root.addActor(exitButton.getActor()); } - /** - * Renders the main menu scene. - * @param batch The SpriteBatch to draw with. - */ + @Override public void render(SpriteBatch batch) { - batch.draw(TEXTURE_WHITE, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - // Unneeded as using Scene2D Stage to render the label - // textLabel.draw(batch, 1.0f); + batch.draw(backgroundTexture, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + + float targetTitleWidth = 300f; + float originalWidth = titleTexture.getWidth(); + float originalHeight = titleTexture.getHeight(); + float scale = targetTitleWidth / originalWidth; + float titleWidth = originalWidth * scale; + float titleHeight = originalHeight * scale; + float titleX = (WINDOW_WIDTH - titleWidth) / 2f; + float titleY = WINDOW_HEIGHT * 0.58f; + batch.draw(titleTexture, titleX, titleY, titleWidth, titleHeight); + + newGameLabel.draw(batch, 1.0f); + loadGameLabel.draw(batch, 1.0f); + settingsLabel.draw(batch, 1.0f); + quitGameLabel.draw(batch, 1.0f); } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/vibecoders/moongazer/scenes/Scene.java b/app/src/main/java/org/vibecoders/moongazer/scenes/Scene.java index 7865bf2..9d793e8 100644 --- a/app/src/main/java/org/vibecoders/moongazer/scenes/Scene.java +++ b/app/src/main/java/org/vibecoders/moongazer/scenes/Scene.java @@ -5,13 +5,16 @@ import org.vibecoders.moongazer.Game; import org.vibecoders.moongazer.managers.Assets; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.scenes.scene2d.ui.Table; public abstract class Scene { protected final Logger log = org.slf4j.LoggerFactory.getLogger(getClass()); + public Table root; public Scene(Game game) { this(); } public Scene() { + root = new Table(); if (!Assets.isLoadedAll() && Assets.isStartLoadAll()) { Assets.waitUntilLoaded(); } diff --git a/app/src/main/java/org/vibecoders/moongazer/scenes/Transition.java b/app/src/main/java/org/vibecoders/moongazer/scenes/Transition.java index 3309fb2..ab8d63d 100644 --- a/app/src/main/java/org/vibecoders/moongazer/scenes/Transition.java +++ b/app/src/main/java/org/vibecoders/moongazer/scenes/Transition.java @@ -9,6 +9,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; * Handles transitions between scenes with a linear transition effect. */ public class Transition extends Scene { + private Game game; private Scene from; private Scene to; private State targetState; @@ -22,7 +23,10 @@ public class Transition extends Scene { * @param targetState The target state of the game after the transition. * @param duration The duration of the transition in milliseconds. */ - public Transition(Scene from, Scene to, State targetState, long duration) { + public Transition(Game game, Scene from, Scene to, State targetState, long duration) { + // Transition does not need to render UI elements + this.root = null; + this.game = game; this.from = from; this.to = to; this.targetState = targetState; @@ -39,15 +43,17 @@ public class Transition extends Scene { var toOpacity = ((float) (System.currentTimeMillis() - startTime)) / duration; if (toOpacity >= 0.99) { log.trace("Transition complete to state: {}", targetState); - Game.state = targetState; - Game.transition = null; + game.state = targetState; + game.transition = null; return; } var fromOpacity = 1 - toOpacity; log.trace("Transition opacities - from: {}, to: {}", fromOpacity, toOpacity); batch.setColor(1, 1, 1, fromOpacity); + from.root.setVisible(true); from.render(batch); batch.setColor(1, 1, 1, toOpacity); + to.root.setVisible(true); to.render(batch); } } diff --git a/app/src/main/resources/textures/main_menu/background.png b/app/src/main/resources/textures/main_menu/background.png new file mode 100644 index 0000000..e9512b2 Binary files /dev/null and b/app/src/main/resources/textures/main_menu/background.png differ diff --git a/app/src/main/resources/textures/main_menu/title.png b/app/src/main/resources/textures/main_menu/title.png new file mode 100644 index 0000000..8e068dc Binary files /dev/null and b/app/src/main/resources/textures/main_menu/title.png differ