From 24f09bf303a5b841cf3910a3ea4be4b7025487d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=E1=BA=BF=20H=C6=B0ng?= Date: Tue, 30 Sep 2025 01:02:46 +0700 Subject: [PATCH] feat(scene): implement transition Should work :D --- .../java/org/vibecoders/moongazer/Assets.java | 20 ++++++- .../org/vibecoders/moongazer/Constants.java | 12 ++++ .../java/org/vibecoders/moongazer/Game.java | 19 +++++-- .../org/vibecoders/moongazer/scene/Intro.java | 35 +++++++++--- .../moongazer/scene/Transition.java | 56 +++++++++++++++++++ 5 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/org/vibecoders/moongazer/scene/Transition.java diff --git a/app/src/main/java/org/vibecoders/moongazer/Assets.java b/app/src/main/java/org/vibecoders/moongazer/Assets.java index 4502f0b..6c0e072 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Assets.java +++ b/app/src/main/java/org/vibecoders/moongazer/Assets.java @@ -1,18 +1,34 @@ package org.vibecoders.moongazer; +import org.slf4j.Logger; + import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.graphics.Texture; public class Assets { private static final AssetManager assetManager = new AssetManager(); + private static final Logger log = org.slf4j.LoggerFactory.getLogger(Assets.class); public static T getAsset(String fileName, Class type) { return assetManager.get(fileName, type); } - public static void loadAll() { - // We load all assets here for simplicity :) + /** + * Loads assets required for the intro scene only. + * + * This is used to load the logo before the main assets are loaded. + */ + public static void loadIntroAndWait() { assetManager.load("icons/logo.png", Texture.class); + waitUntilLoaded(); + } + + public static void loadAll() { + log.info("Loading all assets...."); + log.warn("stub"); + } + + public static void waitUntilLoaded() { assetManager.finishLoading(); } diff --git a/app/src/main/java/org/vibecoders/moongazer/Constants.java b/app/src/main/java/org/vibecoders/moongazer/Constants.java index 7e6351c..4040289 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Constants.java +++ b/app/src/main/java/org/vibecoders/moongazer/Constants.java @@ -1,5 +1,9 @@ package org.vibecoders.moongazer; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; + /** * Client configuration constants and default values * used throughout the Moongazer client application. @@ -12,4 +16,12 @@ 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 76accf0..89afd88 100644 --- a/app/src/main/java/org/vibecoders/moongazer/Game.java +++ b/app/src/main/java/org/vibecoders/moongazer/Game.java @@ -11,28 +11,38 @@ import org.vibecoders.moongazer.scene.*; 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; SpriteBatch batch; Texture logo; Scene currentScene; Scene introScene; + public static Scene mainMenuScene; @Override public void create() { - log.info("Loading assets..."); - Assets.loadAll(); - log.info("Assets loaded successfully."); + log.info("Loading intro assets..."); + Assets.loadIntroAndWait(); + log.info("Intro assets loaded successfully."); batch = new SpriteBatch(); currentScene = introScene = new Intro(); + mainMenuScene = new MainMenu(); } @Override public void render() { + // Handle transition if any + if (transition != null) { + batch.begin(); + transition.render(batch); + batch.end(); + return; + } switch (Game.state) { case INTRO: currentScene = introScene; break; case MAIN_MENU: - // Render main menu scene + currentScene = mainMenuScene; break; case IN_GAME: // Render in-game scene @@ -48,6 +58,7 @@ public class Game extends ApplicationAdapter { @Override public void dispose() { introScene.dispose(); + mainMenuScene.dispose(); Assets.dispose(); log.debug("Resources disposed"); } diff --git a/app/src/main/java/org/vibecoders/moongazer/scene/Intro.java b/app/src/main/java/org/vibecoders/moongazer/scene/Intro.java index 7e6276a..9fe69e4 100644 --- a/app/src/main/java/org/vibecoders/moongazer/scene/Intro.java +++ b/app/src/main/java/org/vibecoders/moongazer/scene/Intro.java @@ -1,36 +1,57 @@ package org.vibecoders.moongazer.scene; -import static org.vibecoders.moongazer.Constants.WINDOW_HEIGHT; -import static org.vibecoders.moongazer.Constants.WINDOW_WIDTH; +import static org.vibecoders.moongazer.Constants.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.vibecoders.moongazer.Assets; +import org.vibecoders.moongazer.Game; +import org.vibecoders.moongazer.State; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.ScreenUtils; +/** + * Intro scene displaying the game logo and handling asset loading. + */ public class Intro extends Scene { private Texture logo; private long startTime; private long endTime = 0; private static final Logger log = LoggerFactory.getLogger(Intro.class); + /** + * Initializes the intro scene, starts loading assets. + */ public Intro() { logo = Assets.getAsset("icons/logo.png", Texture.class); startTime = System.currentTimeMillis() + 500; + log.info("Starting to load all remaining assets..."); + Assets.loadAll(); } + /** + * Renders the intro scene. + * @param batch The SpriteBatch to draw with. + */ + @Override public void render(SpriteBatch batch) { + if (System.currentTimeMillis() > endTime + 2000 && endTime != 0) { + Assets.waitUntilLoaded(); + if (Game.transition == null) { + Game.transition = new Transition(this, Game.mainMenuScene, State.MAIN_MENU, 1000); + } + batch.draw(TEXTURE_BLACK, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + return; + } ScreenUtils.clear(Color.BLACK); - log.debug("Rendering logo at position: ({}, {})", WINDOW_WIDTH / 2 - logo.getWidth() / 4, - WINDOW_HEIGHT / 2 - logo.getHeight() / 4); + // log.debug("Rendering logo at position: ({}, {})", WINDOW_WIDTH / 2 - logo.getWidth() / 4, WINDOW_HEIGHT / 2 - logo.getHeight() / 4); var currentOpacity = (float) (System.currentTimeMillis() - startTime) / 1000; if (currentOpacity > 1) { if (endTime == 0) { - endTime = System.currentTimeMillis() + 3000; + endTime = System.currentTimeMillis() + 2000; } currentOpacity = 1 - ((float) (System.currentTimeMillis() - endTime) / 1000); } @@ -38,8 +59,4 @@ public class Intro extends Scene { batch.draw(logo, WINDOW_WIDTH / 2 - logo.getWidth() / 4, WINDOW_HEIGHT / 2 - logo.getHeight() / 4, logo.getWidth() / 2, logo.getHeight() / 2); } - - public void dispose() { - log.debug("sybau"); - } } diff --git a/app/src/main/java/org/vibecoders/moongazer/scene/Transition.java b/app/src/main/java/org/vibecoders/moongazer/scene/Transition.java new file mode 100644 index 0000000..8a072ca --- /dev/null +++ b/app/src/main/java/org/vibecoders/moongazer/scene/Transition.java @@ -0,0 +1,56 @@ +package org.vibecoders.moongazer.scene; + +import org.slf4j.Logger; +import org.vibecoders.moongazer.Game; +import org.vibecoders.moongazer.State; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; + +/** + * Handles transitions between scenes with a linear transition effect. + */ +public class Transition extends Scene { + private Scene from; + private Scene to; + private State targetState; + private long startTime; + private long duration; + + private static final Logger log = org.slf4j.LoggerFactory.getLogger(Transition.class); + + /** + * Creates a new transition between two scenes. + * @param from The scene to transition from. + * @param to The scene to transition to. + * @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) { + this.from = from; + this.to = to; + this.targetState = targetState; + this.duration = duration; + startTime = System.currentTimeMillis(); + } + + /** + * Renders the transition effect. + * @param batch The SpriteBatch to draw with. + */ + @Override + public void render(SpriteBatch batch) { + var toOpacity = ((float) (System.currentTimeMillis() - startTime)) / duration; + if (toOpacity >= 0.99) { + log.debug("Transition complete to state: {}", targetState); + Game.state = targetState; + Game.transition = null; + return; + } + var fromOpacity = 1 - toOpacity; + log.debug("Transition opacities - from: {}, to: {}", fromOpacity, toOpacity); + batch.setColor(1, 1, 1, fromOpacity); + from.render(batch); + batch.setColor(1, 1, 1, toOpacity); + to.render(batch); + } +}