Compare commits
14 Commits
f4694a1f1e
...
65880853ac
| Author | SHA1 | Date | |
|---|---|---|---|
| 65880853ac | |||
| b1cbef4dd8 | |||
| affa81a3e8 | |||
| 63c81f98c2 | |||
| 381ff306cb | |||
| a4bece69f9 | |||
| 967926c4d2 | |||
| f4d5a351fb | |||
| e7c614c6cd | |||
| b79865d59c | |||
| 0ad13ad368 | |||
| 67100eba23 | |||
| 94b618f66c | |||
| ac37bb43eb |
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
val libgdxVersion = "1.13.5"
|
||||
val gdxVideoVersion = "1.3.3"
|
||||
|
||||
plugins {
|
||||
// Apply the application plugin to add support for building a CLI application in Java.
|
||||
@ -46,6 +47,10 @@ dependencies {
|
||||
// Logging
|
||||
implementation("org.slf4j:slf4j-api:2.1.0-alpha1")
|
||||
implementation("ch.qos.logback:logback-classic:1.5.18")
|
||||
|
||||
// gdx-video
|
||||
implementation("com.badlogicgames.gdx-video:gdx-video:${gdxVideoVersion}")
|
||||
implementation("com.badlogicgames.gdx-video:gdx-video-lwjgl3:${gdxVideoVersion}")
|
||||
}
|
||||
|
||||
// Apply a specific Java toolchain to ease working on different environments.
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
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.
|
||||
|
||||
@ -26,6 +26,7 @@ public class Game extends ApplicationAdapter {
|
||||
Scene currentScene;
|
||||
Scene introScene;
|
||||
public Scene mainMenuScene;
|
||||
public Scene settingsScene;
|
||||
public ArrayList<Scene> gameScenes;
|
||||
|
||||
@Override
|
||||
@ -44,7 +45,7 @@ public class Game extends ApplicationAdapter {
|
||||
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
|
||||
// By the end of the intro, other secenes will be created and assigned to Game.mainMenuScene
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,6 +66,9 @@ public class Game extends ApplicationAdapter {
|
||||
case MAIN_MENU:
|
||||
currentScene = mainMenuScene;
|
||||
break;
|
||||
case SETTINGS:
|
||||
currentScene = settingsScene;
|
||||
break;
|
||||
case IN_GAME:
|
||||
// Render in-game scene
|
||||
break;
|
||||
@ -80,11 +84,6 @@ public class Game extends ApplicationAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentScene.root.isVisible()) {
|
||||
log.trace("Showing current scene: {}", currentScene.getClass().getSimpleName());
|
||||
currentScene.root.setVisible(true);
|
||||
}
|
||||
|
||||
batch.begin();
|
||||
currentScene.render(batch);
|
||||
batch.end();
|
||||
|
||||
@ -3,5 +3,6 @@ package org.vibecoders.moongazer;
|
||||
public enum State {
|
||||
INTRO,
|
||||
MAIN_MENU,
|
||||
SETTINGS,
|
||||
IN_GAME
|
||||
}
|
||||
|
||||
@ -2,9 +2,11 @@ package org.vibecoders.moongazer.managers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
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.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
@ -13,18 +15,26 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGeneratorLoader;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreetypeFontLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Assets {
|
||||
private static final AssetManager assetManager = new AssetManager();
|
||||
private static final FileHandleResolver resolver = new InternalFileHandleResolver();
|
||||
private static final Logger log = org.slf4j.LoggerFactory.getLogger(Assets.class);
|
||||
private static final ArrayList<String> loadedFonts = new ArrayList<>();
|
||||
private static final HashMap<String, FileHandle> loadedFiles = new HashMap<>();
|
||||
private static boolean startLoadAll = false;
|
||||
private static boolean loadedAll = false;
|
||||
private static Texture textureWhite;
|
||||
private static Texture textureBlack;
|
||||
|
||||
public static <T> T getAsset(String fileName, Class<T> type) {
|
||||
if (type == FileHandle.class) {
|
||||
if (!loadedFiles.containsKey(fileName)) {
|
||||
loadAny(fileName);
|
||||
}
|
||||
return type.cast(loadedFiles.get(fileName));
|
||||
}
|
||||
try {
|
||||
if (!assetManager.isLoaded(fileName, type)) {
|
||||
log.warn("Asset not loaded: {}", fileName);
|
||||
@ -41,7 +51,8 @@ public class Assets {
|
||||
/**
|
||||
* Loads and returns a BitmapFont of the specified size from the given TTF file.
|
||||
* <p>
|
||||
* Special file name "ui" is mapped to "fonts/H7GBKHeavy.ttf" (Wuthering Waves UI font).
|
||||
* Special file name "ui" is mapped to "fonts/H7GBKHeavy.ttf" (Wuthering Waves
|
||||
* UI font).
|
||||
*
|
||||
* @param fileName the font name
|
||||
* @param size the font size
|
||||
@ -74,6 +85,19 @@ public class Assets {
|
||||
waitUntilLoaded();
|
||||
}
|
||||
|
||||
public static void loadAny(String fileName) {
|
||||
FileHandle fh = Gdx.files.internal(fileName);
|
||||
if (!fh.exists()) {
|
||||
log.error("File does not exist: {}", fileName);
|
||||
return;
|
||||
}
|
||||
if (loadedFiles.containsKey(fileName)) {
|
||||
return;
|
||||
}
|
||||
loadedFiles.put(fileName, fh);
|
||||
}
|
||||
|
||||
|
||||
public static void loadAll() {
|
||||
if (startLoadAll) {
|
||||
log.warn("loadAll() called multiple times!");
|
||||
@ -89,6 +113,12 @@ public class Assets {
|
||||
assetManager.load("textures/main_menu/background.png", Texture.class);
|
||||
assetManager.load("textures/main_menu/title.png", Texture.class);
|
||||
assetManager.load("textures/ui/text_button.png", Texture.class);
|
||||
assetManager.load("textures/ui/IconExitGame.png", Texture.class);
|
||||
assetManager.load("textures/ui/UI_Icon_Setting.png", Texture.class);
|
||||
assetManager.load("textures/ui/ImgReShaSoundOn.png", Texture.class);
|
||||
assetManager.load("textures/ui/UI_Gcg_Icon_Close.png", Texture.class);
|
||||
// "Load" unsupported file types as FileHandle
|
||||
loadAny("videos/main_menu_background.webm");
|
||||
}
|
||||
|
||||
public static boolean isLoadedAll() {
|
||||
@ -101,7 +131,7 @@ public class Assets {
|
||||
|
||||
public static void waitUntilLoaded() {
|
||||
assetManager.finishLoading();
|
||||
if (startLoadAll) {;
|
||||
if (startLoadAll) {
|
||||
loadedAll = true;
|
||||
}
|
||||
}
|
||||
@ -116,7 +146,7 @@ public class Assets {
|
||||
pixmap.setColor(Color.WHITE);
|
||||
pixmap.fill();
|
||||
textureWhite = new Texture(pixmap);
|
||||
pixmap.dispose(); // Important: dispose pixmap after creating texture
|
||||
pixmap.dispose();
|
||||
}
|
||||
return textureWhite;
|
||||
}
|
||||
@ -133,6 +163,13 @@ public class Assets {
|
||||
}
|
||||
|
||||
public static void dispose() {
|
||||
for (var fontKey : loadedFonts) {
|
||||
if (assetManager.isLoaded(fontKey, BitmapFont.class)) {
|
||||
assetManager.unload(fontKey);
|
||||
}
|
||||
}
|
||||
loadedFonts.clear();
|
||||
loadedFiles.clear();
|
||||
assetManager.dispose();
|
||||
if (textureWhite != null) {
|
||||
textureWhite.dispose();
|
||||
|
||||
@ -29,8 +29,11 @@ public class Intro extends Scene {
|
||||
startTime = System.currentTimeMillis() + 500;
|
||||
log.info("Starting to load all remaining assets...");
|
||||
Assets.loadAll();
|
||||
// Create scenes
|
||||
game.mainMenuScene = new MainMenu(game);
|
||||
game.settingsScene = new Settings(game);
|
||||
game.gameScenes.add(game.mainMenuScene);
|
||||
game.gameScenes.add(game.settingsScene);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,8 +60,12 @@ public class Intro extends Scene {
|
||||
}
|
||||
currentOpacity = 1 - ((float) (System.currentTimeMillis() - endTime) / 1000);
|
||||
}
|
||||
batch.setColor(1, 1, 1, currentOpacity);
|
||||
// Multiply with any externally applied alpha (e.g., Transition)
|
||||
float externalAlpha = batch.getColor().a;
|
||||
float finalAlpha = currentOpacity * externalAlpha;
|
||||
batch.setColor(1, 1, 1, finalAlpha);
|
||||
batch.draw(logo, WINDOW_WIDTH / 2 - logo.getWidth() / 4, WINDOW_HEIGHT / 2 - logo.getHeight() / 4,
|
||||
logo.getWidth() / 2, logo.getHeight() / 2);
|
||||
batch.setColor(1, 1, 1, externalAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,32 +2,58 @@ package org.vibecoders.moongazer.scenes;
|
||||
|
||||
import static org.vibecoders.moongazer.Constants.*;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.vibecoders.moongazer.Game;
|
||||
import org.vibecoders.moongazer.State;
|
||||
import org.vibecoders.moongazer.managers.Assets;
|
||||
import org.vibecoders.moongazer.ui.UITextButton;
|
||||
import org.vibecoders.moongazer.Game;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||
import com.badlogic.gdx.video.VideoPlayer;
|
||||
import com.badlogic.gdx.video.VideoPlayerCreator;
|
||||
|
||||
public class MainMenu extends Scene {
|
||||
private Texture backgroundTexture;
|
||||
private VideoPlayer videoPlayer;
|
||||
private FileHandle videoFileHandle;
|
||||
private Texture titleTexture;
|
||||
private float titleY;
|
||||
private float titleX;
|
||||
private float titleWidth;
|
||||
private float titleHeight;
|
||||
private UITextButton[] buttons;
|
||||
private HashMap<Integer, Long> currentKeyDown = new HashMap<>();
|
||||
private float titleY, titleX, titleWidth, titleHeight;
|
||||
private boolean videoPrepared = false;
|
||||
private int currentChoice = -1;
|
||||
|
||||
public MainMenu(Game game) {
|
||||
super(game);
|
||||
backgroundTexture = Assets.getAsset("textures/main_menu/background.png", Texture.class);
|
||||
initVideo();
|
||||
initUI();
|
||||
}
|
||||
|
||||
private void initVideo() {
|
||||
videoPlayer = VideoPlayerCreator.createVideoPlayer();
|
||||
videoFileHandle = Assets.getAsset("videos/main_menu_background.webm", FileHandle.class);
|
||||
try {
|
||||
videoPlayer.load(videoFileHandle);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error("Failed to load video", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
// Title
|
||||
titleTexture = Assets.getAsset("textures/main_menu/title.png", Texture.class);
|
||||
// Scale and position title
|
||||
float targetTitleWidth = 500f;
|
||||
float originalWidth = titleTexture.getWidth();
|
||||
float originalHeight = titleTexture.getHeight();
|
||||
float scale = targetTitleWidth / originalWidth;
|
||||
titleWidth = originalWidth * scale;
|
||||
titleHeight = originalHeight * scale;
|
||||
float scale = targetTitleWidth / titleTexture.getWidth();
|
||||
titleWidth = titleTexture.getWidth() * scale;
|
||||
titleHeight = titleTexture.getHeight() * scale;
|
||||
titleX = (WINDOW_WIDTH - titleWidth) / 2f;
|
||||
titleY = WINDOW_HEIGHT / 2f - titleHeight / 8f;
|
||||
|
||||
@ -37,9 +63,11 @@ public class MainMenu extends Scene {
|
||||
UITextButton loadButton = new UITextButton("Load", font);
|
||||
UITextButton settingsButton = new UITextButton("Settings", font);
|
||||
UITextButton exitButton = new UITextButton("Exit", font);
|
||||
buttons = new UITextButton[] { playButton, loadButton, settingsButton, exitButton };
|
||||
|
||||
int buttonWidth = 300;
|
||||
int buttonHeight = 80;
|
||||
|
||||
playButton.setSize(buttonWidth, buttonHeight);
|
||||
loadButton.setSize(buttonWidth, buttonHeight);
|
||||
settingsButton.setSize(buttonWidth, buttonHeight);
|
||||
@ -47,28 +75,147 @@ public class MainMenu extends Scene {
|
||||
|
||||
int centerX = WINDOW_WIDTH / 2 - buttonWidth / 2;
|
||||
int startY = WINDOW_HEIGHT / 2 - buttonHeight / 2;
|
||||
int buttonSpacing = 65;
|
||||
int spacing = 65;
|
||||
|
||||
playButton.setSize(buttonWidth, buttonHeight);
|
||||
playButton.setPosition(centerX, startY);
|
||||
loadButton.setPosition(centerX, startY - buttonSpacing);
|
||||
settingsButton.setPosition(centerX, startY - buttonSpacing * 2);
|
||||
exitButton.setPosition(centerX, startY - buttonSpacing * 3);
|
||||
loadButton.setSize(buttonWidth, buttonHeight);
|
||||
loadButton.setPosition(centerX, startY - spacing);
|
||||
settingsButton.setSize(buttonWidth, buttonHeight);
|
||||
settingsButton.setPosition(centerX, startY - spacing * 2);
|
||||
exitButton.setSize(buttonWidth, buttonHeight);
|
||||
exitButton.setPosition(centerX, startY - spacing * 3);
|
||||
|
||||
// Mouse click handlers
|
||||
playButton.onClick(() -> log.debug("Play clicked"));
|
||||
loadButton.onClick(() -> log.debug("Load clicked"));
|
||||
settingsButton.onClick(() -> log.debug("Settings clicked"));
|
||||
exitButton.onClick(() -> log.debug("Exit clicked"));
|
||||
settingsButton.onClick(() -> {
|
||||
log.debug("Settings clicked");
|
||||
if (game.transition == null) {
|
||||
game.transition = new Transition(game, this, game.settingsScene, State.SETTINGS, 350);
|
||||
}
|
||||
});
|
||||
exitButton.onClick(() -> {
|
||||
log.debug("Exit clicked");
|
||||
Gdx.app.exit();
|
||||
});
|
||||
|
||||
root.addActor(playButton.getActor());
|
||||
root.addActor(loadButton.getActor());
|
||||
root.addActor(settingsButton.getActor());
|
||||
root.addActor(exitButton.getActor());
|
||||
|
||||
// Keyboard navigation handling
|
||||
initKeyboardHandling();
|
||||
game.stage.addActor(root);
|
||||
}
|
||||
|
||||
private void initKeyboardHandling() {
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
final int index = i;
|
||||
buttons[i].onHoverEnter(() -> {
|
||||
log.trace("Button hover enter: {}", index);
|
||||
if (currentChoice != index) {
|
||||
if (currentChoice != -1) {
|
||||
buttons[currentChoice].hoverExit();
|
||||
}
|
||||
currentChoice = index;
|
||||
}
|
||||
});
|
||||
buttons[i].onHoverExit(() -> {
|
||||
if (currentChoice == index) {
|
||||
currentChoice = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
root.addListener(new InputListener() {
|
||||
@Override
|
||||
public boolean keyDown(InputEvent event, int keycode) {
|
||||
sKeyDown(event, keycode);
|
||||
currentKeyDown.put(keycode, System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
root.addListener(new InputListener() {
|
||||
@Override
|
||||
public boolean keyUp(InputEvent event, int keycode) {
|
||||
currentKeyDown.remove(keycode);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startVideoOnce() {
|
||||
if (videoPlayer == null || videoPrepared)
|
||||
return;
|
||||
if (videoFileHandle == null || !videoFileHandle.exists())
|
||||
return;
|
||||
if (game.transition == null && game.state != State.MAIN_MENU)
|
||||
return;
|
||||
videoPlayer.setLooping(true);
|
||||
videoPlayer.play();
|
||||
videoPrepared = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual key down handler. ((s)cene key down)
|
||||
*
|
||||
* @param event not used for now, can be null
|
||||
* @param keycode the keycode of the pressed key
|
||||
*/
|
||||
public void sKeyDown(InputEvent event, int keycode) {
|
||||
log.trace("Key pressed: {}", keycode);
|
||||
switch (keycode) {
|
||||
case Input.Keys.UP:
|
||||
currentChoice = (currentChoice - 1 + 4) % 4;
|
||||
break;
|
||||
case Input.Keys.DOWN:
|
||||
currentChoice = (currentChoice + 1) % 4;
|
||||
break;
|
||||
case Input.Keys.RIGHT:
|
||||
case Input.Keys.ENTER:
|
||||
if (currentChoice != -1) {
|
||||
buttons[currentChoice].click();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (currentChoice != -1) {
|
||||
log.trace("Current choice: {}", currentChoice);
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (i == currentChoice) {
|
||||
buttons[i].hoverEnter();
|
||||
} else {
|
||||
buttons[i].hoverExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SpriteBatch batch) {
|
||||
batch.draw(backgroundTexture, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
// SDL way of handling key input XD
|
||||
for (Map.Entry<Integer, Long> entry : currentKeyDown.entrySet()) {
|
||||
Integer keyCode = entry.getKey();
|
||||
Long timeStamp = entry.getValue();
|
||||
if (System.currentTimeMillis() - timeStamp > 100) {
|
||||
sKeyDown(null, keyCode);
|
||||
currentKeyDown.put(keyCode, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
startVideoOnce();
|
||||
videoPlayer.update();
|
||||
Texture videoTexture = videoPlayer.getTexture();
|
||||
batch.draw(videoTexture, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
batch.draw(titleTexture, titleX, titleY, titleWidth, titleHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
videoPlayer.dispose();
|
||||
}
|
||||
}
|
||||
@ -10,8 +10,10 @@ 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 Game game;
|
||||
public Scene(Game game) {
|
||||
this();
|
||||
this.game = game;
|
||||
}
|
||||
public Scene() {
|
||||
root = new Table();
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package org.vibecoders.moongazer.scenes;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
|
||||
import static org.vibecoders.moongazer.Constants.*;
|
||||
|
||||
import org.vibecoders.moongazer.Game;
|
||||
import org.vibecoders.moongazer.State;
|
||||
import org.vibecoders.moongazer.managers.Assets;
|
||||
import org.vibecoders.moongazer.ui.UIImageButton;
|
||||
|
||||
public class Settings extends Scene {
|
||||
public Settings(Game game) {
|
||||
super(game);
|
||||
// WIP
|
||||
UIImageButton settingButton = new UIImageButton("textures/ui/UI_Icon_Setting.png");
|
||||
UIImageButton exitImgButton = new UIImageButton("textures/ui/IconExitGame.png");
|
||||
UIImageButton soundButton = new UIImageButton("textures/ui/ImgReShaSoundOn.png");
|
||||
UIImageButton closeButton = new UIImageButton("textures/ui/UI_Gcg_Icon_Close.png");
|
||||
settingButton.setSize(50, 50);
|
||||
exitImgButton.setSize(50, 50);
|
||||
soundButton.setSize(50, 50);
|
||||
closeButton.setSize(50, 50);
|
||||
settingButton.setPosition(20, WINDOW_HEIGHT - 70);
|
||||
exitImgButton.setPosition(WINDOW_WIDTH - 70, WINDOW_HEIGHT - 70);
|
||||
soundButton.setPosition(20, 20);
|
||||
closeButton.setPosition(WINDOW_WIDTH - 70, 20);
|
||||
|
||||
root.addActor(settingButton.getActor());
|
||||
root.addActor(exitImgButton.getActor());
|
||||
root.addActor(soundButton.getActor());
|
||||
root.addActor(closeButton.getActor());
|
||||
settingButton.onClick(() -> log.debug("Settings clicked"));
|
||||
exitImgButton.onClick(() -> {
|
||||
log.debug("Exit clicked");
|
||||
if (game.transition == null) {
|
||||
game.transition = new Transition(game, this, game.mainMenuScene, State.MAIN_MENU, 350);
|
||||
}
|
||||
});
|
||||
soundButton.onClick(() -> log.debug("Sound clicked"));
|
||||
closeButton.onClick(() -> log.debug("Close clicked"));
|
||||
|
||||
game.stage.addActor(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SpriteBatch batch) {
|
||||
batch.draw(Assets.getWhiteTexture(), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,6 @@ 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;
|
||||
@ -25,8 +24,8 @@ public class Transition extends Scene {
|
||||
*/
|
||||
public Transition(Game game, Scene from, Scene to, State targetState, long duration) {
|
||||
// Transition does not need to render UI elements
|
||||
super(game);
|
||||
this.root = null;
|
||||
this.game = game;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.targetState = targetState;
|
||||
@ -45,6 +44,10 @@ public class Transition extends Scene {
|
||||
log.trace("Transition complete to state: {}", targetState);
|
||||
game.state = targetState;
|
||||
game.transition = null;
|
||||
// Set keyboard focus to the new scene's root
|
||||
from.root.setVisible(false);
|
||||
to.root.setVisible(true);
|
||||
game.stage.setKeyboardFocus(to.root);
|
||||
return;
|
||||
}
|
||||
var fromOpacity = 1 - toOpacity;
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package org.vibecoders.moongazer.ui;
|
||||
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.EventListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Button;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||
|
||||
public abstract class UIButton {
|
||||
protected Actor actor;
|
||||
protected Button button;
|
||||
public Actor actor;
|
||||
public Button button;
|
||||
|
||||
public Actor getActor() {
|
||||
return actor;
|
||||
@ -24,12 +27,65 @@ public abstract class UIButton {
|
||||
actor.addListener(eventListener);
|
||||
}
|
||||
|
||||
public void click() {
|
||||
// Thx ChatGPT
|
||||
InputEvent down = new InputEvent();
|
||||
down.setType(InputEvent.Type.touchDown);
|
||||
down.setButton(Input.Buttons.LEFT);
|
||||
down.setStageX(button.getX());
|
||||
down.setStageY(button.getY());
|
||||
button.fire(down);
|
||||
|
||||
InputEvent up = new InputEvent();
|
||||
up.setType(InputEvent.Type.touchUp);
|
||||
up.setButton(Input.Buttons.LEFT);
|
||||
up.setStageX(button.getX());
|
||||
up.setStageY(button.getY());
|
||||
button.fire(up);
|
||||
}
|
||||
|
||||
public void hoverEnter() {
|
||||
InputEvent e = new InputEvent();
|
||||
e.setType(InputEvent.Type.enter);
|
||||
e.setPointer(-1);
|
||||
button.fire(e);
|
||||
}
|
||||
|
||||
public void hoverExit() {
|
||||
InputEvent e = new InputEvent();
|
||||
e.setType(InputEvent.Type.exit);
|
||||
e.setPointer(-1);
|
||||
button.fire(e);
|
||||
}
|
||||
|
||||
public void onClick(Runnable action) {
|
||||
button.addListener(new com.badlogic.gdx.scenes.scene2d.utils.ClickListener() {
|
||||
button.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void clicked(com.badlogic.gdx.scenes.scene2d.InputEvent event, float x, float y) {
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
action.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onHoverEnter(Runnable action) {
|
||||
button.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
||||
if (pointer == -1) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onHoverExit(Runnable action) {
|
||||
button.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
|
||||
if (pointer == -1) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,20 @@
|
||||
package org.vibecoders.moongazer.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||
import org.vibecoders.moongazer.managers.Assets;
|
||||
|
||||
public class UIImageButton extends UIButton {
|
||||
public UIImageButton() {
|
||||
this.button = new ImageButton(new ImageButton.ImageButtonStyle());
|
||||
public UIImageButton(String texturePath) {
|
||||
Texture texture = Assets.getAsset(texturePath, Texture.class);
|
||||
TextureRegionDrawable drawable = new TextureRegionDrawable(new TextureRegion(texture));
|
||||
ImageButton.ImageButtonStyle style = new ImageButton.ImageButtonStyle();
|
||||
style.imageUp = drawable;
|
||||
style.imageDown = drawable;
|
||||
style.imageOver = drawable;
|
||||
this.button = new ImageButton(style);
|
||||
this.actor = button;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
app/src/main/resources/textures/ui/IconExitGame.png
Normal file
BIN
app/src/main/resources/textures/ui/IconExitGame.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 480 B |
BIN
app/src/main/resources/textures/ui/ImgReShaSoundOn.png
Normal file
BIN
app/src/main/resources/textures/ui/ImgReShaSoundOn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/resources/textures/ui/UI_Gcg_Icon_Close.png
Normal file
BIN
app/src/main/resources/textures/ui/UI_Gcg_Icon_Close.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 869 B |
BIN
app/src/main/resources/textures/ui/UI_Icon_Setting.png
Normal file
BIN
app/src/main/resources/textures/ui/UI_Icon_Setting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/resources/videos/main_menu_background.webm
Normal file
BIN
app/src/main/resources/videos/main_menu_background.webm
Normal file
Binary file not shown.
Reference in New Issue
Block a user