diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 005304b..6879126 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,6 +17,14 @@ jobs: steps: - uses: actions/checkout@v4 + # Check out the flixelgdx library so Gradle can use the local included build + # instead of pulling from JitPack (which avoids 401/authorization issues). + - name: Checkout flixelgdx library + uses: actions/checkout@v4 + with: + repository: stringdotjar/flixelgdx + path: flixelgdx + # LibGDX typically uses Java 11 or newer. - name: Set up JDK 17 uses: actions/setup-java@v4 @@ -42,7 +50,15 @@ jobs: steps: - uses: actions/checkout@v4 - # LibGDX typically uses Java 11 or newer. + # Check out the flixelgdx library so Gradle can use the local included build + # instead of pulling from JitPack (which avoids 401/authorization issues). + - name: Checkout flixelgdx library + uses: actions/checkout@v4 + with: + repository: stringdotjar/flixelgdx + path: flixelgdx + + # LibGDX typically uses Java 11 or newer, however we use Java 17 for modern standards. - name: Set up JDK 17 uses: actions/setup-java@v4 with: diff --git a/android/build.gradle b/android/build.gradle index f819286..ae66ecb 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -58,7 +58,9 @@ configurations { natives } dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' implementation project(':polyverse') - implementation project(':flixelgdx:android') + implementation("com.github.stringdotjar:flixelgdx-android:master-SNAPSHOT") { + changing = true + } } configurations { diff --git a/build.gradle b/build.gradle index e22e156..92ae681 100644 --- a/build.gradle +++ b/build.gradle @@ -69,4 +69,12 @@ subprojects { } } +// Always fetch latest master-SNAPSHOT for flixelgdx from JitPack (if not found locally). +configurations.all { + resolutionStrategy { + cacheChangingModulesFor 0, 'seconds' + cacheDynamicVersionsFor 0, 'seconds' + } +} + eclipse.project.name = 'Polyverse' + '-parent' diff --git a/flixelgdx/android/build.gradle b/flixelgdx/android/build.gradle deleted file mode 100644 index e2c423e..0000000 --- a/flixelgdx/android/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -eclipse.project.name = appName + '-flixelgdx-android' - -apply plugin: 'com.android.library' - -android { - namespace "me.stringdotjar.flixelgdx" - compileSdk 36 - - defaultConfig { - multiDexEnabled = true - minSdkVersion 34 - targetSdkVersion 35 - } - compileOptions { - coreLibraryDesugaringEnabled = true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } -} - -repositories { - // needed for AAPT2, may be needed for other tools - google() -} - -configurations { - coreLibraryDesugaring -} - -dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' - - api project(":flixelgdx:core") - api "androidx.multidex:multidex:2.0.1" - api "games.rednblack.miniaudio:gdx-miniaudio-platform:$miniaudioVersion:natives-armeabi-v7a" - api "games.rednblack.miniaudio:gdx-miniaudio-platform:$miniaudioVersion:natives-arm64-v8a" - api "games.rednblack.miniaudio:gdx-miniaudio-platform:$miniaudioVersion:natives-x86" - api "games.rednblack.miniaudio:gdx-miniaudio-platform:$miniaudioVersion:natives-x86_64" - api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a" - api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a" - api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86" - api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64" - api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" -} diff --git a/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/FlixelAndroidLauncher.java b/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/FlixelAndroidLauncher.java deleted file mode 100644 index f440895..0000000 --- a/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/FlixelAndroidLauncher.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.stringdotjar.flixelgdx.backend.android; - -import android.app.Activity; -import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; -import me.stringdotjar.flixelgdx.Flixel; -import me.stringdotjar.flixelgdx.FlixelGame; -import me.stringdotjar.flixelgdx.backend.android.alert.FlixelAndroidAlerter; - -/** - * Launches the Android version of the FlixelGDX game. - */ -public class FlixelAndroidLauncher { - - /** - * Launches the Android version of the game with the given game instance. - * - *
This should be called from the onCreate method of the Android launcher class, and the - * game instance should be created in the same general area. - * - * @param game The game instance to launch. This should already be initialized with the desired configuration values. - */ - public static void launch(FlixelGame game, Activity activity) { - Flixel.initialize(game, new FlixelAndroidAlerter(activity)); - - AndroidApplicationConfiguration configuration = new AndroidApplicationConfiguration(); - configuration.useImmersiveMode = true; - } -} diff --git a/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/alert/FlixelAndroidAlerter.java b/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/alert/FlixelAndroidAlerter.java deleted file mode 100644 index e7ace9a..0000000 --- a/flixelgdx/android/src/main/java/me/stringdotjar/flixelgdx/backend/android/alert/FlixelAndroidAlerter.java +++ /dev/null @@ -1,44 +0,0 @@ -package me.stringdotjar.flixelgdx.backend.android.alert; - -import android.app.Activity; -import android.app.AlertDialog; -import me.stringdotjar.flixelgdx.backend.Alerter; - -public class FlixelAndroidAlerter implements Alerter { - - private final Activity activity; - - public FlixelAndroidAlerter(Activity activity) { - this.activity = activity; - } - - @Override - public void showInfoAlert(String title, String message) { - showAlert(title, message, android.R.drawable.ic_dialog_info); - } - - @Override - public void showWarningAlert(String title, String message) { - showAlert(title, message, android.R.drawable.ic_dialog_alert); - } - - @Override - public void showErrorAlert(String title, String message) { - showAlert(title, message, android.R.drawable.stat_notify_error); - } - - private void showAlert(final String title, final String message, final int iconResId) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - new AlertDialog.Builder(activity) - .setTitle(title) - .setMessage(message) - .setIcon(iconResId) - .setPositiveButton("OK", null) - .setCancelable(true) - .show(); - } - }); - } -} diff --git a/flixelgdx/build.gradle b/flixelgdx/build.gradle deleted file mode 100644 index 40479df..0000000 --- a/flixelgdx/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -subprojects { - - group = 'me.stringdotjar.flixelgdx' - version = '1.0.0' - - // Force Java 17 for the entire framework. - if (!project.path.contains('android')) { - plugins.withType(JavaPlugin).tap { - configureEach { - java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } - } - } - } - } -} diff --git a/flixelgdx/core/build.gradle b/flixelgdx/core/build.gradle deleted file mode 100644 index 42fa47f..0000000 --- a/flixelgdx/core/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' -eclipse.project.name = appName + '-flixelgdx-core' - -apply plugin: "java-library" - -// Embed version from build so Flixel.getVersion() can read it at runtime (Gradle does not set JAR manifest like Maven). -def generateFlixelVersion = tasks.register('generateFlixelVersion', WriteProperties) { - outputFile = layout.buildDirectory.file("generated/version/version.properties") - property("version", project.version) -} -processResources.from(generateFlixelVersion) { - into "me/stringdotjar/flixelgdx" -} - -java { - sourceCompatibility = 17 - targetCompatibility = 17 -} - -// Put dependencies on module path so module-info.java can resolve requires (automatic modules). -tasks.named('compileJava') { - doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] - classpath = files() - } -} - -// Require Eclipse (and IDEs that use Eclipse project model) to put dependencies on the module path, -// making "requires gdx" etc. resolve. Without this, only Gradle's compileJava sees them as modules. -eclipse.classpath.file { - whenMerged { - entries.findAll { it instanceof org.gradle.plugins.ide.eclipse.model.Library }.each { - it.entryAttributes['module'] = 'true' - } - } -} - -// Avoid JPMS split-package error: gdx and gdx-jnigen-loader both expose com.badlogic.gdx.utils. -configurations.all { - exclude group: 'com.badlogicgames.gdx', module: 'gdx-jnigen-loader' -} - -dependencies { - api "com.badlogicgames.gdx:gdx:$gdxVersion" - api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" - api "com.github.tommyettinger:anim8-gdx:$anim8Version" - api "com.github.tommyettinger:libgdx-utils:$utilsVersion" - api "games.rednblack.miniaudio:miniaudio:$miniaudioVersion" - - implementation "org.fusesource.jansi:jansi:$jansiVersion" - implementation "org.jetbrains:annotations:26.1.0" - - if (enableGraalNative == 'true') { - implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion" - } -} diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java deleted file mode 100644 index 24f3790..0000000 --- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java +++ /dev/null @@ -1,538 +0,0 @@ -package me.stringdotjar.flixelgdx; - -import com.badlogic.gdx.Application.ApplicationType; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.assets.AssetManager; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Stage; -import games.rednblack.miniaudio.MAGroup; -import games.rednblack.miniaudio.MASound; -import games.rednblack.miniaudio.MiniAudio; -import games.rednblack.miniaudio.loader.MASoundLoader; -import me.stringdotjar.flixelgdx.util.FlixelPathsUtil; -import me.stringdotjar.flixelgdx.backend.Alerter; -import me.stringdotjar.flixelgdx.display.FlixelCamera; -import me.stringdotjar.flixelgdx.display.FlixelState; -import me.stringdotjar.flixelgdx.logging.FlixelLogMode; -import me.stringdotjar.flixelgdx.logging.FlixelLogger; -import me.stringdotjar.flixelgdx.signal.FlixelSignal; -import me.stringdotjar.flixelgdx.signal.FlixelSignalData.MusicPlayedSignalData; -import me.stringdotjar.flixelgdx.signal.FlixelSignalData.UpdateSignalData; -import me.stringdotjar.flixelgdx.signal.FlixelSignalData.StateSwitchSignalData; -import me.stringdotjar.flixelgdx.signal.FlixelSignalData.SoundPlayedSignalData; -import org.jetbrains.annotations.NotNull; - -import java.io.InputStream; -import java.util.Properties; - -/** - * Global manager and utility class for Flixel. - * - *
This is where you want to do the main things, like switching screens, playing sounds/music, etc. - */ -public final class Flixel { - - /** The current {@code FlixelState} being displayed. */ - private static FlixelState state; - - /** The main audio object used to create, */ - private static MiniAudio engine; - - /** The global asset manager used to obtain preloaded assets. */ - private static AssetManager assetManager; - - /** The audio group for all sound effects, including the current music. */ - private static MAGroup soundsGroup; - - /** The sound for playing music throughout the game. */ - private static MASound music; - - /** The current master volume that is set. */ - private static float masterVolume = 1; - - /** The static instance used to access the core elements of the game. */ - private static FlixelGame game; - - /** The system to use for displaying alert notifications to the user. */ - private static Alerter alerter; - - /** Has the global manager been initialized yet? */ - private static boolean initialized = false; - - /** The default logger used by {@link #info}, {@link #warn}, and {@link #error}. */ - private static FlixelLogger defaultLogger; - - /** - * Initializes the global manager. - * - *
This can only be called once. If attempted to be executed again, the game will throw an - * exception. - * - * @param gameInstance The instance of the game to use. - * @param alertSystem The system to use for displaying alert notifications to the user. - * @throws IllegalStateException If Flixel has already been initialized. - */ - public static void initialize(@NotNull FlixelGame gameInstance, @NotNull Alerter alertSystem) { - if (initialized) { - throw new IllegalStateException("Flixel has already been initialized!"); - } - game = gameInstance; - alerter = alertSystem; - - assetManager = new AssetManager(); - - // Set up the game's global audio system. - engine = new MiniAudio(); - soundsGroup = engine.createGroup(); - assetManager.setLoader(MASound.class, new MASoundLoader(engine, assetManager.getFileHandleResolver())); - - defaultLogger = new FlixelLogger(FlixelLogMode.SIMPLE); - initialized = true; - } - - /** - * Sets the current screen to the provided screen. - * - * @param newState The new {@code FlixelState} to set as the current screen. - */ - public static void switchState(FlixelState newState) { - Signals.preStateSwitch.dispatch(new StateSwitchSignalData(newState)); - if (!initialized) { - throw new IllegalStateException("Flixel has not been initialized yet!"); - } - if (newState == null) { - throw new IllegalArgumentException("New state cannot be null!"); - } - if (state != null) { - state.hide(); - state.dispose(); - } - game.resetCameras(); - state = newState; - state.create(); - Signals.postStateSwitch.dispatch(new StateSwitchSignalData(newState)); - } - - /** - * Plays a new sound effect. - * - *
When you want to play a sound externally, outside the assets folder, you can use a {@link - * FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playSound(FlixelPathsUtil.external("your/path/here").path());
- * }
- *
- * @param path The path to load the sound from. Note that if you're loading an external sound
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @return The new sound instance.
- */
- public static MASound playSound(String path) {
- return playSound(path, 1, false, null, false);
- }
-
- /**
- * Plays a new sound effect.
- *
- * When you want to play a sound externally, outside the assets folder, you can use a {@link - * FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playSound(FlixelPathsUtil.external("your/path/here").path(), 1);
- * }
- *
- * @param path The path to load the sound from. Note that if you're loading an external sound
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new sound with.
- * @return The new sound instance.
- */
- public static MASound playSound(String path, float volume) {
- return playSound(path, volume, false, null, false);
- }
-
- /**
- * Plays a new sound effect.
- *
- * When you want to play a sound externally, outside the assets folder, you can use a {@link - * FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playSound(FlixelPathsUtil.external("your/path/here").path(), 1, false);
- * }
- *
- * @param path The path to load the sound from. Note that if you're loading an external sound
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new sound with.
- * @param looping Should the new sound loop indefinitely?
- * @return The new sound instance.
- */
- public static MASound playSound(String path, float volume, boolean looping) {
- return playSound(path, volume, looping, null, false);
- }
-
- /**
- * Plays a new sound effect.
- *
- * When you want to play a sound externally, outside the assets folder, you can use a {@link - * FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * // If null is passed down for the group, then the default sound group will be used.
- * Flixel.playSound(FlixelPathsUtil.external("your/path/here").path(), 1, false, null);
- * }
- *
- * @param path The path to load the sound from. Note that if you're loading an external sound
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new sound with.
- * @param looping Should the new sound loop indefinitely?
- * @param group The sound group to add the new sound to. If {@code null} is passed down, then the
- * default sound group will be used.
- * @return The new sound instance.
- */
- public static MASound playSound(String path, float volume, boolean looping, MAGroup group) {
- return playSound(path, volume, looping, group, false);
- }
-
- /**
- * Plays a new sound effect.
- *
- * When you want to play a sound externally, outside the assets folder, you can use a {@link - * FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * // If null is passed down for the group, then the default sound group will be used.
- * // For the boolean attribute "external", you only should make it true for mobile builds,
- * // otherwise just simply leave it be or make it "false" for other platforms like desktop.
- * Flixel.playSound(FlixelPathsUtil.external("your/path/here").path(), 1, false, null, true);
- * }
- *
- * @param path The path to load the sound from. Note that if you're loading an external sound
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new sound with.
- * @param looping Should the new sound loop indefinitely?
- * @param group The sound group to add the new sound to. If {@code null} is passed down, then the
- * default sound group will be used.
- * @param external Should this sound be loaded externally? (This is only for mobile platforms!)
- * @return The new sound instance.
- */
- public static MASound playSound(@NotNull String path, float volume, boolean looping, MAGroup group, boolean external) {
- String resolvedPath = external ? path : FlixelPathsUtil.resolveAudioPath(path);
- MASound sound = engine.createSound(resolvedPath, (short) 0, (group != null) ? group : soundsGroup, external);
- Signals.preSoundPlayed.dispatch(new SoundPlayedSignalData(sound));
- sound.setVolume(volume);
- sound.setLooping(looping);
- sound.play();
- Signals.postSoundPlayed.dispatch(new SoundPlayedSignalData(sound));
- return sound;
- }
-
- /**
- * Sets the current music playing for the entire game.
- *
- * When you want to play music located externally, outside the assets folder, you can use a - * {@link FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playMusic(FlixelPathsUtil.external("your/path/here").path());
- * }
- *
- * @param path The path to load the music from. Note that if you're loading an external sound file
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- */
- public static MASound playMusic(String path) {
- return playMusic(path, 1, true, false);
- }
-
- /**
- * Sets the current music playing for the entire game.
- *
- * When you want to play music located externally, outside the assets folder, you can use a - * {@link FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playMusic(FlixelPathsUtil.external("your/path/here").path(), 1);
- * }
- *
- * @param path The path to load the music from. Note that if you're loading an external sound file
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new music with.
- */
- public static MASound playMusic(String path, float volume) {
- return playMusic(path, volume, true, false);
- }
-
- /**
- * Sets the current music playing for the entire game.
- *
- * When you want to play music located externally, outside the assets folder, you can use a - * {@link FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * Flixel.playMusic(FlixelPathsUtil.external("your/path/here").path(), 1, false);
- * }
- *
- * @param path The path to load the music from. Note that if you're loading an external sound file
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new music with.
- * @param looping Should the new music loop indefinitely?
- */
- public static MASound playMusic(String path, float volume, boolean looping) {
- return playMusic(path, volume, looping, false);
- }
-
- /**
- * Sets the current music playing for the entire game.
- *
- * When you want to play music located externally, outside the assets folder, you can use a - * {@link FileHandle} like so: - * - *
{@code
- * // Notice how it uses the FlixelPathsUtil class provided by Flixel'.
- * // For the boolean attribute "external", you only should make it true for mobile builds,
- * // otherwise just simply leave it be or make it "false" for other platforms like desktop.
- * Flixel.playMusic(FlixelPathsUtil.external("your/path/here").path(), 1, false, true);
- * }
- *
- * @param path The path to load the music from. Note that if you're loading an external sound file
- * outside the game's assets, you should use {@link FileHandle}; otherwise, just pass down a
- * regular string (without {@code assets/} at the beginning).
- * @param volume The volume to play the new music with.
- * @param looping Should the new music loop indefinitely?
- * @param external Should this music be loaded externally? (This is only for mobile platforms!)
- */
- public static MASound playMusic(String path, float volume, boolean looping, boolean external) {
- Signals.preMusicPlayed.dispatch(new MusicPlayedSignalData(music));
- if (music != null) {
- music.stop();
- }
- String resolvedPath = external ? path : FlixelPathsUtil.resolveAudioPath(path);
- music = engine.createSound(resolvedPath, (short) 0, soundsGroup, external);
- music.setVolume(volume);
- music.setLooping(looping);
- music.play();
- Signals.postMusicPlayed.dispatch(new MusicPlayedSignalData(music));
- return music;
- }
-
- /**
- * Sets the game master/global volume, which is automatically applied to all current sounds.
- *
- * @param volume The new master volume to set.
- */
- public static void setMasterVolume(float volume) {
- engine.setMasterVolume(!(volume > 1.0) ? volume : 1.0f);
- masterVolume = volume;
- }
-
- /**
- * Shows an info alert notification to the user.
- *
- * @param title The title of the alert.
- * @param message The message of the alert.
- */
- public static void showInfoAlert(String title, String message) {
- alerter.showInfoAlert(title, message);
- }
-
- /**
- * Shows a warning alert notification to the user.
- *
- * @param title The title of the alert.
- * @param message The message of the alert.
- */
- public static void showWarningAlert(String title, String message) {
- alerter.showWarningAlert(title, message);
- }
-
- /**
- * Shows an error alert notification to the user.
- *
- * @param title The title of the alert.
- * @param message The message of the alert.
- */
- public static void showErrorAlert(String title, String message) {
- alerter.showErrorAlert(title, message);
- }
-
- public static boolean keyPressed(int key) {
- return Gdx.input.isKeyPressed(key);
- }
-
- public static boolean keyJustPressed(int key) {
- return Gdx.input.isKeyJustPressed(key);
- }
-
- public static void info(Object message) {
- info(defaultLogger.getDefaultTag(), message);
- }
-
- public static void info(String tag, Object message) {
- defaultLogger.info(tag, message);
- }
-
- public static void warn(Object message) {
- warn(defaultLogger.getDefaultTag(), message);
- }
-
- public static void warn(String tag, Object message) {
- defaultLogger.warn(tag, message);
- }
-
- public static void error(String message) {
- error(defaultLogger.getDefaultTag(), message, null);
- }
-
- public static void error(String tag, Object message) {
- error(tag, message, null);
- }
-
- public static void error(String tag, Object message, Throwable throwable) {
- defaultLogger.error(tag, message, throwable);
- }
-
- public static void setLogger(@NotNull FlixelLogger logger) {
- defaultLogger = logger;
- }
-
- public static void setDefaultLogTag(@NotNull String tag) {
- defaultLogger.setDefaultTag(tag);
- }
-
- public static Alerter getAlerter() {
- return alerter;
- }
-
- public static FlixelLogger getLogger() {
- return defaultLogger;
- }
-
- public static FlixelLogMode getLogMode() {
- return defaultLogger.getLogMode();
- }
-
- public static FlixelGame getGame() {
- return game;
- }
-
- public static Stage getStage() {
- return game.stage;
- }
-
- public static FlixelState getState() {
- return state;
- }
-
- public static MASound getMusic() {
- return music;
- }
-
- public static Vector2 getWindowSize() {
- return game.viewSize;
- }
-
- public static int getWindowWidth() {
- return (int) game.viewSize.x;
- }
-
- public static int getWindowHeight() {
- return (int) game.viewSize.y;
- }
-
- public static MiniAudio getAudioEngine() {
- return engine;
- }
-
- public static float getMasterVolume() {
- return masterVolume;
- }
-
- public static AssetManager getAssetManager() {
- return assetManager;
- }
-
- public static MAGroup getSoundsGroup() {
- return soundsGroup;
- }
-
- public static float getElapsed() {
- return Gdx.graphics.getDeltaTime();
- }
-
- public static FlixelCamera getCamera() {
- return game.getCamera();
- }
-
- public static boolean isFullscreen() {
- return Gdx.graphics.isFullscreen();
- }
-
- public static ApplicationType getPlatform() {
- return Gdx.app.getType();
- }
-
- public static String getVersion() {
- try (InputStream in = Flixel.class.getResourceAsStream("version.properties")) {
- if (in != null) {
- Properties p = new Properties();
- p.load(in);
- String v = p.getProperty("version");
- if (v != null && !v.isEmpty()) return v;
- }
- } catch (Exception ignored) {}
- return "Unknown";
- }
-
- public static void setLogMode(@NotNull FlixelLogMode mode) {
- defaultLogger.setLogMode(mode);
- }
-
- /**
- * Contains all the global events that get dispatched when something happens in the game.
- *
- * This includes anything from the screen being switched, the game updating every frame, and - * just about everything you can think of. - * - *
IMPORTANT DETAIL!: Anything with the {@code pre} and {@code post} prefixes always mean the
- * same thing. If a signal has {@code pre}, then the signal gets ran BEFORE any functionality is
- * executed, and {@code post} means AFTER all functionality was executed.
- */
- public static final class Signals {
-
- public static final FlixelSignal Override this function to update your object's position and appearance.
- * This is where most game rules and behavioral code will go.
- *
- * @param elapsed Seconds elapsed since the last frame.
- */
- public void update(float elapsed) {}
-
- /**
- * Override this function to control how the object is drawn. Doing so is rarely necessary
- * but can be very useful.
- *
- * @param batch The batch used for rendering.
- */
- public void draw(Batch batch) {}
-
- /**
- * Cleans up this object so it can be garbage-collected. A destroyed {@code FlixelBasic}
- * should not be used anymore. Use {@link #kill()} if you only want to disable it
- * temporarily and {@link #revive()} it later.
- */
- public void destroy() {
- exists = false;
- active = false;
- }
-
- /**
- * Flags this object as nonexistent and dead. Default behavior sets both {@link #alive}
- * and {@link #exists} to {@code false}. Use {@link #revive()} to bring it back.
- */
- public void kill() {
- alive = false;
- exists = false;
- }
-
- /**
- * Brings this object back to life by setting {@link #alive} and {@link #exists} to
- * {@code true}.
- */
- public void revive() {
- alive = true;
- exists = true;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "(ID=" + ID + ")";
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelGame.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelGame.java
deleted file mode 100644
index 1330fac..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelGame.java
+++ /dev/null
@@ -1,726 +0,0 @@
-package me.stringdotjar.flixelgdx;
-
-import com.badlogic.gdx.Application;
-import com.badlogic.gdx.ApplicationListener;
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.files.FileHandle;
-import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.Pixmap;
-import com.badlogic.gdx.graphics.Texture;
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-import com.badlogic.gdx.math.Vector2;
-import com.badlogic.gdx.scenes.scene2d.Stage;
-import com.badlogic.gdx.utils.ScreenUtils;
-import com.badlogic.gdx.utils.SnapshotArray;
-
-import me.stringdotjar.flixelgdx.display.FlixelCamera;
-import me.stringdotjar.flixelgdx.display.FlixelState;
-import me.stringdotjar.flixelgdx.logging.FlixelLogger;
-import me.stringdotjar.flixelgdx.text.FlixelFontRegistry;
-import me.stringdotjar.flixelgdx.tween.FlixelTween;
-import me.stringdotjar.flixelgdx.util.FlixelRuntimeUtil;
-import org.fusesource.jansi.AnsiConsole;
-
-import static me.stringdotjar.flixelgdx.signal.FlixelSignalData.UpdateSignalData;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * The game object used for containing the main loop and core elements of the Flixel game.
- *
- * To actually use this properly, you need to create a subclass of this and override
- * the methods you want to change.
- *
- * It is recommended for using this in the following way:
- *
- * Most games interact with this through {@link me.stringdotjar.flixelgdx.FlixelSprite},
- * which adds graphical capabilities on top of this spatial foundation.
- *
- * @see FlxObject (HaxeFlixel)
- */
-public class FlixelObject extends FlixelBasic {
-
- /** X position of the upper left corner of this object in world space. */
- protected float x = 0f;
-
- /** Y position of the upper left corner of this object in world space. */
- protected float y = 0f;
-
- /** The width of this object's hitbox. */
- protected float width = 0f;
-
- /** The height of this object's hitbox. */
- protected float height = 0f;
-
- /** The angle (in degrees) of this object. Used for visual rotation in sprites. */
- protected float angle = 0f;
-
- public FlixelObject() {
- super();
- }
-
- public FlixelObject(float x, float y) {
- super();
- this.x = x;
- this.y = y;
- }
-
- public FlixelObject(float x, float y, float width, float height) {
- super();
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- }
-
- public float getX() {
- return x;
- }
-
- public void setX(float x) {
- this.x = x;
- }
-
- public float getY() {
- return y;
- }
-
- public void setY(float y) {
- this.y = y;
- }
-
- public float getWidth() {
- return width;
- }
-
- public void setWidth(float width) {
- this.width = width;
- }
-
- public float getHeight() {
- return height;
- }
-
- public void setHeight(float height) {
- this.height = height;
- }
-
- public float getAngle() {
- return angle;
- }
-
- public void setAngle(float angle) {
- this.angle = angle;
- }
-
- /**
- * Helper function to set the coordinates of this object.
- *
- * @param x The new x position.
- * @param y The new y position.
- */
- public void setPosition(float x, float y) {
- this.x = x;
- this.y = y;
- }
-
- /**
- * Shortcut for setting both {@link #width} and {@link #height}.
- *
- * @param width The new width.
- * @param height The new height.
- */
- public void setSize(float width, float height) {
- this.width = width;
- this.height = height;
- }
-
- /** Adds {@code dx} to the current X position. */
- public void changeX(float dx) {x += dx;}
-
- /** Adds {@code dy} to the current Y position. */
- public void changeY(float dy) {y += dy;}
-
- /** Adds {@code dr} degrees to the current rotation angle. */
- public void changeRotation(float dr) {angle += dr;}
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "(ID=" + ID
- + ", x=" + x + ", y=" + y
- + ", w=" + width + ", h=" + height + ")";
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelSprite.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelSprite.java
deleted file mode 100644
index 1aef8bb..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/FlixelSprite.java
+++ /dev/null
@@ -1,505 +0,0 @@
-package me.stringdotjar.flixelgdx;
-
-import com.badlogic.gdx.files.FileHandle;
-import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.Texture;
-import com.badlogic.gdx.graphics.g2d.Animation;
-import com.badlogic.gdx.graphics.g2d.Batch;
-import com.badlogic.gdx.graphics.g2d.TextureAtlas;
-import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
-import com.badlogic.gdx.graphics.g2d.TextureRegion;
-import com.badlogic.gdx.math.Rectangle;
-import com.badlogic.gdx.utils.Array;
-import com.badlogic.gdx.utils.Pool;
-import com.badlogic.gdx.utils.XmlReader;
-
-import me.stringdotjar.flixelgdx.display.FlixelCamera;
-
-import com.badlogic.gdx.utils.ObjectMap;
-
-import java.util.Comparator;
-
-/**
- * The core building block of all Flixel games. Extends {@link FlixelObject} with graphical
- * capabilities including texture rendering, animation, scaling, rotation, tinting, and flipping.
- *
- * It is common to extend {@code FlixelSprite} for your own game's needs; for example a
- * {@code SpaceShip} class may extend {@code FlixelSprite} but add additional game-specific fields.
- *
- * @see FlxSprite (HaxeFlixel)
- */
-public class FlixelSprite extends FlixelObject implements Pool.Poolable {
-
- /** The texture image that {@code this} sprite uses. */
- protected Texture texture;
-
- /** The hitbox used for collision detection and angling. */
- protected Rectangle hitbox;
-
- /** The cameras that {@code this} sprite is projected onto. */
- protected FlixelCamera[] cameras;
-
- /** The atlas regions used in this sprite (used for animations). */
- protected Array
- * By default, one camera is created automatically, that is the same size as the
- * window. You can
- * add more cameras or even replace the main camera using utilities in
- * {@code FlixelGame}.
- *
- *
- * Every camera wraps a libGDX {@link Camera} and {@link Viewport} internally.
- * By default, an
- * {@link OrthographicCamera} and {@link FitViewport} are used, but custom types can be provided
- * via the constructor overloads.
- *
- * @see FlxCamera
- * (HaxeFlixel)
- */
-public class FlixelCamera extends FlixelBasic {
-
- /**
- * Any {@code FlixelCamera} with a zoom of 0 (the default constructor value)
- * will receive this zoom level instead.
- */
- public static float defaultZoom = 1.0f;
-
- private Camera camera;
- private Viewport viewport;
-
- /** The alpha value of this camera display (0.0 to 1.0). */
- public float alpha = 1.0f;
-
- /** The angle of the camera display in degrees. */
- public float angle = 0f;
-
- /**
- * Whether the camera display is smooth and filtered, or chunky and pixelated.
- */
- public boolean antialiasing = false;
-
- /** The natural background color of the camera. Defaults to black. */
- public Color bgColor = new Color(Color.BLACK);
-
- /** The color tint of the camera display. */
- public Color color = new Color(Color.WHITE);
-
- /** Whether positions of rendered objects are rounded to whole pixels. */
- public boolean pixelPerfectRender = false;
-
- /**
- * If {@code true}, screen shake offsets will be rounded to whole pixels.
- * If {@code null}, {@link #pixelPerfectRender} is used instead.
- */
- public boolean pixelPerfectShake = false;
-
- /** Whether to use alpha blending for the camera's background fill. */
- public boolean useBgAlphaBlending = false;
-
- /**
- * The X position of this camera's display in native screen pixels.
- * {@link #zoom} does NOT affect this value.
- */
- public float x;
-
- /**
- * The Y position of this camera's display in native screen pixels.
- * {@link #zoom} does NOT affect this value.
- */
- public float y;
-
- /** How wide the camera display is, in game pixels. */
- public int width;
-
- /** How tall the camera display is, in game pixels. */
- public int height;
-
- /**
- * The basic parallax scrolling values, essentially the camera's top-left corner
- * position
- * in world coordinates. Use {@link #focusOn(Vector2)} to look at a specific
- * world point.
- */
- public final Vector2 scroll = new Vector2();
-
- /**
- * Lower bound of the camera's scroll on the X axis. {@code null} = unbounded.
- */
- public Float minScrollX;
-
- /**
- * Upper bound of the camera's scroll on the X axis. {@code null} = unbounded.
- */
- public Float maxScrollX;
-
- /**
- * Lower bound of the camera's scroll on the Y axis. {@code null} = unbounded.
- */
- public Float minScrollY;
-
- /**
- * Upper bound of the camera's scroll on the Y axis. {@code null} = unbounded.
- */
- public Float maxScrollY;
-
- /**
- * The dead zone rectangle, measured from the camera's upper left corner in game pixels.
- * The camera will always keep the focus object inside this zone unless bumping against
- * scroll bounds. For rapid prototyping, use the preset styles with
- * {@link #follow(FlixelObject, FollowStyle, float)}.
- */
- public Rectangle deadzone;
-
- /** Used to force the camera to look ahead of the target. */
- public final Vector2 followLead = new Vector2();
-
- /**
- * The ratio of the distance to the follow target the camera moves per 1/60 sec.
- * {@code 1.0} = snap to target. {@code 0.0} = don't move. Lower values produce
- * smoother motion.
- */
- public float followLerp = 1.0f;
-
- /** The current follow style. */
- public FollowStyle style = FollowStyle.LOCKON;
-
- /** The {@link FlixelObject} the camera follows. Set via {@link #follow}. */
- public FlixelObject target;
-
- /** Offset applied to the follow target's position. */
- public final Vector2 targetOffset = new Vector2();
-
- /** Camera's initial zoom value, captured at construction time. */
- public final float initialZoom;
-
- /**
- * Internal zoom storage. Use {@link #getZoom()} / {@link #setZoom(float)} to access.
- * A value of {@code 1} = 1:1. {@code 2} = 2x zoom in (world appears larger).
- */
- private float zoom;
-
- private boolean flashActive = false;
- private final Color flashColor = new Color(Color.WHITE);
- private float flashDuration = 1f;
- private float flashElapsed = 0f;
- private float flashAlpha = 0f;
- private Runnable flashOnComplete;
-
- private boolean fadeActive = false;
- private final Color fadeColor = new Color(Color.BLACK);
- private float fadeDuration = 1f;
- private float fadeElapsed = 0f;
- private float fadeAlpha = 0f;
- private boolean fadeIn = false;
- private Runnable fadeOnComplete;
-
- private boolean shakeActive = false;
- private float shakeIntensity = 0.05f;
- private float shakeDuration = 0.5f;
- private float shakeElapsed = 0f;
- private FlxAxes shakeAxes = FlxAxes.XY;
- private Runnable shakeOnComplete;
- private float shakeOffsetX = 0f;
- private float shakeOffsetY = 0f;
-
- /** Reusable vector for internal calculations that would otherwise allocate. */
- private final Vector2 tmpVec = new Vector2();
-
- /** Reusable rectangle for internal calculations that would otherwise allocate. */
- private final Rectangle tmpRect = new Rectangle();
-
- /**
- * Creates a camera sized to the current window using the default
- * {@link OrthographicCamera} and {@link FitViewport}.
- */
- public FlixelCamera() {
- this(0f, 0f, Flixel.getWindowWidth(), Flixel.getWindowHeight(), 0f);
- }
-
- /**
- * Creates a camera with the given dimensions using the default camera and
- * viewport types.
- *
- * @param width The width of the camera display in game pixels.
- * @param height The height of the camera display in game pixels.
- */
- public FlixelCamera(int width, int height) {
- this(0f, 0f, width, height, 0f);
- }
-
- /**
- * Creates a camera with a custom libGDX {@link Camera}, wrapped in a default
- * {@link FitViewport}.
- *
- * @param width The width of the camera display in game pixels.
- * @param height The height of the camera display in game pixels.
- * @param camera A custom libGDX Camera (e.g.
- * {@link com.badlogic.gdx.graphics.PerspectiveCamera}).
- */
- public FlixelCamera(int width, int height, Camera camera) {
- this(0f, 0f, width, height, 0f, camera, null);
- }
-
- /**
- * Creates a camera with a custom libGDX {@link Viewport}. The camera is
- * extracted from the viewport.
- *
- * @param width The width of the camera display in game pixels.
- * @param height The height of the camera display in game pixels.
- * @param viewport A custom libGDX Viewport (e.g.
- * {@link com.badlogic.gdx.utils.viewport.ScreenViewport}).
- */
- public FlixelCamera(int width, int height, Viewport viewport) {
- this(0f, 0f, width, height, 0f, null, viewport);
- }
-
- /**
- * Creates a camera at the given display position, size, and zoom level using
- * default types.
- *
- * @param x X location of the camera's display in native screen pixels.
- * @param y Y location of the camera's display in native screen pixels.
- * @param width The width of the camera display in game pixels. 0 = window
- * width.
- * @param height The height of the camera display in game pixels. 0 = window
- * height.
- * @param zoom The initial zoom level. 0 = {@link #defaultZoom}.
- */
- public FlixelCamera(float x, float y, int width, int height, float zoom) {
- this(x, y, width, height, zoom, null, null);
- }
-
- /**
- * Full constructor allowing fully custom libGDX {@link Camera} and
- * {@link Viewport} types.
- *
- *
- * If {@code viewport} is provided, its camera is used (the {@code camera} parameter is ignored).
- * If only {@code camera} is provided, it is wrapped in a new {@link FitViewport}.
- * If neither is provided, an {@link OrthographicCamera} and {@link FitViewport}
- * are created.
- *
- * @param x X location of the camera's display in native screen pixels.
- * @param y Y location of the camera's display in native screen pixels.
- * @param width The width of the camera display in game pixels. 0 = window width.
- * @param height The height of the camera display in game pixels. 0 = window height.
- * @param zoom The initial zoom level. 0 = {@link #defaultZoom}. 2 = 2x magnification.
- * @param camera Custom libGDX Camera, or {@code null} for a default {@link OrthographicCamera}.
- * @param viewport Custom libGDX Viewport, or {@code null} for a default {@link FitViewport}.
- */
- public FlixelCamera(float x, float y, int width, int height, float zoom, Camera camera, Viewport viewport) {
- super();
- this.x = x;
- this.y = y;
- this.width = (width <= 0) ? Flixel.getWindowWidth() : width;
- this.height = (height <= 0) ? Flixel.getWindowHeight() : height;
-
- if (viewport != null) {
- this.viewport = viewport;
- this.camera = viewport.getCamera();
- } else if (camera != null) {
- this.camera = camera;
- this.viewport = new FitViewport(this.width, this.height, this.camera);
- } else {
- this.camera = new OrthographicCamera(this.width, this.height);
- this.viewport = new FitViewport(this.width, this.height, this.camera);
- }
-
- this.zoom = (zoom == 0f) ? defaultZoom : zoom;
- this.initialZoom = this.zoom;
- applyZoom();
- }
-
- /** Returns the underlying libGDX {@link Camera} used for projection. */
- public Camera getCamera() {
- return camera;
- }
-
- /** Returns the underlying libGDX {@link Viewport} used for screen scaling. */
- public Viewport getViewport() {
- return viewport;
- }
-
- /**
- * Applies the viewport's OpenGL viewport rectangle. Call before rendering
- * through this camera.
- */
- public void apply() {
- viewport.apply();
- }
-
- /**
- * Updates the viewport in response to a window resize event.
- *
- * @param screenWidth The new screen width in pixels.
- * @param screenHeight The new screen height in pixels.
- * @param centerCamera Whether to re-center the camera in the viewport.
- */
- public void update(int screenWidth, int screenHeight, boolean centerCamera) {
- viewport.update(screenWidth, screenHeight, centerCamera);
- }
-
- /** Returns the world width of the underlying viewport. */
- public float getWorldWidth() {
- return viewport.getWorldWidth();
- }
-
- /** Returns the world height of the underlying viewport. */
- public float getWorldHeight() {
- return viewport.getWorldHeight();
- }
-
- /**
- * Updates the camera scroll, follow logic, and active effects.
- * Called once per frame from the game loop.
- *
- * @param elapsed Seconds elapsed since the last frame.
- */
- @Override
- public void update(float elapsed) {
- if (!active || !exists) {
- return;
- }
-
- updateFollow(elapsed);
- updateScroll();
- updateFlash(elapsed);
- updateFade(elapsed);
- updateShake(elapsed);
-
- if (camera instanceof OrthographicCamera ortho) {
- ortho.up.set(0, 1, 0);
- ortho.direction.set(0, 0, -1);
- if (angle != 0f) {
- ortho.rotate(angle);
- }
- }
-
- float camX = scroll.x + getViewWidth() / 2f + shakeOffsetX;
- float camY = scroll.y + getViewHeight() / 2f + shakeOffsetY;
- camera.position.set(camX, camY, 0);
- camera.update();
- }
-
- /**
- * Tells this camera to follow the given sprite using {@link FollowStyle#LOCKON}
- * and lerp of 1.
- *
- * @param target The sprite to follow. Pass {@code null} to stop following.
- */
- public void follow(FlixelObject target) {
- follow(target, FollowStyle.LOCKON, 1.0f);
- }
-
- /**
- * Tells this camera to follow the given sprite with the specified style and a
- * lerp of 1.
- *
- * @param target The sprite to follow. Pass {@code null} to stop following.
- * @param style One of the preset {@link FollowStyle} dead zone presets.
- */
- public void follow(FlixelObject target, FollowStyle style) {
- follow(target, style, 1.0f);
- }
-
- /**
- * Tells this camera to follow the given sprite.
- *
- * @param target The sprite to follow. Pass {@code null} to stop following.
- * @param style One of the preset {@link FollowStyle} dead zone presets.
- * @param lerp How much lag the camera should have. {@code 1.0} = snap, lower
- * = smoother.
- */
- public void follow(FlixelObject target, FollowStyle style, float lerp) {
- this.target = target;
- this.style = style;
- this.followLerp = lerp;
- updateDeadzoneForStyle();
- }
-
- /**
- * Instantly moves the camera so the given world point is centered.
- *
- * @param point The world-space point to focus on.
- */
- public void focusOn(Vector2 point) {
- scroll.set(
- point.x - getViewWidth() / 2f,
- point.y - getViewHeight() / 2f
- );
- }
-
- /**
- * Snaps the camera to the current {@link #target} position with no easing, then
- * clamps scroll to bounds. Useful after teleporting the target.
- */
- public void snapToTarget() {
- if (target == null) {
- return;
- }
- float tx = target.getX() + target.getWidth() / 2f + targetOffset.x + followLead.x;
- float ty = target.getY() + target.getHeight() / 2f + targetOffset.y + followLead.y;
- focusOn(tmpVec.set(tx, ty));
- updateScroll();
- }
-
- private void updateFollow(float elapsed) {
- if (target == null) {
- return;
- }
-
- float tx = target.getX() + target.getWidth() / 2f + targetOffset.x + followLead.x;
- float ty = target.getY() + target.getHeight() / 2f + targetOffset.y + followLead.y;
-
- float desiredX = tx - getViewWidth() / 2f;
- float desiredY = ty - getViewHeight() / 2f;
-
- if (followLerp >= 1.0f) {
- scroll.set(desiredX, desiredY);
- return;
- }
-
- if (deadzone != null) {
- float dzLeft = scroll.x + deadzone.x;
- float dzRight = dzLeft + deadzone.width;
- float dzTop = scroll.y + deadzone.y;
- float dzBottom = dzTop + deadzone.height;
-
- if (tx < dzLeft) {
- desiredX = tx - deadzone.x;
- } else if (tx > dzRight) {
- desiredX = tx - deadzone.x - deadzone.width;
- } else {
- desiredX = scroll.x;
- }
-
- if (ty < dzTop) {
- desiredY = ty - deadzone.y;
- } else if (ty > dzBottom) {
- desiredY = ty - deadzone.y - deadzone.height;
- } else {
- desiredY = scroll.y;
- }
- }
-
- float lerpFactor = 1f - (float) Math.pow(1f - followLerp, elapsed * 60f);
- scroll.x = MathUtils.lerp(scroll.x, desiredX, lerpFactor);
- scroll.y = MathUtils.lerp(scroll.y, desiredY, lerpFactor);
- }
-
- private void updateDeadzoneForStyle() {
- if (style == null || style == FollowStyle.NO_DEAD_ZONE) {
- deadzone = null;
- return;
- }
-
- float w, h;
- switch (style) {
- case LOCKON -> {
- w = 1;
- h = 1;
- }
- case PLATFORMER -> {
- w = width / 8f;
- h = height / 3f;
- }
- case TOPDOWN -> {
- w = width / 3f;
- h = height / 3f;
- }
- case TOPDOWN_TIGHT -> {
- w = width / 8f;
- h = height / 8f;
- }
- case SCREEN_BY_SCREEN -> {
- w = width;
- h = height;
- }
- default -> {
- deadzone = null;
- return;
- }
- }
- deadzone = new Rectangle((width - w) / 2f, (height - h) / 2f, w, h);
- }
-
- /**
- * Specifies the bounds of where the camera scroll is allowed. Pass {@code null}
- * for any side
- * to leave it unbounded.
- *
- * @param minX Lower X bound (or {@code null}).
- * @param maxX Upper X bound (or {@code null}).
- * @param minY Lower Y bound (or {@code null}).
- * @param maxY Upper Y bound (or {@code null}).
- */
- public void setScrollBounds(Float minX, Float maxX, Float minY, Float maxY) {
- this.minScrollX = minX;
- this.maxScrollX = maxX;
- this.minScrollY = minY;
- this.maxScrollY = maxY;
- }
-
- /**
- * Specifies scroll bounds as a bounding rectangle (typically the level size).
- *
- * @param x Smallest X value (usually 0).
- * @param y Smallest Y value (usually 0).
- * @param w Largest X extent (usually level width).
- * @param h Largest Y extent (usually level height).
- */
- public void setScrollBoundsRect(float x, float y, float w, float h) {
- setScrollBoundsRect(x, y, w, h, false);
- }
-
- /**
- * Specifies scroll bounds as a bounding rectangle.
- *
- * @param x Smallest X value (usually 0).
- * @param y Smallest Y value (usually 0).
- * @param w Largest X extent (usually level width).
- * @param h Largest Y extent (usually level height).
- * @param updateWorld Reserved for future use (quad-tree bounds).
- */
- public void setScrollBoundsRect(float x, float y, float w, float h, boolean updateWorld) {
- minScrollX = x;
- maxScrollX = x + w;
- minScrollY = y;
- maxScrollY = y + h;
- }
-
- /**
- * Clamps the current {@link #scroll} to the configured scroll bounds.
- * Called automatically each frame by {@link #update(float)}.
- */
- public void updateScroll() {
- float vw = getViewWidth();
- float vh = getViewHeight();
- if (minScrollX != null && scroll.x < minScrollX) {
- scroll.x = minScrollX;
- }
- if (maxScrollX != null && scroll.x + vw > maxScrollX) {
- scroll.x = maxScrollX - vw;
- }
- if (minScrollY != null && scroll.y < minScrollY) {
- scroll.y = minScrollY;
- }
- if (maxScrollY != null && scroll.y + vh > maxScrollY) {
- scroll.y = maxScrollY - vh;
- }
- }
-
- /**
- * Clamps the given scroll position to the camera's min/max bounds, modifying it
- * in-place.
- *
- * @param scrollPos The scroll position to restrict.
- * @return The same vector, clamped within bounds.
- */
- public Vector2 bindScrollPos(Vector2 scrollPos) {
- float vw = getViewWidth();
- float vh = getViewHeight();
- if (minScrollX != null) {
- scrollPos.x = Math.max(scrollPos.x, minScrollX);
- }
- if (maxScrollX != null) {
- scrollPos.x = Math.min(scrollPos.x, maxScrollX - vw);
- }
- if (minScrollY != null) {
- scrollPos.y = Math.max(scrollPos.y, minScrollY);
- }
- if (maxScrollY != null) {
- scrollPos.y = Math.min(scrollPos.y, maxScrollY - vh);
- }
- return scrollPos;
- }
-
- /** Flashes white for 1 second. */
- public void flash() {
- flash(Color.WHITE, 1f, null, false);
- }
-
- /** Flashes the given color for 1 second. */
- public void flash(Color color) {
- flash(color, 1f, null, false);
- }
-
- /** Flashes the given color for the specified duration. */
- public void flash(Color color, float duration) {
- flash(color, duration, null, false);
- }
-
- /**
- * The screen is filled with this color and gradually returns to normal.
- *
- * @param color The color to flash.
- * @param duration How long the flash takes to fade, in seconds.
- * @param onComplete Callback invoked when the flash finishes, or {@code null}.
- * @param force If {@code true}, resets any currently-running flash.
- */
- public void flash(Color color, float duration, Runnable onComplete, boolean force) {
- if (flashActive && !force) {
- return;
- }
- flashActive = true;
- flashColor.set(color);
- flashDuration = Math.max(duration, 0.001f);
- flashElapsed = 0f;
- flashAlpha = 1f;
- flashOnComplete = onComplete;
- }
-
- private void updateFlash(float elapsed) {
- if (!flashActive) {
- return;
- }
- flashElapsed += elapsed;
- flashAlpha = 1f - (flashElapsed / flashDuration);
- if (flashAlpha <= 0f) {
- flashAlpha = 0f;
- flashActive = false;
- if (flashOnComplete != null) {
- flashOnComplete.run();
- }
- }
- }
-
- /** Fades to black over 1 second. */
- public void fade() {
- fade(Color.BLACK, 1f, false, null, false);
- }
-
- /** Fades to the given color over 1 second. */
- public void fade(Color color) {
- fade(color, 1f, false, null, false);
- }
-
- /** Fades to the given color over the specified duration. */
- public void fade(Color color, float duration) {
- fade(color, duration, false, null, false);
- }
-
- /** Fades to/from the given color. */
- public void fade(Color color, float duration, boolean fadeIn) {
- fade(color, duration, fadeIn, null, false);
- }
-
- /**
- * The screen is gradually filled with (or cleared of) this color.
- *
- * @param color The color to fade to/from.
- * @param duration How long the fade takes, in seconds.
- * @param fadeIn {@code true} = fade FROM the color to clear. {@code false}
- * = fade TO the color.
- * @param onComplete Callback invoked when the fade finishes, or {@code null}.
- * @param force If {@code true}, resets any currently-running fade.
- */
- public void fade(Color color, float duration, boolean fadeIn, Runnable onComplete, boolean force) {
- if (fadeActive && !force) {
- return;
- }
- fadeActive = true;
- fadeColor.set(color);
- fadeDuration = Math.max(duration, 0.001f);
- fadeElapsed = 0f;
- this.fadeIn = fadeIn;
- fadeAlpha = fadeIn ? 1f : 0f;
- fadeOnComplete = onComplete;
- }
-
- private void updateFade(float elapsed) {
- if (!fadeActive) {
- return;
- }
- fadeElapsed += elapsed;
- float progress = fadeElapsed / fadeDuration;
- fadeAlpha = fadeIn ? (1f - progress) : progress;
- if (progress >= 1f) {
- fadeAlpha = fadeIn ? 0f : 1f;
- fadeActive = false;
- if (fadeOnComplete != null) {
- fadeOnComplete.run();
- }
- }
- }
-
- /** Shakes with default intensity (0.05) for 0.5 seconds on both axes. */
- public void shake() {
- shake(0.05f, 0.5f, null, true, FlxAxes.XY);
- }
-
- /** Shakes with the given intensity for 0.5 seconds on both axes. */
- public void shake(float intensity) {
- shake(intensity, 0.5f, null, true, FlxAxes.XY);
- }
-
- /** Shakes with the given intensity and duration on both axes. */
- public void shake(float intensity, float duration) {
- shake(intensity, duration, null, true, FlxAxes.XY);
- }
-
- /**
- * A simple screen-shake effect.
- *
- * @param intensity Fraction of camera size representing the max shake
- * distance.
- * @param duration How long the shake lasts, in seconds.
- * @param onComplete Callback invoked when the shake finishes, or {@code null}.
- * @param force If {@code true}, resets any currently-running shake
- * (default unlike flash/fade).
- * @param axes Which axes to shake on.
- */
- public void shake(float intensity, float duration, Runnable onComplete, boolean force, FlxAxes axes) {
- if (shakeActive && !force) {
- return;
- }
- shakeActive = true;
- shakeIntensity = intensity;
- shakeDuration = Math.max(duration, 0.001f);
- shakeElapsed = 0f;
- shakeAxes = (axes != null) ? axes : FlxAxes.XY;
- shakeOnComplete = onComplete;
- shakeOffsetX = 0f;
- shakeOffsetY = 0f;
- }
-
- private void updateShake(float elapsed) {
- if (!shakeActive) {
- return;
- }
- shakeElapsed += elapsed;
- if (shakeElapsed >= shakeDuration) {
- shakeActive = false;
- shakeOffsetX = 0f;
- shakeOffsetY = 0f;
- if (shakeOnComplete != null) {
- shakeOnComplete.run();
- }
- return;
- }
-
- float sx = (shakeAxes == FlxAxes.Y) ? 0 : (MathUtils.random(-1f, 1f) * shakeIntensity * width);
- float sy = (shakeAxes == FlxAxes.X) ? 0 : (MathUtils.random(-1f, 1f) * shakeIntensity * height);
-
- boolean pp = pixelPerfectShake || pixelPerfectRender;
- if (pp) {
- sx = Math.round(sx);
- sy = Math.round(sy);
- }
-
- shakeOffsetX = sx;
- shakeOffsetY = sy;
- }
-
- /** Stops all screen effects (flash, fade, shake) on this camera. */
- public void stopFX() {
- stopFlash();
- stopFade();
- stopShake();
- }
-
- /** Stops the flash effect on this camera. */
- public void stopFlash() {
- flashActive = false;
- flashAlpha = 0f;
- }
-
- /** Stops the fade effect on this camera. */
- public void stopFade() {
- fadeActive = false;
- fadeAlpha = 0f;
- }
-
- /** Stops the shake effect on this camera. */
- public void stopShake() {
- shakeActive = false;
- shakeOffsetX = 0f;
- shakeOffsetY = 0f;
- }
-
- /**
- * Fills the camera display with the specified color using the given batch and a
- * 1x1 white texture.
- *
- * @param fillColor The color to fill with (alpha channel is respected).
- * @param blendAlpha Whether to blend the alpha or overwrite previous contents.
- * @param fxAlpha Additional alpha multiplier (0.0 to 1.0).
- * @param batch An active {@link Batch} to draw with (must be between
- * begin/end).
- * @param whitePixel A 1x1 white {@link Texture} used for color drawing.
- */
- public void fill(Color fillColor, boolean blendAlpha, float fxAlpha, Batch batch, Texture whitePixel) {
- float a = blendAlpha ? fillColor.a * fxAlpha : fxAlpha;
- batch.setColor(fillColor.r, fillColor.g, fillColor.b, a);
- batch.draw(whitePixel, scroll.x, scroll.y, getViewWidth(), getViewHeight());
- batch.setColor(Color.WHITE);
- }
-
- /**
- * Draws active screen effects (flash and fade overlays) using the given batch.
- * Call this after drawing all game objects but before {@code batch.end()}.
- *
- * @param batch An active {@link Batch} (must be between begin/end).
- * @param whitePixel A 1x1 white {@link Texture} used for color drawing.
- */
- public void drawFX(Batch batch, Texture whitePixel) {
- if (flashActive && flashAlpha > 0f) {
- batch.setColor(flashColor.r, flashColor.g, flashColor.b, flashAlpha * alpha);
- batch.draw(whitePixel, scroll.x, scroll.y, getViewWidth(), getViewHeight());
- }
- if (fadeActive || fadeAlpha > 0f) {
- batch.setColor(fadeColor.r, fadeColor.g, fadeColor.b, fadeAlpha * alpha);
- batch.draw(whitePixel, scroll.x, scroll.y, getViewWidth(), getViewHeight());
- }
- batch.setColor(Color.WHITE);
- }
-
- /**
- * Checks whether this camera's display area contains the given point (screen
- * coordinates).
- *
- * @param point The point to test.
- * @return {@code true} if the point is inside the camera display.
- */
- public boolean containsPoint(Vector2 point) {
- return containsPoint(point, 0, 0);
- }
-
- /**
- * Checks whether this camera's display area overlaps a rectangle at the given
- * point.
- *
- * @param point Top-left corner of the rectangle in screen coordinates.
- * @param width Width of the rectangle.
- * @param height Height of the rectangle.
- * @return {@code true} if any part of the rectangle overlaps the camera
- * display.
- */
- public boolean containsPoint(Vector2 point, float width, float height) {
- return point.x + width > x
- && point.x < x + this.width
- && point.y + height > y
- && point.y < y + this.height;
- }
-
- /**
- * Checks whether this camera's display area overlaps the given rectangle
- * (screen coordinates).
- *
- * @param rect The rectangle to test.
- * @return {@code true} if the rectangle overlaps the camera display.
- */
- public boolean containsRect(Rectangle rect) {
- return containsPoint(tmpVec.set(rect.x, rect.y), rect.width, rect.height);
- }
-
- /** The width of the visible area in world-space, accounting for zoom. */
- public float getViewWidth() {
- return width / zoom;
- }
-
- /** The height of the visible area in world-space, accounting for zoom. */
- public float getViewHeight() {
- return height / zoom;
- }
-
- /** The left edge of the visible area in world-space. */
- public float getViewX() {
- return scroll.x + getViewMarginX();
- }
-
- /** The top edge of the visible area in world-space. */
- public float getViewY() {
- return scroll.y + getViewMarginY();
- }
-
- /** Alias for {@link #getViewX()}. */
- public float getViewLeft() {
- return getViewX();
- }
-
- /** Alias for {@link #getViewY()}. */
- public float getViewTop() {
- return getViewY();
- }
-
- /** The right edge of the visible area in world-space. */
- public float getViewRight() {
- return getViewX() + getViewWidth();
- }
-
- /** The bottom edge of the visible area in world-space. */
- public float getViewBottom() {
- return getViewY() + getViewHeight();
- }
-
- /** Margin cut off on each side horizontally by zoom, in world-space. */
- public float getViewMarginX() {
- return (width - getViewWidth()) / 2f;
- }
-
- /** Margin cut off on each side vertically by zoom, in world-space. */
- public float getViewMarginY() {
- return (height - getViewHeight()) / 2f;
- }
-
- /** Margin cut off on the left by zoom. */
- public float getViewMarginLeft() {
- return getViewMarginX();
- }
-
- /** Margin cut off on the right by zoom. */
- public float getViewMarginRight() {
- return getViewMarginX();
- }
-
- /** Margin cut off on the top by zoom. */
- public float getViewMarginTop() {
- return getViewMarginY();
- }
-
- /** Margin cut off on the bottom by zoom. */
- public float getViewMarginBottom() {
- return getViewMarginY();
- }
-
- /**
- * Returns a {@link Rectangle} describing the view margins (position = margin offsets, size = visible area).
- *
- * @return A new rectangle with the margin bounds.
- */
- public Rectangle getViewMarginRect() {
- return tmpRect.set(getViewMarginLeft(), getViewMarginTop(), getViewWidth(), getViewHeight());
- }
-
- /**
- * Returns the current zoom level. {@code 1} = 1:1, {@code 2} = 2x magnification.
- * Changing zoom affects all view properties ({@link #getViewWidth()}, etc.).
- */
- public float getZoom() {
- return zoom;
- }
-
- /**
- * Sets the zoom level. {@code 1} = 1:1, {@code 2} = 2x magnification (world appears larger).
- * Cameras always zoom toward their center.
- *
- * @param zoom The new zoom level.
- */
- public void setZoom(float zoom) {
- float oldZoom = this.zoom;
- this.zoom = zoom;
- // Keep the center of the view fixed in world space so zoom happens from center, not from the left edge.
- float centerX = scroll.x + width / (2f * oldZoom);
- float centerY = scroll.y + height / (2f * oldZoom);
- scroll.x = centerX - width / (2f * this.zoom);
- scroll.y = centerY - height / (2f * this.zoom);
- applyZoom();
- }
-
- /**
- * Changes the zoom level by the given amount.
- *
- * @param zoom The amount to change the zoom level by.
- */
- public void changeZoom(float zoom) {
- setZoom(getZoom() + zoom);
- }
-
- private void applyZoom() {
- if (camera instanceof OrthographicCamera ortho) {
- ortho.zoom = 1f / zoom;
- }
- }
-
- /** The horizontal scale factor derived from zoom. */
- public float getScaleX() {
- return zoom;
- }
-
- /** The vertical scale factor derived from zoom. */
- public float getScaleY() {
- return zoom;
- }
-
- /**
- * Product of the camera's {@link #getScaleX()} and the game's scale mode.
- * For a default setup this equals {@link #getScaleX()}.
- */
- public float getTotalScaleX() {
- return getScaleX();
- }
-
- /**
- * Product of the camera's {@link #getScaleY()} and the game's scale mode.
- * For a default setup this equals {@link #getScaleY()}.
- */
- public float getTotalScaleY() {
- return getScaleY();
- }
-
- /**
- * Sets the display position of this camera.
- *
- * @param x The new X display position.
- * @param y The new Y display position.
- */
- public void setPosition(float x, float y) {
- this.x = x;
- this.y = y;
- }
-
- /**
- * Sets the zoom-based scale of this camera. Because cameras use a single zoom
- * value, this
- * sets zoom to the average of {@code scaleX} and {@code scaleY}.
- *
- * @param scaleX The desired horizontal scale.
- * @param scaleY The desired vertical scale.
- */
- public void setScale(float scaleX, float scaleY) {
- setZoom((scaleX + scaleY) / 2f);
- }
-
- /**
- * Sets both {@link #width} and {@link #height} of the camera display.
- *
- * @param width The new width in game pixels.
- * @param height The new height in game pixels.
- */
- public void setSize(int width, int height) {
- this.width = width;
- this.height = height;
- }
-
- /**
- * Copies the bounds, follow target, deadzone info, and scroll from another
- * camera.
- *
- * @param other The camera to copy from.
- * @return This camera for chaining.
- */
- public FlixelCamera copyFrom(FlixelCamera other) {
- x = other.x;
- y = other.y;
- width = other.width;
- height = other.height;
- scroll.set(other.scroll);
-
- target = other.target;
- targetOffset.set(other.targetOffset);
- followLead.set(other.followLead);
- followLerp = other.followLerp;
- style = other.style;
- deadzone = (other.deadzone != null) ? new Rectangle(other.deadzone) : null;
-
- minScrollX = other.minScrollX;
- maxScrollX = other.maxScrollX;
- minScrollY = other.minScrollY;
- maxScrollY = other.maxScrollY;
-
- setZoom(other.zoom);
- return this;
- }
-
- /**
- * Called by the game front end on window resize. Triggers repositioning of
- * internal display
- * objects.
- */
- public void onResize() {
- viewport.update(
- Flixel.getWindowWidth(),
- Flixel.getWindowHeight(),
- true
- );
- }
-
- /**
- * Cleans up this camera's state, stopping all effects and clearing the follow
- * target.
- */
- @Override
- public void destroy() {
- stopFX();
- target = null;
- deadzone = null;
- flashOnComplete = null;
- fadeOnComplete = null;
- shakeOnComplete = null;
- super.destroy();
- }
-
- public boolean isFlashActive() {
- return flashActive;
- }
-
- public boolean isFadeActive() {
- return fadeActive;
- }
-
- public boolean isShakeActive() {
- return shakeActive;
- }
-
- public Color getFlashColor() {
- return flashColor;
- }
-
- public float getFlashAlpha() {
- return flashAlpha;
- }
-
- public Color getFadeColor() {
- return fadeColor;
- }
-
- public float getFadeAlpha() {
- return fadeAlpha;
- }
-
- /**
- * Preset dead zone styles used with
- * {@link #follow(FlixelObject, FollowStyle, float)}.
- */
- public enum FollowStyle {
-
- /**
- * Camera follows the target and keeps it centered on the screen (with no dead zone).
- * The camera snaps to the target's position each frame.
- */
- LOCKON,
-
- /**
- * A horizontally-biased dead zone placed near the bottom of the camera.
- * Useful for platformers to show more of what is ahead and to prevent
- * the camera from moving up and down too frequently.
- */
- PLATFORMER,
-
- /**
- * The dead zone is centered, allowing free camera movement in all directions,
- * commonly used in top-down games.
- */
- TOPDOWN,
-
- /**
- * Like TOPDOWN but with a tighter (smaller) dead zone, so the camera
- * follows the target more closely.
- */
- TOPDOWN_TIGHT,
-
- /**
- * The camera moves in whole-screen increments, or "pages", jumping
- * once the target leaves the current screen. Good for classic puzzle or
- * arcade games with discrete screen segments.
- */
- SCREEN_BY_SCREEN,
-
- /**
- * No dead zone, the camera only follows the target when explicitly moved;
- * the camera does not track the target automatically.
- */
- NO_DEAD_ZONE
- }
-
- /** Axes on which an effect (e.g. shake) can operate. */
- public enum FlxAxes {
- X, Y, XY
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelState.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelState.java
deleted file mode 100644
index 57229b6..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelState.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package me.stringdotjar.flixelgdx.display;
-
-import com.badlogic.gdx.Screen;
-import com.badlogic.gdx.graphics.Color;
-import com.badlogic.gdx.graphics.g2d.Batch;
-
-import me.stringdotjar.flixelgdx.FlixelBasic;
-import me.stringdotjar.flixelgdx.group.FlixelGroup;
-
-/**
- * Base class for creating a better screen display with more functionality than the default {@link
- * com.badlogic.gdx.Screen} interface.
- *
- * A {@code FlixelState} can open a {@link FlixelSubState} on top of itself.
- * By default, when a substate is active the parent state will continue to be drawn
- * ({@link #persistentDraw} = {@code true}) but will stop updating
- * ({@link #persistentUpdate} = {@code false}).
- *
- * @see FlxState (HaxeFlixel)
- */
-public abstract class FlixelState extends FlixelGroup Make sure to override this, NOT the constructor!
- */
- public void create() {}
-
- /**
- * Updates the logic of {@code this} state.
- *
- * @param delta The amount of time that occurred since the last frame.
- */
- public void update(float delta) {}
-
- /**
- * Draws {@code this} state's members onto the screen.
- *
- * @param batch The batch that's used to draw {@code this} state's members.
- */
- public void draw(Batch batch) {}
-
- /**
- * Opens a {@link FlixelSubState} on top of {@code this} state. If there is already
- * an active substate, it will be closed first.
- *
- * @param subState The substate to open.
- */
- public void openSubState(FlixelSubState subState) {
- if (subState == null) {
- return;
- }
- if (this.subState == subState) {
- return;
- }
- if (this.subState != null) {
- closeSubState();
- }
-
- this.subState = subState;
- subState.parentState = this;
- subState.create();
-
- if (subState.openCallback != null) {
- subState.openCallback.run();
- }
- }
-
- /**
- * Closes the currently active substate, if one exists.
- */
- public void closeSubState() {
- if (subState == null) {
- return;
- }
- FlixelSubState closing = subState;
- subState = null;
- closing.parentState = null;
-
- if (closing.closeCallback != null) {
- closing.closeCallback.run();
- }
- if (destroySubStates) {
- closing.dispose();
- }
- }
-
- /**
- * Reloads the current substate's parent reference. Called internally after state
- * transitions to ensure the parent link is correct.
- */
- public void resetSubState() {
- if (subState != null) {
- subState.parentState = this;
- }
- }
-
- /**
- * Called from {@link me.stringdotjar.flixelgdx.Flixel#switchState(FlixelState)} before
- * the actual state switch happens. Override this to play an exit animation or transition,
- * then call {@code onOutroComplete} when finished.
- *
- * The default implementation calls {@code onOutroComplete} immediately.
- *
- * @param onOutroComplete Callback to invoke when the outro is complete.
- */
- public void startOutro(Runnable onOutroComplete) {
- if (onOutroComplete != null) {
- onOutroComplete.run();
- }
- }
-
- @Override
- public void resize(int width, int height) {}
-
- @Override
- public void pause() {}
-
- @Override
- public void resume() {}
-
- @Override
- public void hide() {}
-
- /**
- * Disposes {@code this} state, any active substate, and all members. Called automatically
- * when {@link me.stringdotjar.flixelgdx.Flixel#switchState(FlixelState)} is used, so that
- * sprites and other objects release their resources.
- */
- @Override
- public void dispose() {
- if (subState != null) {
- closeSubState();
- }
- if (members == null) {
- return;
- }
- Object[] items = members.begin();
- for (int i = 0, n = members.size; i < n; i++) {
- FlixelBasic obj = (FlixelBasic) items[i];
- if (obj != null) {
- obj.destroy();
- }
- }
- members.end();
- members.clear();
- }
-
- /**
- * Adds a new object to {@code this} state. If it is {@code null}, it will not be added and
- * simply ignored.
- *
- * @param object The object to add to the state.
- */
- public void add(FlixelBasic object) {
- if (object != null) {
- members.add(object);
- }
- }
-
- /** Returns the currently active substate, or {@code null} if none is open. */
- public FlixelSubState getSubState() {
- return subState;
- }
-
- public Color getBgColor() {
- return (bgColor != null) ? bgColor : Color.BLACK;
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelSubState.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelSubState.java
deleted file mode 100644
index 7ee8515..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/display/FlixelSubState.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package me.stringdotjar.flixelgdx.display;
-
-import com.badlogic.gdx.graphics.Color;
-
-/**
- * A {@code FlixelSubState} can be opened inside of a {@link FlixelState}. By default, it
- * stops the parent state from updating, making it convenient for pause screens or menus.
- *
- * The parent state's {@link FlixelState#persistentUpdate} and
- * {@link FlixelState#persistentDraw} flags control whether it continues to update and
- * draw while this substate is active.
- *
- * Substates can be nested: a substate can open another substate on top of itself.
- *
- * @see FlxSubState (HaxeFlixel)
- */
-public abstract class FlixelSubState extends FlixelState {
-
- /** Called when this substate is closed. */
- public Runnable closeCallback;
-
- /** Called when this substate is opened or resumed. */
- public Runnable openCallback;
-
- /** The parent state that opened this substate. Set internally by {@link FlixelState#openSubState}. */
- FlixelState parentState;
-
- /**
- * Creates a new substate with a clear background.
- */
- public FlixelSubState() {
- this(Color.CLEAR);
- }
-
- /**
- * Creates a new substate with the given background color.
- *
- * @param bgColor The background color for this substate.
- */
- public FlixelSubState(Color bgColor) {
- super();
- this.bgColor = bgColor;
- }
-
- /**
- * Closes this substate by telling the parent state to remove it.
- */
- public void close() {
- if (parentState != null) {
- parentState.closeSubState();
- }
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/group/FlixelGroup.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/group/FlixelGroup.java
deleted file mode 100644
index da62146..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/group/FlixelGroup.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package me.stringdotjar.flixelgdx.group;
-
-import com.badlogic.gdx.graphics.g2d.Batch;
-import com.badlogic.gdx.utils.SnapshotArray;
-
-import me.stringdotjar.flixelgdx.FlixelBasic;
-
-import java.util.function.Consumer;
-
-/**
- * Base class for creating groups with a list of members inside of it.
- */
-public abstract class FlixelGroup
- * Because {@code FlixelSpriteGroup} extends {@code FlixelSprite}, groups can be nested
- * inside other groups, enabling complex hierarchical sprite compositions. Any property
- * change on the group (position, alpha, color, scale, rotation, flip) automatically
- * propagates to all members.
- *
- * Sprites added to the group are automatically offset by the group's current position
- * and have their alpha multiplied by the group's alpha. When a sprite is removed, its
- * position offset is subtracted to restore local coordinates.
- *
- * Rotation behavior is controlled by {@link RotationMode}:
- *
- * Individual sprite rotations cannot be changed independently in this mode.
- */
- WHEEL,
-
- /**
- * All sprites orbit around the group origin as a rigid body. When the rotation
- * changes, each sprite's position is rotated around the center by the delta, and
- * its individual rotation is adjusted by the same amount.
- */
- ORBIT
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/input/FlixelKey.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/input/FlixelKey.java
deleted file mode 100644
index 3b522fc..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/input/FlixelKey.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package me.stringdotjar.flixelgdx.input;
-
-import com.badlogic.gdx.Input;
-
-/**
- * A simple extension of {@link Input.Keys} to simplify accessing key constants.
- */
-public class FlixelKey extends Input.Keys {
-
- private FlixelKey() {}
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogLevel.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogLevel.java
deleted file mode 100644
index f5d12b9..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogLevel.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package me.stringdotjar.flixelgdx.logging;
-
-/**
- * An enum that defines the log levels for FlixelGDX's logging system. This is used to determine the
- * severity of a log message and how it should be displayed in the console.
- */
-public enum FlixelLogLevel {
-
- /**
- * Simple white/gray text and simple informational log level that is used for general information about the game.
- */
- INFO,
-
- /**
- * Highlighted yellow in the console and, although not critical, indicates that something may be
- * wrong and should be looked into.
- */
- WARN,
-
- /**
- * Highlighted red in the console and indicates an error. Shows something is wrong and
- * should be looked into immediately.
- */
- ERROR
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogMode.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogMode.java
deleted file mode 100644
index e01ba04..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogMode.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package me.stringdotjar.flixelgdx.logging;
-
-/**
- * An enum that defines the log modes for FlixelGDX's logging system. This is used to determine how the
- * log messages should be displayed in the console.
- */
-public enum FlixelLogMode {
-
- /**
- * Provides a simple log output that only includes the location of the log call and the message.
- * Great for people who are familiar with Haxe and its {@code trace()} function!
- */
- SIMPLE,
-
- /**
- * Provides a more detailed log output that includes the time of the log call, class, line number, and
- * method of the call. Great for debugging purposes and people who like a more professional feel for their game!
- */
- DETAILED
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogger.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogger.java
deleted file mode 100644
index 985ef80..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/logging/FlixelLogger.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package me.stringdotjar.flixelgdx.logging;
-
-import com.badlogic.gdx.files.FileHandle;
-
-import me.stringdotjar.flixelgdx.util.FlixelConstants;
-import me.stringdotjar.flixelgdx.util.FlixelRuntimeUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.function.Consumer;
-
-/**
- * Logger instance for Flixel that formats and outputs log messages to the console and optionally
- * to a file. Console output respects the current {@link FlixelLogMode}; file output always uses
- * detailed format.
- */
-public class FlixelLogger {
-
- /** Default tag to use when logging without a specific tag. */
- private String defaultTag = "";
-
- /** Where the log file is written (for reference); actual writes go through the file line consumer. */
- private FileHandle logFileLocation;
-
- /** Log mode for console output. File output always uses {@link FlixelLogMode#DETAILED}. */
- private FlixelLogMode logMode;
-
- /** Callback for when a log message is written to the file. */
- private Consumer This is used to get the file and method name of where the log was called from.
- *
- * @return The location of where the log was called from.
- */
- protected StackWalker.StackFrame getCaller() {
- // TODO: Make this work for TeaVM, as call stacks aren't supported for web builds/TeaVM!
- return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
- .walk(frames -> frames.filter(f -> {
- // Filter packages to not log.
- String pkg = f.getDeclaringClass().getPackageName();
- if (pkg.startsWith(FlixelRuntimeUtil.getLibraryRoot())) return false; // Do not include FlixelGDX logs.
- if (pkg.startsWith("org.codehaus.groovy.")) return false;
- if (pkg.startsWith("groovy.lang.")) return false;
- if (pkg.contains("$_run_closure")) return false;
- if (pkg.contains("$$Lambda$")) return false;
- if (pkg.startsWith("sun.reflect.") || pkg.startsWith("java.lang.reflect.")) return false;
- return true;
- })
- .findFirst()
- )
- .orElse(null);
- }
-
- /**
- * Wraps text with ANSI color/format codes for console output.
- */
- protected String colorText(String text, String color, boolean bold, boolean italic, boolean underline) {
- StringBuilder sb = new StringBuilder();
- if (bold) {
- sb.append(FlixelConstants.AsciiCodes.BOLD);
- }
- if (italic) {
- sb.append(FlixelConstants.AsciiCodes.ITALIC);
- }
- if (underline) {
- sb.append(FlixelConstants.AsciiCodes.UNDERLINE);
- }
- sb.append(color);
- sb.append(text);
- sb.append(FlixelConstants.AsciiCodes.RESET);
- return sb.toString();
- }
-
- public String getDefaultTag() {
- return defaultTag;
- }
-
- public void setDefaultTag(@NotNull String defaultTag) {
- this.defaultTag = defaultTag;
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/signal/FlixelSignal.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/signal/FlixelSignal.java
deleted file mode 100644
index 5fecf97..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/signal/FlixelSignal.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package me.stringdotjar.flixelgdx.signal;
-
-import com.badlogic.gdx.utils.SnapshotArray;
-
-/**
- * Utility class for creating objects that can execute multiple callbacks when it is dispatched (or triggered).
- */
-public class FlixelSignal {@link UpdateSignalData} is a mutable, reusable class rather than a record because it is
- * dispatched every frame. Allocating a new object 120 times per second (pre+post) adds GC
- * pressure that causes frame stutters. Signal handlers must not hold a reference to the data
- * object past the callback return.
- */
-public final class FlixelSignalData {
-
- /**
- * Mutable carrier for per-frame update data. Reuse the same instance across frames to
- * avoid GC pressure. Do NOT store a reference to this object; read values during the
- * callback only.
- */
- public static final class UpdateSignalData {
- private float delta;
-
- public UpdateSignalData() {}
-
- public UpdateSignalData(float delta) {
- this.delta = delta;
- }
-
- public float delta() {
- return delta;
- }
-
- public void set(float delta) {
- this.delta = delta;
- }
- }
-
- public record StateSwitchSignalData(FlixelState screen) {}
-
- public record SoundPlayedSignalData(MASound sound) {}
-
- public record MusicPlayedSignalData(MASound music) {}
-
- private FlixelSignalData() {}
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/text/FlixelFontRegistry.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/text/FlixelFontRegistry.java
deleted file mode 100644
index cc0dceb..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/text/FlixelFontRegistry.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package me.stringdotjar.flixelgdx.text;
-
-import com.badlogic.gdx.files.FileHandle;
-import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A global registry for TrueType ({@code .ttf}/{@code .otf}) fonts that can be used
- * with {@link FlixelText}.
- *
- * Fonts are registered once with a unique string identifier and an asset path, then
- * referenced by that identifier throughout the game. The registry caches
- * {@link FreeTypeFontGenerator} instances internally so that multiple {@link FlixelText}
- * objects sharing the same font ID reuse the same generator, avoiding redundant file parsing.
- *
- * {@link #dispose()} is called when the game shuts down (in
- * {@code FlixelGame.dispose()}) to release all cached generators. Individual entries
- * can be removed earlier with {@link #unregister(String)}.
- */
-public final class FlixelFontRegistry {
-
- private static final Map Extends {@link FlixelSprite} so that text objects can be added to sprite groups and
- * states, with full support for tinting, fading, rotation, and scaling. Uses libGDX's
- * {@link BitmapFont} for rendering and optionally {@link FreeTypeFontGenerator} for
- * dynamic font generation from {@code .ttf}/{@code .otf} files.
- *
- * By default, {@code FlixelText} auto-sizes to fit its text content. To use a fixed
- * width, pass a positive {@code fieldWidth} to the constructor or call
- * {@link #setFieldWidth(float)}. A fixed height can be set via {@link #setFieldHeight(float)}.
- *
- * The default font is libGDX's built-in bitmap font (Arial 15px), scaled to the
- * requested size. For best quality at any size, supply a {@code .ttf} or {@code .otf}
- * file via {@link #setFont(FileHandle)}, which uses FreeType to generate a crisp
- * bitmap font at the exact pixel size requested.
- *
- * Text can be rendered with borders via {@link #setBorderStyle(BorderStyle, Color, float, float)}.
- * Supported styles are {@link BorderStyle#SHADOW}, {@link BorderStyle#OUTLINE}, and
- * {@link BorderStyle#OUTLINE_FAST}.
- *
- * Graphic-loading and animation methods inherited from {@link FlixelSprite} are not
- * applicable to text and will throw {@link UnsupportedOperationException} if called.
- */
-public class FlixelText extends FlixelSprite {
-
- /** The text being displayed. */
- private String text = "";
-
- /** Font size in pixels. */
- private int size;
-
- /** Horizontal alignment within the field. */
- private Alignment alignment = Alignment.LEFT;
-
- /** Whether text wraps at {@link #fieldWidth}. Defaults to {@code true}. */
- private boolean wordWrap = true;
-
- /**
- * Whether the field dimensions are determined automatically from the text
- * content. Requires {@link #wordWrap} to be {@code false} to take full effect.
- */
- private boolean autoSize = true;
-
- /** The width of the text field. {@code 0} means auto-width. */
- private float fieldWidth;
-
- /** The height of the text field. {@code 0} means auto-height. */
- private float fieldHeight;
-
- /** Whether to render bold text. Only effective with FreeType fonts. */
- private boolean bold = false;
-
- /** Whether to render italic text. Only effective with FreeType fonts. */
- private boolean italic = false;
-
- /** Whether the text is underlined. Stored for API compatibility. */
- private boolean underline = false;
-
- /** Extra horizontal spacing between characters, in pixels. */
- private float letterSpacing = 0;
-
- /** The current border style. */
- private BorderStyle borderStyle = BorderStyle.NONE;
-
- /** The color of the border in RGBA. */
- private final Color borderColor = new Color(Color.CLEAR);
-
- /** The size of the border in pixels. */
- private float borderSize = 1;
-
- /**
- * Quality of the border rendering. {@code 0}: single iteration,
- * {@code 1}: one iteration for every pixel in {@link #borderSize}.
- */
- private float borderQuality = 1;
-
- /** The font used for text rendering. */
- private BitmapFont bitmapFont;
-
- /** Cached text layout used for measurement and drawing. */
- private final GlyphLayout glyphLayout = new GlyphLayout();
-
- /** The TrueType font file used for FreeType generation, or {@code null} for the default font. */
- private FileHandle fontFile;
-
- /**
- * The {@link FlixelFontRegistry} ID for the font, or {@code null} if a direct
- * {@link FileHandle} or the default font is used instead.
- */
- private String fontRegistryId;
-
- /**
- * The FreeType generator used by this instance. May be owned by
- * {@link FlixelFontRegistry} (shared) or by this instance (private).
- */
- private FreeTypeFontGenerator generator;
-
- /** The path used to create a privately-owned {@link #generator}, for change detection. */
- private String currentGeneratorPath;
-
- /** Whether this instance created (and therefore owns) the current {@link #generator}. */
- private boolean ownsGenerator;
-
- /** Whether the font needs to be regenerated (size, bold, italic, or font file changed). */
- private boolean fontDirty = true;
-
- /** Whether the text layout needs to be recalculated. */
- private boolean layoutDirty = true;
-
- /** Reusable matrix to save the batch's transform before applying text transforms. */
- private final Matrix4 savedTransform = new Matrix4();
-
- /** Reusable matrix for applying rotation/scale transforms during drawing. */
- private final Matrix4 textTransform = new Matrix4();
-
- /** Creates a new text object at (0, 0) with default settings. */
- public FlixelText() {
- this(0, 0, 0, null, 8);
- }
-
- /**
- * Creates a new text object at the specified position.
- *
- * @param x The x position of the text.
- * @param y The y position of the text.
- */
- public FlixelText(float x, float y) {
- this(x, y, 0, null, 8);
- }
-
- /**
- * Creates a new text object at the specified position with a field width.
- *
- * @param x The x position of the text.
- * @param y The y position of the text.
- * @param fieldWidth The width of the text field. Auto-sizes if {@code <= 0}.
- */
- public FlixelText(float x, float y, float fieldWidth) {
- this(x, y, fieldWidth, null, 8);
- }
-
- /**
- * Creates a new text object with position, field width, and initial text.
- *
- * @param x The x position of the text.
- * @param y The y position of the text.
- * @param fieldWidth The width of the text field. Auto-sizes if {@code <= 0}.
- * @param text The text to display initially.
- */
- public FlixelText(float x, float y, float fieldWidth, String text) {
- this(x, y, fieldWidth, text, 8);
- }
-
- /**
- * Creates a new text object with all primary parameters.
- *
- * @param x The x position of the text.
- * @param y The y position of the text.
- * @param fieldWidth The width of the text field. Auto-sizes if {@code <= 0}.
- * @param text The text to display initially.
- * @param size The font size in pixels.
- */
- public FlixelText(float x, float y, float fieldWidth, String text, int size) {
- super();
- setPosition(x, y);
- setFieldWidth(fieldWidth);
- setAutoSize(fieldWidth <= 0);
- setText(text);
- setTextSize(size);
- }
-
- /** Returns the text currently being displayed. */
- public String getText() {
- return text;
- }
-
- /**
- * Sets the text to display.
- *
- * @param text The new text string.
- * @return This instance for chaining.
- */
- public FlixelText setText(String text) {
- String newText = (text != null) ? text : "null";
- if (!this.text.equals(newText)) {
- this.text = newText;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns the font size in pixels. */
- public int getTextSize() {
- return size;
- }
-
- /**
- * Sets the font size in pixels. When using a FreeType font, this triggers font
- * regeneration. When using the default font, the built-in bitmap font is scaled.
- *
- * @param size The new font size (minimum 1).
- * @return This instance for chaining.
- */
- public FlixelText setTextSize(int size) {
- int newSize = Math.max(1, size);
- if (this.size != newSize) {
- this.size = newSize;
- fontDirty = true;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns the current text alignment. */
- public Alignment getAlignment() {
- return alignment;
- }
-
- /**
- * Sets the horizontal alignment of the text within the field. Only has a visible
- * effect when {@link #isAutoSize()} is {@code false} (i.e. the field has a fixed width).
- *
- * @param alignment The alignment to use.
- * @return This instance for chaining.
- */
- public FlixelText setAlignment(@NotNull Alignment alignment) {
- if (this.alignment != alignment) {
- this.alignment = alignment;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns whether word wrapping is enabled. */
- public boolean isWordWrap() {
- return wordWrap;
- }
-
- /**
- * Enables or disables word wrapping. Defaults to {@code true}.
- *
- * @param wordWrap Whether to wrap text at the field width.
- * @return This instance for chaining.
- */
- public FlixelText setWordWrap(boolean wordWrap) {
- if (this.wordWrap != wordWrap) {
- this.wordWrap = wordWrap;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns whether the text field auto-sizes to fit its content. */
- public boolean isAutoSize() {
- return autoSize;
- }
-
- /**
- * Sets whether the text field auto-sizes to fit content. When {@code true},
- * {@link #getFieldWidth()} and {@link #getFieldHeight()} are determined
- * automatically. Requires {@link #isWordWrap()} to be {@code false} to
- * take full effect.
- *
- * @param autoSize Whether to auto-size.
- * @return This instance for chaining.
- */
- public FlixelText setAutoSize(boolean autoSize) {
- if (this.autoSize != autoSize) {
- this.autoSize = autoSize;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns the width of the text field, or {@code 0} if auto-sizing. */
- public float getFieldWidth() {
- return fieldWidth;
- }
-
- /**
- * Sets the width of the text field. Enables auto-sizing if {@code <= 0}.
- *
- * @param fieldWidth The field width in pixels.
- * @return This instance for chaining.
- */
- public FlixelText setFieldWidth(float fieldWidth) {
- float newWidth = Math.max(0, fieldWidth);
- if (this.fieldWidth != newWidth) {
- this.fieldWidth = newWidth;
- if (newWidth <= 0) {
- autoSize = true;
- }
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns the height of the text field, or {@code 0} if auto-height. */
- public float getFieldHeight() {
- return fieldHeight;
- }
-
- /**
- * Sets the height of the text field. When {@code <= 0}, height is determined
- * automatically from the text content. Has no effect when {@link #isAutoSize()}
- * is {@code true}.
- *
- * @param fieldHeight The field height in pixels.
- * @return This instance for chaining.
- */
- public FlixelText setFieldHeight(float fieldHeight) {
- float newHeight = Math.max(0, fieldHeight);
- if (this.fieldHeight != newHeight) {
- this.fieldHeight = newHeight;
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns whether bold text is enabled. */
- public boolean isBold() {
- return bold;
- }
-
- /**
- * Sets whether to use bold text. Only takes visual effect when a {@code .ttf}
- * font has been set via {@link #setFont(FileHandle)}, since the default bitmap
- * font does not support runtime weight changes.
- *
- * @param bold Whether to use bold.
- * @return This instance for chaining.
- */
- public FlixelText setBold(boolean bold) {
- if (this.bold != bold) {
- this.bold = bold;
- if (fontFile != null || fontRegistryId != null) {
- fontDirty = true;
- }
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns whether italic text is enabled. */
- public boolean isItalic() {
- return italic;
- }
-
- /**
- * Sets whether to use italic text. Only takes visual effect when a {@code .ttf}
- * font has been set via {@link #setFont(FileHandle)}, since the default bitmap
- * font does not support runtime style changes.
- *
- * @param italic Whether to use italic.
- * @return This instance for chaining.
- */
- public FlixelText setItalic(boolean italic) {
- if (this.italic != italic) {
- this.italic = italic;
- if (fontFile != null || fontRegistryId != null) {
- fontDirty = true;
- }
- layoutDirty = true;
- }
- return this;
- }
-
- /** Returns whether underline is enabled. */
- public boolean isUnderline() {
- return underline;
- }
-
- /**
- * Sets whether to underline the text. This property is stored for API
- * compatibility but visual rendering of underlines is limited.
- *
- * @param underline Whether to underline.
- * @return This instance for chaining.
- */
- public FlixelText setUnderline(boolean underline) {
- this.underline = underline;
- return this;
- }
-
- /** Returns the letter spacing in pixels. */
- public float getLetterSpacing() {
- return letterSpacing;
- }
-
- /**
- * Sets the spacing between characters in pixels. Only takes visual effect
- * when a {@code .ttf} font has been set via {@link #setFont(FileHandle)},
- * as FreeType uses this value during glyph generation.
- *
- * @param letterSpacing The spacing in pixels.
- * @return This instance for chaining.
- */
- public FlixelText setLetterSpacing(float letterSpacing) {
- if (this.letterSpacing != letterSpacing) {
- this.letterSpacing = letterSpacing;
- if (fontFile != null || fontRegistryId != null) {
- fontDirty = true;
- }
- layoutDirty = true;
- }
- return this;
- }
-
- /**
- * Returns whether this text uses a custom embedded font ({@code true}) or the
- * default libGDX bitmap font ({@code false}). A font is considered embedded when
- * set via {@link #setFont(FileHandle)}, {@link #setFont(String)}, or when a
- * {@linkplain FlixelFontRegistry#setDefault(String) registry default} is active.
- */
- public boolean isEmbedded() {
- return fontFile != null || fontRegistryId != null
- || FlixelFontRegistry.getDefault() != null;
- }
-
- /**
- * Returns the {@link FlixelFontRegistry} ID currently set on this text, or
- * {@code null} if a direct {@link FileHandle} or the default font is used.
- */
- public String getFontRegistryId() {
- return fontRegistryId;
- }
-
- /**
- * Sets the font by its {@link FlixelFontRegistry} identifier. The font must
- * have been previously registered via
- * {@link FlixelFontRegistry#register(String, FileHandle)}. Pass {@code null}
- * to clear the registry reference and fall back to the default resolution order
- * (direct file → registry default → built-in font).
- *
- * @param id The registered font ID, or {@code null} to clear.
- * @return This instance for chaining.
- * @throws IllegalArgumentException if {@code id} is non-null but not registered.
- */
- public FlixelText setFont(String id) {
- if (id != null && !FlixelFontRegistry.has(id)) {
- throw new IllegalArgumentException("No font registered with id \"" + id + "\".");
- }
- disposeOwnedGenerator();
- this.fontRegistryId = id;
- this.fontFile = null;
- fontDirty = true;
- layoutDirty = true;
- return this;
- }
-
- /**
- * Sets a custom TrueType font file for this text. Uses FreeType to generate a
- * bitmap font at the current size. Pass {@code null} to revert to the default
- * font. This clears any previously set {@linkplain #setFont(String) registry ID}.
- *
- * @param fontFile The {@code .ttf} or {@code .otf} file handle, or {@code null}.
- * @return This instance for chaining.
- */
- public FlixelText setFont(FileHandle fontFile) {
- disposeOwnedGenerator();
- this.fontFile = fontFile;
- this.fontRegistryId = null;
- fontDirty = true;
- layoutDirty = true;
- return this;
- }
-
- /**
- * Sets a pre-built {@link BitmapFont} directly, bypassing FreeType generation.
- * This gives full control over font settings. The caller is responsible for the
- * font's lifecycle if this text is destroyed or the font is replaced.
- * Clears any previously set font file or registry ID.
- *
- * @param font The bitmap font to use. Must not be {@code null}.
- * @return This instance for chaining.
- * @throws IllegalArgumentException if {@code font} is {@code null}.
- */
- public FlixelText setBitmapFont(BitmapFont font) {
- if (font == null) {
- throw new IllegalArgumentException("BitmapFont cannot be null.");
- }
- disposeFont();
- this.bitmapFont = font;
- this.fontFile = null;
- this.fontRegistryId = null;
- fontDirty = false;
- layoutDirty = true;
- return this;
- }
-
- /** Returns the current border style. */
- public BorderStyle getBorderStyle() {
- return borderStyle;
- }
-
- /** Returns the border color. */
- public Color getBorderColor() {
- return borderColor;
- }
-
- /** Returns the border size in pixels. */
- public float getBorderSize() {
- return borderSize;
- }
-
- /** Returns the border rendering quality. */
- public float getBorderQuality() {
- return borderQuality;
- }
-
- /**
- * Sets the border style, color, size, and quality in one call.
- *
- * @param style The border style.
- * @param color The border color in RGBA. Pass {@code null} for transparent.
- * @param size The border size in pixels.
- * @param quality Rendering quality. {@code 0}: single iteration, {@code 1}: one
- * iteration per pixel in {@code size}.
- * @return This instance for chaining.
- */
- public FlixelText setBorderStyle(BorderStyle style, Color color, float size, float quality) {
- this.borderStyle = (style != null) ? style : BorderStyle.NONE;
- this.borderColor.set((color != null) ? color : Color.CLEAR);
- this.borderSize = Math.max(0, size);
- this.borderQuality = Math.max(0, quality);
- return this;
- }
-
- /**
- * Sets the border style and color with default size (1) and quality (1).
- *
- * @param style The border style.
- * @param color The border color.
- * @return This instance for chaining.
- */
- public FlixelText setBorderStyle(BorderStyle style, Color color) {
- return setBorderStyle(style, color, 1, 1);
- }
-
- /**
- * Sets the border style with a default black color, size of 1, and quality of 1.
- *
- * @param style The border style.
- * @return This instance for chaining.
- */
- public FlixelText setBorderStyle(BorderStyle style) {
- return setBorderStyle(style, Color.BLACK, 1, 1);
- }
-
- /**
- * Convenience method to set many text properties at once. Pass {@code null} or
- * {@code 0} for any parameter to keep its current value.
- *
- * @param fontFile The {@code .ttf}/{@code .otf} font file, or {@code null} to keep current.
- * @param size The font size, or {@code 0} to keep current.
- * @param color The text color, or {@code null} to keep current.
- * @param alignment The text alignment, or {@code null} to keep current.
- * @param borderStyle The border style, or {@code null} to keep current.
- * @param borderColor The border color, or {@code null} to keep current.
- * @return This instance for chaining.
- */
- public FlixelText setFormat(FileHandle fontFile, int size, Color color,
- Alignment alignment, BorderStyle borderStyle,
- Color borderColor) {
- if (fontFile != null) {
- setFont(fontFile);
- }
- if (size > 0) {
- setTextSize(size);
- }
- if (color != null) {
- setColor(color);
- }
- if (alignment != null) {
- setAlignment(alignment);
- }
- if (borderStyle != null) {
- setBorderStyle(borderStyle, (borderColor != null) ? borderColor : this.borderColor);
- } else if (borderColor != null) {
- this.borderColor.set(borderColor);
- }
- return this;
- }
-
- /**
- * Simplified format setter with font file, size, and color.
- *
- * @param fontFile The font file, or {@code null} to keep current.
- * @param size The font size, or {@code 0} to keep current.
- * @param color The text color, or {@code null} to keep current.
- * @return This instance for chaining.
- */
- public FlixelText setFormat(FileHandle fontFile, int size, Color color) {
- return setFormat(fontFile, size, color, null, null, null);
- }
-
- /**
- * Convenience format setter using a {@link FlixelFontRegistry} font ID.
- * Pass {@code null} for any parameter to keep its current value.
- *
- * @param fontId The registered font ID, or {@code null} to keep current.
- * @param size The font size, or {@code 0} to keep current.
- * @param color The text color, or {@code null} to keep current.
- * @param alignment The text alignment, or {@code null} to keep current.
- * @param borderStyle The border style, or {@code null} to keep current.
- * @param borderColor The border color, or {@code null} to keep current.
- * @return This instance for chaining.
- */
- public FlixelText setFormat(String fontId, int size, Color color,
- Alignment alignment, BorderStyle borderStyle,
- Color borderColor) {
- if (fontId != null) {
- setFont(fontId);
- }
- if (size > 0) {
- setTextSize(size);
- }
- if (color != null) {
- setColor(color);
- }
- if (alignment != null) {
- setAlignment(alignment);
- }
- if (borderStyle != null) {
- setBorderStyle(borderStyle, (borderColor != null) ? borderColor : this.borderColor);
- } else if (borderColor != null) {
- this.borderColor.set(borderColor);
- }
- return this;
- }
-
- /**
- * Simplified format setter with a registry font ID, size, and color.
- *
- * @param fontId The registered font ID, or {@code null} to keep current.
- * @param size The font size, or {@code 0} to keep current.
- * @param color The text color, or {@code null} to keep current.
- * @return This instance for chaining.
- */
- public FlixelText setFormat(String fontId, int size, Color color) {
- return setFormat(fontId, size, color, null, null, null);
- }
-
- /**
- * Simplified format setter with size and color only.
- *
- * @param size The font size, or {@code 0} to keep current.
- * @param color The text color, or {@code null} to keep current.
- * @return This instance for chaining.
- */
- public FlixelText setFormat(int size, Color color) {
- return setFormat((FileHandle) null, size, color, null, null, null);
- }
-
- /**
- * Returns the actual rendered width of the text content (which may differ from
- * {@link #getFieldWidth()} when a fixed field width is set). Triggers a layout
- * rebuild if necessary.
- */
- public float getTextWidth() {
- rebuildIfDirty();
- return glyphLayout.width;
- }
-
- /**
- * Returns the actual rendered height of the text content (which may differ from
- * {@link #getFieldHeight()} when a fixed field height is set). Triggers a layout
- * rebuild if necessary.
- */
- public float getTextHeight() {
- rebuildIfDirty();
- return glyphLayout.height;
- }
-
- /**
- * Text objects do not use frame-based animation. This override prevents the
- * animation state machine in {@link FlixelSprite} from running.
- */
- @Override
- public void update(float delta) {
- // No-op: text does not animate.
- }
-
- @Override
- public void draw(Batch batch) {
- if (text.isEmpty()) {
- return;
- }
- rebuildIfDirty();
-
- float scaleX = getScaleX();
- float scaleY = getScaleY();
- float rotation = getAngle();
- boolean needsTransform = rotation != 0 || scaleX != 1 || scaleY != 1;
-
- float textTop = getHeight();
-
- if (needsTransform) {
- savedTransform.set(batch.getTransformMatrix());
-
- float ox = getOriginX();
- float oy = getOriginY();
- textTransform.set(savedTransform);
- textTransform.translate(getX() + ox, getY() + oy, 0);
- textTransform.rotate(0, 0, 1, rotation);
- textTransform.scale(scaleX, scaleY, 1);
- textTransform.translate(-ox, -oy, 0);
- batch.setTransformMatrix(textTransform);
-
- drawTextContent(batch, 0, textTop);
-
- batch.setTransformMatrix(savedTransform);
- } else {
- drawTextContent(batch, getX(), getY() + textTop);
- }
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load graphics. */
- @Override
- public final FlixelSprite loadGraphic(FileHandle path) {
- throw new UnsupportedOperationException("FlixelText does not support loadGraphic(). Use setText() instead.");
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load graphics. */
- @Override
- public final FlixelSprite loadGraphic(FileHandle path, int frameWidth) {
- throw new UnsupportedOperationException("FlixelText does not support loadGraphic(). Use setText() instead.");
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load graphics. */
- @Override
- public final FlixelSprite loadGraphic(FileHandle path, int frameWidth, int frameHeight) {
- throw new UnsupportedOperationException("FlixelText does not support loadGraphic(). Use setText() instead.");
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load graphics. */
- @Override
- public final FlixelSprite loadGraphic(Texture texture, int frameWidth, int frameHeight) {
- throw new UnsupportedOperationException("FlixelText does not support loadGraphic(). Use setText() instead.");
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load sparrow frames. */
- @Override
- public final FlixelSprite loadSparrowFrames(FileHandle texture, FileHandle xmlFile) {
- throw new UnsupportedOperationException("FlixelText does not support loadSparrowFrames().");
- }
-
- /** @throws UnsupportedOperationException always; text objects cannot load sparrow frames. */
- @Override
- public final FlixelSprite loadSparrowFrames(Texture texture, XmlReader.Element xmlFile) {
- throw new UnsupportedOperationException("FlixelText does not support loadSparrowFrames().");
- }
-
- /** @throws UnsupportedOperationException always; text objects do not have frame animations. */
- @Override
- public final void addAnimationByPrefix(String name, String prefix, int frameRate, boolean loop) {
- throw new UnsupportedOperationException("FlixelText does not support animations.");
- }
-
- /** @throws UnsupportedOperationException always; text objects do not have frame animations. */
- @Override
- public final void addAnimation(String name, int[] frameIndices, float frameDuration) {
- throw new UnsupportedOperationException("FlixelText does not support animations.");
- }
-
- /** @throws UnsupportedOperationException always; text objects do not have frame animations. */
- @Override
- public final void playAnimation(String name) {
- throw new UnsupportedOperationException("FlixelText does not support animations.");
- }
-
- /** @throws UnsupportedOperationException always; text objects do not have frame animations. */
- @Override
- public final void playAnimation(String name, boolean loop) {
- throw new UnsupportedOperationException("FlixelText does not support animations.");
- }
-
- /** @throws UnsupportedOperationException always; text objects do not have frame animations. */
- @Override
- public final void playAnimation(String name, boolean loop, boolean forceRestart) {
- throw new UnsupportedOperationException("FlixelText does not support animations.");
- }
-
- /** @return {@code true} always, since text has no animations to finish. */
- @Override
- public final boolean isAnimationFinished() {
- return true;
- }
-
- private static final ObjectMap Please note that while this isn't an abstract class, it is advised to NOT create instances
- * of this class, since it does not implement the actual tweening logic. Instead, you should use one of
- * its subclasses, such as {@link FlixelVarTween}, or create your own subclass and add your own functionality.
- *
- * The only reason this class is not abstract is to allow pooling of generic tweens when needed to save memory.
- */
-public class FlixelTween implements Pool.Poolable {
-
- /** The global tween manager for the entire game. */
- private static final FlixelTweenManager globalManager = new FlixelTweenManager();
-
- /** The settings used for how the tween is handled and calculated (aka how it looks and animates). */
- protected FlixelTweenSettings tweenSettings;
-
- /** The parent manager that {@code this} tween gets updated in. */
- protected FlixelTweenManager manager;
-
- /** How far the tween is tweening itself. This is what's used to actually tween the object! */
- protected float scale = 0.0f;
-
- /** How many seconds has elapsed since {@code this} tween started. */
- protected float secondsSinceStart = 0.0f;
-
- /** How many times {@code this} tween has updated. */
- protected int executions = 0;
-
- /** Is {@code this} tween currently paused? */
- public boolean paused = false;
-
- /** Is {@code this} tween currently active? */
- public boolean running = false;
-
- /** Is {@code this} tween finished tweening? */
- public boolean finished = false;
-
- /** Is {@code this} tween tweening backwards? */
- protected boolean backward = false;
-
- /** Default constructor for pooling purposes. */
- protected FlixelTween() {}
-
- /**
- * Constructs a new tween with the provided settings.
- *
- * @param tweenSettings The settings that configure and determine how the tween should animate.
- */
- protected FlixelTween(FlixelTweenSettings tweenSettings) {
- this.tweenSettings = tweenSettings;
- }
-
- /**
- * Creates a new reflection-based tween with the provided settings and starts it in the global tween manager.
- *
- * @param object The object to tween its values.
- * @param tweenSettings The settings that configure and determine how the tween should animate.
- * @param updateCallback Callback function for updating the objects values when the tween updates.
- * @return The newly created and started tween.
- */
- public static FlixelTween tween(Object object, FlixelTweenSettings tweenSettings, FlixelVarTween.FunkinVarTweenUpdateCallback updateCallback) {
- return new FlixelVarTween(object, tweenSettings, updateCallback)
- .setManager(globalManager)
- .start();
- }
-
- /**
- * Creates a new property-based tween with the provided settings and starts it in the global tween manager.
- *
- * @param tweenSettings The settings that configure and determine how the tween should animate.
- * @return The newly created and started tween.
- */
- public static FlixelTween tween(FlixelTweenSettings tweenSettings) {
- return new FlixelPropertyTween(tweenSettings)
- .setManager(globalManager)
- .start();
- }
-
- /**
- * Creates a new numerical tween with the provided settings and starts it in the global tween manager.
- *
- * @param from The starting floating point value.
- * @param to The ending floating point value.
- * @param tweenSettings The settings that configure and determine how the tween should animate.
- * @param updateCallback Callback function for updating any variable(s) that needs the current value when the tween updates.
- * @return The newly created and started tween.
- */
- public static FlixelTween num(float from, float to, FlixelTweenSettings tweenSettings, FlixelNumTween.FlixelNumTweenUpdateCallback updateCallback) {
- return new FlixelNumTween(from, to, tweenSettings, updateCallback)
- .setManager(globalManager)
- .start();
- }
-
- /**
- * Starts {@code this} tween and resets every value to its initial state.
- *
- * @return {@code this} tween.
- */
- public FlixelTween start() {
- resetBasic();
- running = true;
- finished = false;
- return this;
- }
-
- /**
- * Updates {@code this} tween by the given delta time.
- *
- * @param elapsed How much time has passed since the last update.
- */
- public void update(float elapsed) {
- if (paused || finished || !running || manager == null) {
- return;
- }
- if (tweenSettings == null) {
- return;
- }
-
- var ease = tweenSettings.getEase();
- var duration = tweenSettings.getDuration();
- var onStart = tweenSettings.getOnStart();
- var onUpdate = tweenSettings.getOnUpdate();
- var onComplete = tweenSettings.getOnComplete();
- var framerate = tweenSettings.getFramerate();
-
- float preTick = secondsSinceStart;
- secondsSinceStart += elapsed;
- float postTick = secondsSinceStart;
-
- float delay = (executions > 0) ? tweenSettings.getLoopDelay() : tweenSettings.getStartDelay();
- if (secondsSinceStart < delay) {
- return;
- }
-
- if (framerate > 0) {
- preTick = Math.round(preTick * framerate) / framerate;
- postTick = Math.round(postTick * framerate) / framerate;
- }
-
- scale = Math.max((postTick - delay), 0.0f) / duration;
- if (ease != null) {
- scale = ease.compute(scale);
- }
- if (backward) {
- scale = 1 - scale;
- }
- if (secondsSinceStart >= delay && !running) {
- running = true;
- if (onStart != null) {
- onStart.run(this);
- }
- }
-
- // Check if the tween has finished.
- if (secondsSinceStart >= duration + delay) {
- scale = (backward) ? 0 : 1;
- updateTweenValues();
- finished = true;
- if (onComplete != null) {
- onComplete.run(this);
- }
- } else {
- updateTweenValues();
- if (postTick > preTick && onUpdate != null) {
- onUpdate.run(this);
- }
- }
- }
-
- /**
- * Hook method called by {@link #update(float)} after {@link #scale} has been computed
- * and all common checks have passed. Subclasses should override this to apply their
- * tween-specific value updates instead of overriding {@link #update(float)}.
- *
- * This method is guaranteed to only be called when the tween is active (not paused,
- * not finished, has a manager and settings). The {@link #scale} field is already set to
- * the correct value for the current frame.
- */
- protected void updateTweenValues() {
- // No-op by default; subclasses provide their own implementation.
- }
-
- /**
- * Resumes {@code this} tween if it was previously paused.
- *
- * @return {@code this} tween.
- */
- public FlixelTween resume() {
- paused = false;
- running = true;
- return this;
- }
-
- /**
- * Pauses {@code this} tween, stopping it from updating until resumed.
- *
- * @return {@code this} tween.
- */
- public FlixelTween pause() {
- paused = true;
- running = false;
- return this;
- }
-
- /**
- * Stops {@code this} tween. Note that this does not remove the tween from the active tweens in
- * its manager.
- *
- * @return {@code this} tween.
- */
- public FlixelTween stop() {
- running = false;
- return this;
- }
-
- /**
- * Restarts {@code this} tween if it is currently running and not finished.
- *
- * @return {@code this} tween.
- */
- public FlixelTween restart() {
- if (running && !finished && manager != null) {
- start();
- }
- return this;
- }
-
- /**
- * Cancels {@code this} tween, removes it from its manager and automatically defaults its values.
- */
- public FlixelTween cancel() {
- resetBasic();
- manager.getTweenPool().free(this);
- return this;
- }
-
- @Override
- public void reset() {
- resetBasic();
- manager = null;
- }
-
- /**
- * Resets only the basic values of {@code this} tween without removing any references to the
- * object, its settings or its callback function.
- */
- public void resetBasic() {
- scale = 0.0f;
- secondsSinceStart = 0.0f;
- executions = 0;
- paused = false;
- running = false;
- finished = false;
- backward = false;
- }
-
- public FlixelTweenSettings getTweenSettings() {
- return tweenSettings;
- }
-
- public FlixelTween setTweenSettings(@NotNull FlixelTweenSettings tweenSettings) {
- this.tweenSettings = tweenSettings;
- return this;
- }
-
- public static FlixelTweenManager getGlobalManager() {
- return globalManager;
- }
-
- public FlixelTweenManager getManager() {
- return manager;
- }
-
- public FlixelTween setManager(FlixelTweenManager newManager) {
- if (newManager != null) {
- if (manager != null) {
- int index = manager.getActiveTweens().indexOf(this, true);
- manager.getActiveTweens().removeIndex(index);
- manager.getTweenPool().free(this);
- }
- manager = newManager;
- manager.getActiveTweens().add(this);
- }
- return this;
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTweenManager.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTweenManager.java
deleted file mode 100644
index 1c7f0b8..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTweenManager.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package me.stringdotjar.flixelgdx.tween;
-
-import com.badlogic.gdx.utils.Pool;
-import com.badlogic.gdx.utils.SnapshotArray;
-
-/** Manager class for handling a list of active {@link FlixelTween}s. */
-public class FlixelTweenManager {
-
- /** Array where all current active tweens are stored. */
- protected final SnapshotArray Iterates in reverse so that finished ONESHOT tweens can be removed by index
- * without skipping elements or traversing null padding beyond the array's valid size.
- *
- * @param elapsed The amount of time that has passed since the last frame.
- */
- public void update(float elapsed) {
- FlixelTween[] tweens = activeTweens.begin();
- for (int i = 0, n = activeTweens.size; i < n; i++) {
- FlixelTween tween = tweens[i];
- if (tween == null) {
- continue;
- }
- tween.update(elapsed);
-
- if (tween.finished) {
- if (tween.manager != this) {
- continue;
- }
- var settings = tween.getTweenSettings();
- if (settings == null) {
- continue;
- }
-
- switch (settings.getType()) {
- case ONESHOT -> {
- activeTweens.removeValue(tween, true);
- tweenPool.free(tween);
- }
- case PERSIST -> {} // Do nothing, let it be.
- }
- }
- }
- activeTweens.end();
- }
-
- public SnapshotArray Note that this is only used on a {@link me.stringdotjar.flixelgdx.tween.type.FlixelVarTween}.
- *
- * @param field The field to tween.
- * @param value The value to tween the field to.
- * @return {@code this} tween settings object for chaining.
- */
- public FlixelTweenSettings addGoal(String field, float value) {
- goals.add(new FlixelTweenVarGoal(field, value));
- return this;
- }
-
- /**
- * Adds a new property goal that tweens a value via a getter and setter rather than direct field
- * access. This allows side effects (bounds updates, listeners, etc.) to fire naturally through
- * the setter on every interpolated step.
- *
- * The getter is called once at tween start to capture the initial value. Each subsequent
- * update interpolates from that captured value toward {@code toValue} and passes the result to
- * the setter.
- *
- * @param getter Supplies the current value of the property at tween start.
- * @param toValue The value to tween the property to.
- * @param setter Consumes the interpolated value on every tween update.
- * @return {@code this} tween settings object for chaining.
- */
- public FlixelTweenSettings addPropertyGoal(@NotNull FlixelTweenPropertyGoal.FlixelTweenPropertyFloatGetter getter, float toValue, @NotNull FlixelTweenPropertyGoal.FlixelTweenPropertyFloatSetter setter) {
- propertyGoals.add(new FlixelTweenPropertyGoal(getter, toValue, setter));
- return this;
- }
-
- /**
- * Sets the duration of how long the tween should last for.
- *
- * @param duration The new value to set.
- * @return {@code this} tween settings object for chaining.
- */
- public FlixelTweenSettings setDuration(float duration) {
- this.duration = duration;
- return this;
- }
-
- public float getDuration() {
- return duration;
- }
-
- public FlixelTweenType getType() {
- return type;
- }
-
- public FlixelEase.FunkinEaseFunction getEase() {
- return ease;
- }
-
- public FlixelEase.FunkinEaseStartCallback getOnStart() {
- return onStart;
- }
-
- public FlixelEase.FunkinEaseUpdateCallback getOnUpdate() {
- return onUpdate;
- }
-
- public FlixelEase.FunkinEaseCompleteCallback getOnComplete() {
- return onComplete;
- }
-
- public FlixelTweenVarGoal getGoal(String field) {
- for (FlixelTweenVarGoal goal : goals) {
- if (goal.field().equals(field)) {
- return goal;
- }
- }
- return null;
- }
-
- public Array Note that this is faster than {@link FlixelVarTween} since it does not use reflection to access the fields.
- * It is recommended to use this when you need setter side effects (e.g. bounds updates, listeners) to
- * run on every interpolated step, the {@code FlixelVarTween} type is there for convenience.
- */
-public class FlixelPropertyTween extends FlixelTween {
-
- /**
- * Cached property goals captured at {@link #start()} to avoid re-allocating the list every
- * frame inside {@link #updateTweenValues()}.
- */
- protected Array Although it is slightly slower than a {@link FlixelPropertyTween}, this type is here
- * just in case you need it and for convenience.
- */
-public class FlixelVarTween extends FlixelTween {
-
- /** The object to tween. */
- protected Object object;
-
- /** The initial values of the fields being tweened. */
- protected final ObjectFloatMap Note that this does NOT add the tween to the global manager, it just assigns its main
- * values. That's it. If you wish to create a tween to automatically start working, you might want
- * to see {@link FlixelTween#tween(Object object, FlixelTweenSettings tweenSettings,
- * FunkinVarTweenUpdateCallback updateCallback)}.
- *
- * @param object The object to tween values.
- * @param settings The settings that configure and determine how the tween should animate and last for.
- * @param updateCallback Callback function for updating the objects values when the tween updates.
- */
- public FlixelVarTween(Object object, FlixelTweenSettings settings, FunkinVarTweenUpdateCallback updateCallback) {
- super(settings);
- this.object = object;
- this.updateCallback = updateCallback;
- }
-
- @Override
- public FlixelTween start() {
- super.start();
-
- if (tweenSettings == null) {
- return this;
- }
-
- var goals = tweenSettings.getGoals();
- if (goals == null || goals.isEmpty()) {
- return this;
- }
-
- if (fieldsCache == null) {
- fieldsCache = FlixelReflectUtil.getAllFieldsAsArray(object.getClass());
- }
-
- ObjectSet When running from the IDE the working directory is the {@code assets/} folder, so the raw
- * relative path works as-is. When running from a packaged JAR the assets are embedded as
- * classpath resources and MiniAudio cannot open them by name. In that case the resource is
- * extracted to a temp file on first call, and the temp file's absolute path is returned. Results
- * are cached so repeated calls for the same path do not produce extra temp files.
- *
- * @param path The internal asset path, e.g. {@code "shared/sounds/foo.ogg"}.
- * @return An absolute filesystem path that MiniAudio can open.
- */
- public static String resolveAudioPath(String path) {
- return audioPathCache.computeIfAbsent(path, FlixelPathsUtil::extractAudioPath);
- }
-
- private static String extractAudioPath(String path) {
- FileHandle handle = asset(path);
- if (handle.file().exists()) {
- return handle.file().getAbsolutePath();
- }
- // Asset is inside a JAR, copy it out to a temp file so MiniAudio can open it.
- String ext = path.contains(".") ? path.substring(path.lastIndexOf('.')) : "";
- try {
- File temp = File.createTempFile("flixelaudio_", ext);
- temp.deleteOnExit();
- handle.copyTo(new FileHandle(temp));
- return temp.getAbsolutePath();
- } catch (IOException e) {
- throw new RuntimeException("Failed to extract audio asset from JAR: " + path, e);
- }
- }
-
- private FlixelPathsUtil() {}
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/util/FlixelReflectUtil.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/util/FlixelReflectUtil.java
deleted file mode 100644
index be4ea93..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/util/FlixelReflectUtil.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package me.stringdotjar.flixelgdx.util;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-
-/**
- * Backend utility class for obtaining and manipulating fields on objects through the usage of Java reflection.
- */
-public final class FlixelReflectUtil {
-
- private FlixelReflectUtil() {}
-
- /**
- * Checks if a field exists on a given object.
- *
- * @param target The object to verify the existence of the given field to check.
- * @param fieldName The name of the
- * @return If the field exists on the given object.
- */
- public static boolean hasField(Object target, String fieldName) {
- return getAllFields(target.getClass()).stream().anyMatch(field -> field.getName().equals(fieldName));
- }
-
- /**
- * Obtains all fields of a class, including the master types above it all the way to {@link
- * Object}.
- *
- * @param type A class literal to obtain the fields from.
- * @return All fields from itself and its master classes above it.
- */
- public static List Gradle builds each module (e.g. {@code flixelgdx}) into its own module JAR inside
- * {@code build/libs/} and puts that on the classpath during IDE runs. Checking only whether the
- * code-source path ends with {@code .jar} therefore incorrectly returns {@code true} in the IDE.
- * Instead, this method opens the JAR that contains this class and inspects its manifest for a
- * {@code Main-Class} attribute. The only JAR in this project that carries that attribute is the
- * fat distribution JAR produced by the {@code lwjgl3:jar} task. Individual module JARs do not
- * have it.
- *
- * @return {@code true} if running from the distribution JAR, {@code false} otherwise.
- */
- public static boolean isRunningFromJar() {
- try {
- String path = getWorkingDirectory();
-
- if (path == null) {
- // Failed to get the working directory, so we can't determine if we're running from a JAR or not.
- return false;
- }
-
- if (!path.endsWith(".jar")) {
- // Exploded class-file directory, which we can safely assume is from the IDE.
- return false;
- }
- // The class is inside a JAR. Module JARs built during development have no Main-Class entry.
- // The fat distribution JAR always does (set by the lwjgl3:jar manifest block).
- try (JarFile jar = new JarFile(path)) {
- var manifest = jar.getManifest();
- return manifest != null && manifest.getMainAttributes().getValue("Main-Class") != null;
- }
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- * Returns {@code true} when the application is running inside an IDE (IntelliJ, Eclipse, Cursor,
- * VS Code, etc.), and {@code false} when running from the distribution JAR or plain classpath.
- *
- * Detection uses IDE-specific system properties, classpath hints, and the code source path.
- * Gradle-based runs are detected via {@code build/classes} (exploded) or a JAR under
- * {@code build/libs/} that is not the distribution JAR (no {@code Main-Class} in manifest).
- *
- * @return {@code true} if running in an IDE, {@code false} otherwise.
- */
- public static boolean isRunningInIDE() {
- // IntelliJ (run/debug).
- if (System.getProperty("idea.launcher.port") != null) {
- return true;
- }
- // IntelliJ fallback: idea_rt.jar on classpath (e.g. debug).
- if (System.getProperty("java.class.path", "").contains("idea_rt.jar")) {
- return true;
- }
- // Eclipse.
- if (System.getProperty("eclipse.application") != null) {
- return true;
- }
- var path = getWorkingDirectory();
- if (path == null) {
- return false;
- }
- // IntelliJ default output.
- if (path.contains("out/production")) {
- return true;
- }
- // Eclipse default output.
- if (path.contains("bin/")) {
- return true;
- }
- // Gradle: exploded classes (e.g. build/classes/java/main).
- if (path.contains("build/classes")) {
- return true;
- }
- // Gradle: module JAR on classpath (build/libs/*.jar without Main-Class); distribution JAR has Main-Class.
- if (path.contains("build/libs") && path.endsWith(".jar") && !isRunningFromJar()) {
- return true;
- }
- return false;
- }
-
- /**
- * Detects the current runtime environment.
- *
- * This method is used to determine if the application is running in the IDE, from a JAR, or from the classpath.
- *
- * @return The detected environment.
- */
- public static RunEnvironment detectEnvironment() {
- if (isRunningInIDE()) {
- return RunEnvironment.IDE;
- }
- if (isRunningFromJar()) {
- return RunEnvironment.JAR;
- }
- return RunEnvironment.CLASSPATH;
- }
-
- /**
- * Returns the working directory of the game.
- *
- * @return The working directory of the game. If an error occurs, {@code null} is returned.
- */
- public static String getWorkingDirectory() {
- try {
- return FlixelRuntimeUtil.class
- .getProtectionDomain()
- .getCodeSource()
- .getLocation()
- .toURI()
- .getPath();
- } catch (Exception e) {
- return null;
- }
- }
-
- /**
- * Returns the root package name of the library. This is done just in case
- * (for whatever reason it may be) the root package changes.
- *
- * @return The root package name of the library.
- */
- public static String getLibraryRoot() {
- return FlixelRuntimeUtil.class.getPackageName().replaceAll("\\.[^.]+$", "");
- }
-
- /**
- * Obtains a string representation of where an exception was thrown from, including the class,
- * method, file, and line number.
- *
- * @param exception The exception to obtain the location from.
- * @return A string representation of where the exception was thrown from.
- */
- public static String getExceptionLocation(Throwable exception) {
- if (exception == null) {
- return "Unknown Location";
- }
- StackTraceElement[] stackTrace = exception.getStackTrace();
- if (stackTrace.length == 0) {
- return "Unknown Location";
- }
- StackTraceElement element = stackTrace[0];
- return "FILE="
- + element.getFileName()
- + ", CLASS="
- + element.getClassName()
- + ", METHOD="
- + element.getMethodName()
- + "(), LINE="
- + element.getLineNumber();
- }
-
- /**
- * Obtains a full detailed message from an exception, including its type, location, and stack trace.
- *
- * @param exception The exception to obtain the message from.
- * @return A full detailed message from the exception.
- */
- public static String getFullExceptionMessage(Throwable exception) {
- if (exception == null) {
- return "No exception provided.";
- }
- StringBuilder messageBuilder = new StringBuilder();
- messageBuilder.append("Exception: ").append(exception).append("\n");
- messageBuilder.append("Location: ").append(getExceptionLocation(exception)).append("\n");
- messageBuilder.append("Stack Trace:\n");
- for (StackTraceElement element : exception.getStackTrace()) {
- messageBuilder.append("\tat ").append(element.toString()).append("\n");
- }
- return messageBuilder.toString();
- }
-
- /**
- * Enum representing the environment in which Flixel is running in.
- */
- public enum RunEnvironment {
- IDE,
- JAR,
- CLASSPATH
- }
-
- private FlixelRuntimeUtil() {}
-}
diff --git a/flixelgdx/core/src/main/java/module-info.java b/flixelgdx/core/src/main/java/module-info.java
deleted file mode 100644
index 784f441..0000000
--- a/flixelgdx/core/src/main/java/module-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-module me.stringdotjar.flixelgdx.core {
- exports me.stringdotjar.flixelgdx;
- exports me.stringdotjar.flixelgdx.backend;
- exports me.stringdotjar.flixelgdx.display;
- exports me.stringdotjar.flixelgdx.text;
- exports me.stringdotjar.flixelgdx.group;
- exports me.stringdotjar.flixelgdx.input;
- exports me.stringdotjar.flixelgdx.logging;
- exports me.stringdotjar.flixelgdx.signal;
- exports me.stringdotjar.flixelgdx.tween;
- exports me.stringdotjar.flixelgdx.tween.settings;
- exports me.stringdotjar.flixelgdx.tween.type;
- exports me.stringdotjar.flixelgdx.util;
-
- // Automatic module names (from JAR filenames when on module path).
- requires transitive gdx;
- requires transitive gdx.freetype;
- requires transitive anim8.gdx;
- requires transitive libgdx.utils;
- requires transitive miniaudio;
- requires org.fusesource.jansi;
- requires org.jetbrains.annotations;
-}
diff --git a/flixelgdx/lwjgl3/build.gradle b/flixelgdx/lwjgl3/build.gradle
deleted file mode 100644
index 4e8bcd5..0000000
--- a/flixelgdx/lwjgl3/build.gradle
+++ /dev/null
@@ -1,18 +0,0 @@
-[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
-eclipse.project.name = appName + '-flixelgdx-lwjgl3'
-
-apply plugin: "java-library"
-
-java {
- sourceCompatibility = 17
- targetCompatibility = 17
-}
-
-dependencies {
- api project(":flixelgdx:core")
-
- api "games.rednblack.miniaudio:gdx-miniaudio-platform:$miniaudioVersion:natives-desktop"
- api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
- api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
- api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
-}
diff --git a/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/FlixelLwjgl3Launcher.java b/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/FlixelLwjgl3Launcher.java
deleted file mode 100644
index 9a91ab0..0000000
--- a/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/FlixelLwjgl3Launcher.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package me.stringdotjar.flixelgdx.backend.lwjgl3;
-
-import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
-import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
-import com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowAdapter;
-import me.stringdotjar.flixelgdx.Flixel;
-import me.stringdotjar.flixelgdx.FlixelGame;
-import me.stringdotjar.flixelgdx.backend.lwjgl3.alert.FlixelLwjgl3Alerter;
-
-/**
- * Launches the desktop (LWJGL3) version of the Flixel game.
- */
-public class FlixelLwjgl3Launcher {
-
- /**
- * Launches the LWJGL3 version of the Flixel game with the given game instance. This should be called from the main
- * method of the libGDX LWJGL3 launcher class, and the game instance should be created in the same general area.
- *
- * @param game The game instance to launch. This should already be initialized with the desired configuration values.
- */
- public static void launch(FlixelGame game, String... icons) {
- Flixel.initialize(game, new FlixelLwjgl3Alerter());
-
- Lwjgl3ApplicationConfiguration configuration = new Lwjgl3ApplicationConfiguration();
- configuration.setTitle(game.getTitle());
- configuration.useVsync(game.isVsync());
- configuration.setForegroundFPS(game.getFramerate());
- if (game.isFullscreen()) {
- configuration.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
- } else {
- configuration.setWindowedMode(game.getWindowWidth(), game.getWindowHeight());
- }
- configuration.setWindowIcon(icons);
- configuration.setWindowListener(new Lwjgl3WindowAdapter() {
- @Override
- public void focusGained() {
- super.focusGained();
- Flixel.getGame().onWindowFocused();
- }
-
- @Override
- public void focusLost() {
- super.focusLost();
- Flixel.getGame().onWindowUnfocused();
- }
-
- @Override
- public void iconified(boolean isIconified) {
- super.iconified(isIconified);
- Flixel.getGame().onWindowMinimized(isIconified);
- }
- });
-
- new Lwjgl3Application(game, configuration);
- }
-}
diff --git a/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/alert/FlixelLwjgl3Alerter.java b/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/alert/FlixelLwjgl3Alerter.java
deleted file mode 100644
index bc5601d..0000000
--- a/flixelgdx/lwjgl3/src/main/java/me/stringdotjar/flixelgdx/backend/lwjgl3/alert/FlixelLwjgl3Alerter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package me.stringdotjar.flixelgdx.backend.lwjgl3.alert;
-
-import me.stringdotjar.flixelgdx.backend.Alerter;
-
-import java.awt.EventQueue;
-import java.lang.reflect.InvocationTargetException;
-
-import javax.swing.JOptionPane;
-
-public class FlixelLwjgl3Alerter implements Alerter {
-
- @Override
- public void showInfoAlert(String title, String message) {
- showAlert(title, message, JOptionPane.INFORMATION_MESSAGE);
- }
-
- @Override
- public void showWarningAlert(String title, String message) {
- showAlert(title, message, JOptionPane.WARNING_MESSAGE);
- }
-
- @Override
- public void showErrorAlert(String title, String message) {
- showAlert(title, message, JOptionPane.ERROR_MESSAGE);
- }
-
- private void showAlert(String title, Object message, int type) {
- String msg = message != null ? message.toString() : "null";
- if (EventQueue.isDispatchThread()) {
- JOptionPane.showMessageDialog(null, msg, title, type);
- } else {
- try {
- EventQueue.invokeAndWait(() -> {
- JOptionPane.showMessageDialog(null, msg, title, type);
- });
- } catch (InterruptedException | InvocationTargetException e) {
- // Ignore.
- }
- }
- }
-}
diff --git a/lwjgl3/build.gradle b/lwjgl3/build.gradle
index bcd9bd5..453c610 100644
--- a/lwjgl3/build.gradle
+++ b/lwjgl3/build.gradle
@@ -26,7 +26,9 @@ if (JavaVersion.current().isJava9Compatible()) {
dependencies {
implementation project(':polyverse')
- implementation project(":flixelgdx:lwjgl3")
+ implementation("com.github.stringdotjar:flixelgdx-lwjgl3:master-SNAPSHOT") {
+ changing = true
+ }
if (enableGraalNative == 'true') {
implementation "io.github.berstanio:gdx-svmhelper-backend-lwjgl3:$graalHelperVersion"
diff --git a/polyverse/build.gradle b/polyverse/build.gradle
index 6c123dd..ad12c6d 100644
--- a/polyverse/build.gradle
+++ b/polyverse/build.gradle
@@ -11,7 +11,9 @@ processResources.from(generatePolyverseVersion) {
}
dependencies {
- implementation project(":flixelgdx:core")
+ implementation("com.github.stringdotjar:flixelgdx-core:master-SNAPSHOT") {
+ changing = true
+ }
implementation "org.apache.groovy:groovy:5.0.4"
implementation "org.jetbrains:annotations:26.1.0"
diff --git a/settings.gradle b/settings.gradle
index 0684d9f..7c24eeb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,5 +9,18 @@ plugins {
// Polyverse and libGDX projects.
include 'polyverse', 'lwjgl3', 'android'
-// FlixelGDX projects.
-include 'flixelgdx:core', 'flixelgdx:lwjgl3', 'flixelgdx:android'
+// Include the FlixelGDX library only if it's found locally.
+// This supports two layouts:
+// 1) ../flixelgdx - sibling repo next to Polyverse (typical local dev)
+// 2) flixelgdx - nested repo inside this project (used by CI workflow)
+def flixelLocalDir = ['../flixelgdx', 'flixelgdx'].collect { file(it) }.find { it.exists() }
+if (flixelLocalDir != null) {
+ includeBuild(flixelLocalDir) {
+ dependencySubstitution {
+ // Substitute using the new group ID
+ substitute module('com.github.stringdotjar:flixelgdx-core') using project(':core')
+ substitute module('com.github.stringdotjar:flixelgdx-lwjgl3') using project(':lwjgl3')
+ substitute module('com.github.stringdotjar:flixelgdx-android') using project(':android')
+ }
+ }
+}
{@code
- * // Create a new subclass of FlixelGame.
- * // Remember that you can override any methods to add extra functionality
- * // to the game's behavior.
- * public class MyGame extends FlixelGame {
- * public MyGame(String title, int width, int height, FlixelState initialState) {
- * super(title, width, height, initialState);
- * }
- * }
- * }
- *
- * Then, in a platform-specific launcher, you can create a new instance of your game and run it:
- *
- * {@code
- * // Example of how to create a new game instance and run it using the LWJGL3 launcher.
- * public class Lwjgl3Launcher {
- * public static void main(String[] args) {
- * if (StartupHelper.startNewJvmIfRequired()) { // This handles macOS support and helps on Windows.
- * return;
- * }
- *
- * MyGame game = new MyGame(
- * "My Game",
- * 800,
- * 600,
- * new InitialState() // The initial state the game enters when it starts!
- * );
- *
- * FlixelLwjgl3Launcher.launch(game);
- * }
- * }
- * }
- */
-public abstract class FlixelGame implements ApplicationListener {
-
- /** The title displayed on the game's window. */
- protected String title;
-
- /** The size of the game's starting window position and its first camera. */
- protected Vector2 viewSize;
-
- /** The current window size stored in a vector object. */
- protected Vector2 windowSize;
-
- /** The entry point screen the game starts in (which becomes null after the game is done setting up!). */
- protected FlixelState initialScreen;
-
- /** The framerate of how fast the game should update and render. */
- private int framerate;
-
- /** Should the game use VSync to limit the framerate to the monitor's refresh rate? */
- private boolean vsync;
-
- /** Should the game start in fullscreen mode? */
- protected boolean fullscreen;
-
- /** Is the game's window currently focused? */
- private boolean isFocused = true;
-
- /** Is the game's window currently minimized? */
- private boolean isMinimized = false;
-
- /** The main stage used for rendering all screens and sprites on screen. */
- protected Stage stage;
-
- /** The main sprite batch used for rendering all sprites on screen. */
- protected SpriteBatch batch;
-
- /** The 1x1 texture used to draw the background color of the current screen. */
- protected Texture bgTexture;
-
- /** Where all the global cameras are stored. */
- protected SnapshotArray
- *
- */
-public class FlixelSpriteGroup extends FlixelSprite implements FlixelGroupable
- *
- *
- * @param degrees the new rotation in degrees.
- */
- @Override
- public void setAngle(float degrees) {
- float delta = degrees - getAngle();
- super.setAngle(degrees);
-
- switch (rotationMode) {
- case INDIVIDUAL:
- transformMembersIndividualRotation(delta);
- break;
- case ORBIT:
- orbitMembersAroundCenter(delta);
- break;
- case WHEEL:
- break;
- }
- }
-
- public RotationMode getRotationMode() {
- return rotationMode;
- }
-
- public void setRotationMode(RotationMode rotationMode) {
- this.rotationMode = rotationMode;
- }
-
- public float getRotationRadius() {
- return rotationRadius;
- }
-
- public void setRotationRadius(float rotationRadius) {
- this.rotationRadius = rotationRadius;
- }
-
- /**
- * Sets the opacity of the group and all of its current members. Members added later via
- * {@link #add(FlixelSprite)} will have their alpha multiplied by this value rather than
- * overwritten.
- *
- * @param a Alpha between 0 (fully transparent) and 1 (fully opaque).
- */
- @Override
- public void setAlpha(float a) {
- super.setAlpha(a);
- forEach(s -> s.setAlpha(a));
- }
-
- public float getAlpha() {
- return getColor().a;
- }
-
- /** Sets a color tint on the group and propagates it to all current members. */
- @Override
- public void setColor(Color tint) {
- super.setColor(tint);
- forEach(s -> s.setColor(tint));
- }
-
- /** Sets a color tint on the group and propagates it to all current members. */
- @Override
- public void setColor(float r, float g, float b, float a) {
- super.setColor(r, g, b, a);
- forEach(s -> s.setColor(r, g, b, a));
- }
-
- /** Sets a uniform scale on the group and propagates it to all current members. */
- @Override
- public void setScale(float scaleXY) {
- super.setScale(scaleXY);
- forEach(s -> s.setScale(scaleXY));
- }
-
- /** Sets a non-uniform scale on the group and propagates it to all current members. */
- @Override
- public void setScale(float scaleX, float scaleY) {
- super.setScale(scaleX, scaleY);
- forEach(s -> s.setScale(scaleX, scaleY));
- }
-
- /** Toggles the flip state on the X and/or Y axis for the group and all current members. */
- @Override
- public void flip(boolean x, boolean y) {
- super.flip(x, y);
- forEach(s -> s.flip(x, y));
- }
-
- /**
- * Sets the X-axis flip state on the group and all members to the desired value.
- * Unlike {@link #flip(boolean, boolean)}, which toggles, this method ensures a
- * specific state.
- *
- * @param flipX {@code true} to flip horizontally, {@code false} to un-flip.
- */
- public void setFlipX(boolean flipX) {
- if (isFlipX() != flipX) {
- super.flip(true, false);
- }
- forEach(s -> {
- if (s.isFlipX() != flipX) {
- s.flip(true, false);
- }
- });
- }
-
- /**
- * Sets the Y-axis flip state on the group and all members to the desired value.
- * Unlike {@link #flip(boolean, boolean)}, which toggles, this method ensures a
- * specific state.
- *
- * @param flipY {@code true} to flip vertically, {@code false} to un-flip.
- */
- public void setFlipY(boolean flipY) {
- if (isFlipY() != flipY) {
- super.flip(false, true);
- }
- forEach(s -> {
- if (s.isFlipY() != flipY) {
- s.flip(false, true);
- }
- });
- }
-
- public boolean isVisible() {
- return visible;
- }
-
- public void setVisible(boolean visible) {
- this.visible = visible;
- }
-
- /** Sets the rotation and scale pivot point on every current member. */
- @Override
- public void setOrigin(float originX, float originY) {
- super.setOrigin(originX, originY);
- forEach(s -> s.setOrigin(originX, originY));
- }
-
- /** Centers the origin on every current member based on each member's own dimensions. */
- @Override
- public void setOriginCenter() {
- super.setOriginCenter();
- forEach(FlixelSprite::setOriginCenter);
- }
-
- /**
- * Adds a sprite to the group. The sprite's position is automatically offset by the
- * group's current position, and its alpha is multiplied by the group's alpha. If the
- * group has a {@link #maxSize} and is already at capacity, the sprite is not added.
- */
- @Override
- public void add(FlixelSprite sprite) {
- if (sprite == null) {
- return;
- }
- if (maxSize > 0 && members.size >= maxSize) {
- return;
- }
- preAdd(sprite);
- members.add(sprite);
- }
-
- /** Adds a sprite to the group and returns it, allowing for method chaining. */
- public FlixelSprite addAndReturn(FlixelSprite sprite) {
- add(sprite);
- return sprite;
- }
-
- /**
- * Inserts a sprite at the given index, offset by the group's current position. The
- * index is clamped to the valid range {@code [0, length]}.
- *
- * @param index The index to insert the sprite at.
- * @param sprite The sprite to insert.
- */
- public void insert(int index, FlixelSprite sprite) {
- if (sprite == null) {
- return;
- }
- if (maxSize > 0 && members.size >= maxSize) {
- return;
- }
- preAdd(sprite);
- index = MathUtils.clamp(index, 0, members.size);
- members.insert(index, sprite);
- }
-
- /**
- * Removes a sprite from the group. The group's position offset is subtracted from the
- * sprite to restore it to local coordinates.
- */
- @Override
- public void remove(FlixelSprite sprite) {
- if (sprite == null) {
- return;
- }
- members.removeValue(sprite, true);
- sprite.setX(sprite.getX() - getX());
- sprite.setY(sprite.getY() - getY());
- }
-
- /**
- * Replaces an existing member with a new sprite. The new sprite is offset by the group's
- * current position. If {@code oldSprite} is not found, {@code newSprite} is simply added
- * to the end of the group instead.
- *
- * @param oldSprite The member to replace.
- * @param newSprite The replacement sprite.
- * @return The replacement sprite.
- */
- public FlixelSprite replace(FlixelSprite oldSprite, FlixelSprite newSprite) {
- if (oldSprite == null || newSprite == null) {
- return newSprite;
- }
- int idx = members.indexOf(oldSprite, true);
- if (idx < 0) {
- add(newSprite);
- return newSprite;
- }
- preAdd(newSprite);
- members.set(idx, newSprite);
- return newSprite;
- }
-
- /** Destroys every member and then clears the group. */
- @Override
- public void clear() {
- forEach(FlixelSprite::destroy);
- members.clear();
- }
-
- /** Returns the member at the given index, or {@code null} if the index is out of bounds. */
- public FlixelSprite get(int index) {
- if (index < 0 || index >= members.size) {
- return null;
- }
- return members.get(index);
- }
-
- public int getLength() {
- return members.size;
- }
-
- /** Returns the number of non-null members, which may differ from {@link #getLength()}. */
- public int countMembers() {
- int count = 0;
- for (int i = 0, n = members.size; i < n; i++) {
- if (members.get(i) != null) {
- count++;
- }
- }
- return count;
- }
-
- public boolean isEmpty() {
- return members.size == 0;
- }
-
- public int getMaxSize() {
- return maxSize;
- }
-
- public void setMaxSize(int maxSize) {
- this.maxSize = Math.max(0, maxSize);
- }
-
- public SnapshotArrayUsage
- * {@code
- * // Register fonts at startup (e.g. in your FlixelState.create()):
- * FlixelFontRegistry.register("pixel", Gdx.files.internal("fonts/pixel.ttf"));
- * FlixelFontRegistry.register("ui", Gdx.files.internal("fonts/opensans.ttf"));
- *
- * // Optionally set a global default so FlixelText objects use it automatically:
- * FlixelFontRegistry.setDefault("ui");
- *
- * // Use in FlixelText:
- * FlixelText title = new FlixelText(0, 0, 0, "Hello!", 32);
- * title.setFont("pixel");
- *
- * // Clean up when the game shuts down:
- * FlixelFontRegistry.dispose();
- * }
- *
- * Lifecycle
- * Auto-sizing
- * Fonts
- * Border Styles
- * Sprite Methods
- *
- *
- */
- private void rebuildFont() {
- BitmapFont oldFont = bitmapFont;
-
- FreeTypeFontGenerator gen = resolveGenerator();
- if (gen != null) {
- FreeTypeFontParameter param = new FreeTypeFontParameter();
- param.size = size;
- param.spaceX = (int) letterSpacing;
- param.genMipMaps = true;
- param.minFilter = Texture.TextureFilter.Linear;
- param.magFilter = Texture.TextureFilter.Linear;
-
- bitmapFont = gen.generateFont(param);
- } else {
- bitmapFont = new BitmapFont();
- float defaultHeight = bitmapFont.getLineHeight();
- if (defaultHeight > 0) {
- bitmapFont.getData().setScale(size / defaultHeight);
- }
- bitmapFont.getRegion()
- .getTexture()
- .setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
- }
-
- if (oldFont != null) {
- oldFont.dispose();
- }
- }
-
- /**
- * Resolves the {@link FreeTypeFontGenerator} to use, following the cascade:
- * registry ID → direct file → registry default → {@code null}.
- */
- private FreeTypeFontGenerator resolveGenerator() {
- if (fontRegistryId != null) {
- generator = FlixelFontRegistry.getGenerator(fontRegistryId);
- ownsGenerator = false;
- return generator;
- }
-
- if (fontFile != null) {
- String path = fontFile.path();
- if (!ownsGenerator || generator == null || !path.equals(currentGeneratorPath)) {
- disposeOwnedGenerator();
- generator = new FreeTypeFontGenerator(fontFile);
- currentGeneratorPath = path;
- ownsGenerator = true;
- }
- return generator;
- }
-
- FreeTypeFontGenerator defaultGen = FlixelFontRegistry.getDefaultGenerator();
- if (defaultGen != null) {
- generator = defaultGen;
- ownsGenerator = false;
- return generator;
- }
-
- return null;
- }
-
- /** Recalculates the text layout and updates the sprite dimensions. */
- private void rebuildLayout() {
- if (bitmapFont == null) {
- return;
- }
-
- boolean fixedWidth = fieldWidth > 0 && !autoSize;
-
- if (fixedWidth) {
- glyphLayout.setText(bitmapFont, text, Color.WHITE, fieldWidth,
- alignment.gdxAlign, wordWrap);
- } else if (alignment != Alignment.LEFT) {
- glyphLayout.setText(bitmapFont, text);
- float naturalWidth = glyphLayout.width;
- if (naturalWidth > 0) {
- glyphLayout.setText(bitmapFont, text, Color.WHITE, naturalWidth, alignment.gdxAlign, false);
- }
- } else {
- glyphLayout.setText(bitmapFont, text);
- }
-
- float w = fixedWidth ? fieldWidth : glyphLayout.width;
- float h = (fieldHeight > 0 && !autoSize) ? fieldHeight : glyphLayout.height;
- setSize(w, h);
- setOriginCenter();
- }
-
- /**
- * Draws the full text content (border + main text) at the given coordinates.
- *
- * @param batch The sprite batch.
- * @param x The x coordinate of the text's left edge.
- * @param y The y coordinate of the text's top edge (BitmapFont convention).
- */
- private void drawTextContent(Batch batch, float x, float y) {
- Color spriteColor = getColor();
-
- if (borderStyle != BorderStyle.NONE && borderColor.a > 0 && borderSize > 0) {
- drawBorder(batch, x, y);
- }
-
- updateLayoutColors(spriteColor);
- bitmapFont.draw(batch, glyphLayout, x, y);
- }
-
- /** Draws the text border/outline by rendering the layout at offset positions. */
- private void drawBorder(Batch batch, float x, float y) {
- updateLayoutColors(borderColor);
-
- switch (borderStyle) {
- case SHADOW:
- bitmapFont.draw(batch, glyphLayout, x + borderSize, y - borderSize);
- break;
-
- case OUTLINE_FAST:
- bitmapFont.draw(batch, glyphLayout, x - borderSize, y);
- bitmapFont.draw(batch, glyphLayout, x + borderSize, y);
- bitmapFont.draw(batch, glyphLayout, x, y - borderSize);
- bitmapFont.draw(batch, glyphLayout, x, y + borderSize);
- break;
-
- case OUTLINE:
- int iterations = Math.max(1, (int) (borderSize * borderQuality));
- float step = borderSize / iterations;
- for (int i = 1; i <= iterations; i++) {
- float offset = step * i;
- bitmapFont.draw(batch, glyphLayout, x - offset, y - offset);
- bitmapFont.draw(batch, glyphLayout, x, y - offset);
- bitmapFont.draw(batch, glyphLayout, x + offset, y - offset);
- bitmapFont.draw(batch, glyphLayout, x - offset, y);
- bitmapFont.draw(batch, glyphLayout, x + offset, y);
- bitmapFont.draw(batch, glyphLayout, x - offset, y + offset);
- bitmapFont.draw(batch, glyphLayout, x, y + offset);
- bitmapFont.draw(batch, glyphLayout, x + offset, y + offset);
- }
- break;
-
- default:
- break;
- }
- }
-
- /**
- * Updates the color of all glyphs in the cached layout. The layout stores colors
- * as (glyphIndex, ABGR8888) pairs in {@link GlyphLayout#colors}.
- */
- private void updateLayoutColors(Color color) {
- int colorBits = color.toIntBits();
- for (int i = 1; i < glyphLayout.colors.size; i += 2) {
- glyphLayout.colors.set(i, colorBits);
- }
- }
-
- /** Disposes the BitmapFont and any privately-owned generator. */
- private void disposeFont() {
- if (bitmapFont != null) {
- bitmapFont.dispose();
- bitmapFont = null;
- }
- disposeOwnedGenerator();
- }
-
- /** Disposes the generator only if this instance owns it (not borrowed from the registry). */
- private void disposeOwnedGenerator() {
- if (generator != null && ownsGenerator) {
- generator.dispose();
- }
- generator = null;
- currentGeneratorPath = null;
- ownsGenerator = false;
- }
-
- /** Horizontal alignment options for text within its field. */
- public enum Alignment {
- LEFT(Align.left),
- CENTER(Align.center),
- RIGHT(Align.right);
-
- final int gdxAlign;
-
- Alignment(int gdxAlign) {
- this.gdxAlign = gdxAlign;
- }
-
- public static Alignment fromInt(int value) {
- return switch (value) {
- case 0 -> LEFT;
- case 1 -> CENTER;
- case 2 -> RIGHT;
- default -> throw new IllegalArgumentException("Invalid alignment value: " + value);
- };
- }
-
- public int toInt() {
- return switch (this) {
- case LEFT -> 0;
- case CENTER -> 1;
- case RIGHT -> 2;
- };
- }
-
- public int toGdxAlign() {
- return switch (this) {
- case LEFT -> Align.left;
- case CENTER -> Align.center;
- case RIGHT -> Align.right;
- };
- }
- }
-
- /** Border/outline styles for text rendering. */
- public enum BorderStyle {
- /** No border. */
- NONE,
- /** A simple drop-shadow offset below and to the right of the text. */
- SHADOW,
- /** A full outline drawn in all 8 directions around each glyph. */
- OUTLINE,
- /** A faster outline using only the 4 cardinal directions. */
- OUTLINE_FAST
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelEase.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelEase.java
deleted file mode 100644
index 074e992..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelEase.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package me.stringdotjar.flixelgdx.tween;
-
-/** Class where all easer functions are stored, mostly used for tweening. */
-public final class FlixelEase {
-
- // Easing constants for specific functions.
- private static final float PI2 = (float) Math.PI / 2;
- private static final float EL = (float) ((float) 2 * Math.PI / .45);
- private static final float B1 = (float) ((float) 1 / 2.75);
- private static final float B2 = (float) ((float) 2 / 2.75);
- private static final float B3 = (float) ((float) 1.5 / 2.75);
- private static final float B4 = (float) ((float) 2.5 / 2.75);
- private static final float B5 = (float) ((float) 2.25 / 2.75);
- private static final float B6 = (float) ((float) 2.625 / 2.75);
- private static final float ELASTIC_AMPLITUDE = 1;
- private static final float ELASTIC_PERIOD = 0.4f;
-
- private FlixelEase() {}
-
- public static float linear(float t) {
- return t;
- }
-
- public static float quadIn(float t) {
- return t * t;
- }
-
- public static float quadOut(float t) {
- return -t * (t - 2);
- }
-
- public static float quadInOut(float t) {
- return t <= .5 ? t * t * 2 : 1 - (--t) * t * 2;
- }
-
- public static float cubeIn(float t) {
- return t * t * t;
- }
-
- public static float cubeOut(float t) {
- return 1 + (--t) * t * t;
- }
-
- public static float cubeInOut(float t) {
- return t <= .5 ? t * t * t * 4 : 1 + (--t) * t * t * 4;
- }
-
- public static float quartIn(float t) {
- return t * t * t * t;
- }
-
- public static float quartOut(float t) {
- return 1 - (t -= 1) * t * t * t;
- }
-
- public static float quartInOut(float t) {
- return t <= .5 ? t * t * t * t * 8 : (float) ((1 - (t = t * 2 - 2) * t * t * t) / 2 + .5);
- }
-
- public static float quintIn(float t) {
- return t * t * t * t * t;
- }
-
- public static float quintOut(float t) {
- return (t = t - 1) * t * t * t * t + 1;
- }
-
- public static float quintInOut(float t) {
- return ((t *= 2) < 1) ? (t * t * t * t * t) / 2 : ((t -= 2) * t * t * t * t + 2) / 2;
- }
-
- public static float smoothStepIn(float t) {
- return 2 * smoothStepInOut(t / 2);
- }
-
- public static float smoothStepOut(float t) {
- return 2 * smoothStepInOut((float) (t / 2 + 0.5)) - 1;
- }
-
- public static float smoothStepInOut(float t) {
- return t * t * (t * -2 + 3);
- }
-
- public static float smootherStepIn(float t) {
- return 2 * smootherStepInOut(t / 2);
- }
-
- public static float smootherStepOut(float t) {
- return 2 * smootherStepInOut((float) (t / 2 + 0.5)) - 1;
- }
-
- public static float smootherStepInOut(float t) {
- return t * t * t * (t * (t * 6 - 15) + 10);
- }
-
- public static float sineIn(float t) {
- return (float) (-Math.cos(PI2 * t) + 1);
- }
-
- public static float sineOut(float t) {
- return (float) Math.sin(PI2 * t);
- }
-
- public static float sineInOut(float t) {
- return (float) (-Math.cos(Math.PI * t) / 2 + .5);
- }
-
- public static float bounceIn(float t) {
- return 1 - bounceOut(1 - t);
- }
-
- public static float bounceOut(float t) {
- if (t < B1) return (float) (7.5625 * t * t);
- if (t < B2) return (float) (7.5625 * (t - B3) * (t - B3) + .75);
- if (t < B4) return (float) (7.5625 * (t - B5) * (t - B5) + .9375);
- return (float) (7.5625 * (t - B6) * (t - B6) + .984375);
- }
-
- public static float bounceInOut(float t) {
- return t < 0.5 ? (1 - bounceOut(1 - 2 * t)) / 2 : (1 + bounceOut(2 * t - 1)) / 2;
- }
-
- public static float circIn(float t) {
- return (float) -(Math.sqrt(1 - t * t) - 1);
- }
-
- public static float circOut(float t) {
- return (float) Math.sqrt(1 - (t - 1) * (t - 1));
- }
-
- public static float circInOut(float t) {
- return (float)
- (t <= .5
- ? (Math.sqrt(1 - t * t * 4) - 1) / -2
- : (Math.sqrt(1 - (t * 2 - 2) * (t * 2 - 2)) + 1) / 2);
- }
-
- public static float expoIn(float t) {
- return (float) Math.pow(2, 10 * (t - 1));
- }
-
- public static float expoOut(float t) {
- return (float) (-Math.pow(2, -10 * t) + 1);
- }
-
- public static float expoInOut(float t) {
- return (float)
- (t < .5 ? Math.pow(2, 10 * (t * 2 - 1)) / 2 : (-Math.pow(2, -10 * (t * 2 - 1)) + 2) / 2);
- }
-
- public static float backIn(float t) {
- return (float) (t * t * (2.70158 * t - 1.70158));
- }
-
- public static float backOut(float t) {
- return (float) (1 - (--t) * (t) * (-2.70158 * t - 1.70158));
- }
-
- public static float backInOut(float t) {
- t *= 2;
- if (t < 1) return (float) (t * t * (2.70158 * t - 1.70158) / 2);
- t--;
- return (float) ((1 - (--t) * (t) * (-2.70158 * t - 1.70158)) / 2 + .5);
- }
-
- public static float elasticIn(float t) {
- return (float)
- -(ELASTIC_AMPLITUDE
- * Math.pow(2, 10 * (t -= 1))
- * Math.sin(
- (t - (ELASTIC_PERIOD / (2 * Math.PI) * Math.asin(1 / ELASTIC_AMPLITUDE)))
- * (2 * Math.PI)
- / ELASTIC_PERIOD));
- }
-
- public static float elasticOut(float t) {
- return (float)
- (ELASTIC_AMPLITUDE
- * Math.pow(2, -10 * t)
- * Math.sin(
- (t - (ELASTIC_PERIOD / (2 * Math.PI) * Math.asin(1 / ELASTIC_AMPLITUDE)))
- * (2 * Math.PI)
- / ELASTIC_PERIOD)
- + 1);
- }
-
- public static float elasticInOut(float t) {
- if (t < 0.5) {
- return (float)
- (-0.5
- * (Math.pow(2, 10 * (t -= 0.5f))
- * Math.sin((t - (ELASTIC_PERIOD / 4)) * (2 * Math.PI) / ELASTIC_PERIOD)));
- }
- return (float)
- (Math.pow(2, -10 * (t -= 0.5f))
- * Math.sin((t - (ELASTIC_PERIOD / 4)) * (2 * Math.PI) / ELASTIC_PERIOD)
- * 0.5
- + 1);
- }
-
- @FunctionalInterface
- public interface FunkinEaseFunction {
- float compute(float t);
- }
-
- @FunctionalInterface
- public interface FunkinEaseStartCallback {
- void run(FlixelTween tween);
- }
-
- @FunctionalInterface
- public interface FunkinEaseUpdateCallback {
- void run(FlixelTween tween);
- }
-
- @FunctionalInterface
- public interface FunkinEaseCompleteCallback {
- void run(FlixelTween tween);
- }
-}
diff --git a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTween.java b/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTween.java
deleted file mode 100644
index 445af1d..0000000
--- a/flixelgdx/core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTween.java
+++ /dev/null
@@ -1,296 +0,0 @@
-package me.stringdotjar.flixelgdx.tween;
-
-import com.badlogic.gdx.utils.Pool;
-import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings;
-import me.stringdotjar.flixelgdx.tween.type.FlixelNumTween;
-import me.stringdotjar.flixelgdx.tween.type.FlixelPropertyTween;
-import me.stringdotjar.flixelgdx.tween.type.FlixelVarTween;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Core class for creating new tweens to add nice and smooth animations.
- *
- *