From 933b4f0a37fb9f64e3d984125011a3c2da2771d0 Mon Sep 17 00:00:00 2001 From: String Date: Fri, 6 Mar 2026 14:01:52 -0600 Subject: [PATCH 1/2] Add custom functionality to clear tweens on state switch --- .../me/stringdotjar/flixelgdx/Flixel.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java b/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java index 4174eff..7860379 100644 --- a/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java +++ b/core/src/main/java/me/stringdotjar/flixelgdx/Flixel.java @@ -19,6 +19,7 @@ import me.stringdotjar.flixelgdx.logging.FlixelLogger; import me.stringdotjar.flixelgdx.signal.FlixelSignal; import me.stringdotjar.flixelgdx.signal.FlixelSignalData.UpdateSignalData; +import me.stringdotjar.flixelgdx.tween.FlixelTween; import me.stringdotjar.flixelgdx.signal.FlixelSignalData.StateSwitchSignalData; import org.jetbrains.annotations.NotNull; @@ -90,12 +91,22 @@ public static void initialize(@NotNull FlixelGame gameInstance, initialized = true; } + /** + * Sets the current screen to the provided screen, and clears all active tweens by default. + * + * @param newState The new {@code FlixelState} to set as the current screen. + */ + public static void switchState(FlixelState newState) { + switchState(newState, true); + } + /** * Sets the current screen to the provided screen. * * @param newState The new {@code FlixelState} to set as the current screen. + * @param clearTweens Whether to clear all active tweens. */ - public static void switchState(FlixelState newState) { + public static void switchState(FlixelState newState, boolean clearTweens) { Signals.preStateSwitch.dispatch(new StateSwitchSignalData(newState)); if (!initialized) { throw new IllegalStateException("Flixel has not been initialized yet!"); @@ -107,6 +118,14 @@ public static void switchState(FlixelState newState) { state.hide(); state.dispose(); } + if (clearTweens) { + FlixelTween.getGlobalManager() + .getActiveTweens() + .forEach(tween -> tween.cancel()); + FlixelTween.getGlobalManager() + .getTweenPool() + .clear(); + } game.resetCameras(); state = newState; state.create(); From 03edb079896eb782f69829892d6555fd46b68120 Mon Sep 17 00:00:00 2001 From: String Date: Sat, 7 Mar 2026 18:55:20 -0600 Subject: [PATCH 2/2] Add builders for constructing tweens more easily --- README.md | 47 +++++----- .../flixelgdx/tween/FlixelTween.java | 59 +++++++++--- .../flixelgdx/tween/FlixelTweenManager.java | 20 +++- .../builders/FlixelAbstractTweenBuilder.java | 94 +++++++++++++++++++ .../tween/builders/FlixelNumTweenBuilder.java | 59 ++++++++++++ .../builders/FlixelPropertyTweenBuilder.java | 45 +++++++++ .../tween/builders/FlixelTweenBuilder.java | 21 +++++ .../tween/builders/FlixelVarTweenBuilder.java | 62 ++++++++++++ flixelgdx-core/src/main/java/module-info.java | 1 + 9 files changed, 370 insertions(+), 38 deletions(-) create mode 100644 flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelAbstractTweenBuilder.java create mode 100644 flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelNumTweenBuilder.java create mode 100644 flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelPropertyTweenBuilder.java create mode 100644 flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelTweenBuilder.java create mode 100644 flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelVarTweenBuilder.java diff --git a/README.md b/README.md index 1736431..962b762 100644 --- a/README.md +++ b/README.md @@ -283,27 +283,26 @@ FlixelGDX includes a built-in tweening system inspired by Flixel/HaxeFlixel that - **Reducing boilerplate compared to Universal Tween Engine (UTE)**, which typically requires writing a `TweenAccessor` for every type you want to animate. - **Providing both beginner-friendly defaults and power features** that experienced users expect (easing, delays, callbacks, looping), without forcing you into reflection-heavy or brittle APIs. -At the core is `FlixelTween` plus a settings object `FlixelTweenSettings`. For property-based tweens, `FlixelPropertyTween` lets you supply getters and setters directly, so you can tween real Java properties with side effects instead of raw fields. +At the core is `FlixelTween` and a fluent builder API. You call `FlixelTween.tween(tweenType, builderType)` with the tween class and its builder class; the returned builder lets you chain options and then call `.start()` to run the tween. Three built-in variants are available: + +- **Var tweens**: `FlixelVarTween` / `FlixelVarTweenBuilder`: tween a single object and optional completion callback (e.g. `setObject(sprite).setCallback(...)`). +- **Property tweens**: `FlixelPropertyTween` / `FlixelPropertyTweenBuilder`: supply getters and setters so you can tween real Java properties with side effects. +- **Num tweens**: `FlixelNumTween` / `FlixelNumTweenBuilder`: tween a numeric range with `from(...).to(...)` and optional callback. + +Example: tween the player's X and Y using the property builder: ```java FlixelSprite player = new FlixelSprite() .makeGraphic(16, 16, Color.WHITE); -// Tween the player's X and Y using getters/setters. -FlixelTween.tween( - new FlixelTweenSettings() - .setDuration(0.5f) - .setEase(FlixelEase::quadOut) - .addGoal(player::getX, 400f, player::setX) - .addGoal(player::getY, 200f, player::setY) -); +FlixelTween.tween(FlixelPropertyTween.class, FlixelPropertyTweenBuilder.class) + .setDuration(0.5f) + .setEase(FlixelEase::quadOut) + .addGoal(player::getX, 400f, player::setX) + .addGoal(player::getY, 200f, player::setY) + .start(); ``` -This pattern is familiar to HaxeFlixel users (property-style tweens) while being very approachable for beginners: - -- **Beginners** just pass method references (`player::getX`, `player::setX`) and a target value. -- **Experienced users** can configure easing, durations, delays, callbacks, and loop behavior through `FlixelTweenSettings`, or drop down to lower-level types like `FlixelVarTween` if they want reflection-based tweens. - Compared to Universal Tween Engine's `TweenAccessor` pattern, you do not need to: - Implement a custom accessor interface per type. @@ -327,11 +326,10 @@ public class PlayState extends FlixelState { add(player); // Fade the player in over 1 second (alpha: 0 -> 1). - FlixelTween.tween( - new FlixelTweenSettings() - .setDuration(1.0f) - .addGoal(() -> player.getColor().a, 1.0f, player::setAlpha) - ); + FlixelTween.tween(FlixelPropertyTween.class, FlixelPropertyTweenBuilder.class) + .setDuration(1.0f) + .addGoal(() -> player.getColor().a, 1.0f, player::setAlpha) + .start(); } } ``` @@ -350,12 +348,11 @@ public class MyLibGdxScreen implements Screen { public void show() { player.makeGraphic(16, 16, Color.WHITE); - FlixelTween.tween( - new FlixelTweenSettings() - .setDuration(0.75f) - .setEase(FlixelEase::sineInOut) - .addGoal(player::getScaleX, 2.0f, value -> player.setScale(value, value)) - ); + FlixelTween.tween(FlixelPropertyTween.class, FlixelPropertyTweenBuilder.class) + .setDuration(0.75f) + .setEase(FlixelEase::sineInOut) + .addGoal(player::getScaleX, 2.0f, value -> player.setScale(value, value)) + .start(); } @Override 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 index 3e03473..c724904 100644 --- a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTween.java +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTween.java @@ -1,6 +1,8 @@ package me.stringdotjar.flixelgdx.tween; import com.badlogic.gdx.utils.Pool; +import me.stringdotjar.flixelgdx.tween.builders.FlixelAbstractTweenBuilder; +import me.stringdotjar.flixelgdx.tween.builders.FlixelPropertyTweenBuilder; import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings; import me.stringdotjar.flixelgdx.tween.type.FlixelNumTween; import me.stringdotjar.flixelgdx.tween.type.FlixelPropertyTween; @@ -61,7 +63,44 @@ protected FlixelTween(FlixelTweenSettings tweenSettings) { } /** - * Creates a new reflection-based tween with the provided settings and starts it in the global tween manager. + * Returns a fluent builder for the given tween type. Pass both the tween class and its builder + * class so the return type is the concrete builder ({@code B}), giving full IDE support for + * type-specific methods ({@code addGoal}, {@code from}, {@code to}, etc.) and common ones + * ({@code setDuration}, {@code setEase}), then {@link FlixelAbstractTweenBuilder#start()}. + * + *

Example (property): + *

{@code
+   * FlixelPropertyTween tween = FlixelTween.tween(FlixelPropertyTween.class, FlixelPropertyTweenBuilder.class)
+   *   .addGoal(sprite::getX, 100f, sprite::setX)
+   *   .setDuration(1f)
+   *   .start();
+   * }
+ * + *

Example (num): + *

{@code
+   * FlixelNumTween tween = FlixelTween.tween(FlixelNumTween.class, FlixelNumTweenBuilder.class)
+   *   .from(0f)
+   *   .to(1f)
+   *   .setCallback(v -> {})
+   *   .setDuration(1f)
+   *   .start();
+   * }
+ * + * @param tweenType The tween class (e.g. {@link FlixelPropertyTween}.class). + * @param builderType The corresponding builder class (e.g. {@link FlixelPropertyTweenBuilder}.class). + * @return A new builder instance of type {@code B} for chaining. + */ + public static > B tween(Class tweenType, Class builderType) { + try { + return builderType.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalArgumentException("Could not instantiate builder " + builderType.getName() + ". It must have a no-arg constructor.", e); + } + } + + /** + * Creates a new reflection-based tween with the provided settings and adds it to the global tween manager + * (which starts it automatically). Shorthand for create, add and start, matching HaxeFlixel's FlxTween.tween. * * @param object The object to tween its values. * @param tweenSettings The settings that configure and determine how the tween should animate. @@ -69,25 +108,23 @@ protected FlixelTween(FlixelTweenSettings tweenSettings) { * @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(); + return globalManager.addTween(new FlixelVarTween(object, tweenSettings, updateCallback)); } /** - * Creates a new property-based tween with the provided settings and starts it in the global tween manager. + * Creates a new property-based tween with the provided settings and adds it to the global tween manager + * (which starts it automatically). Shorthand for create, add and start, matching HaxeFlixel's FlxTween.tween. * * @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(); + return globalManager.addTween(new FlixelPropertyTween(tweenSettings)); } /** - * Creates a new numerical tween with the provided settings and starts it in the global tween manager. + * Creates a new numerical tween with the provided settings and adds it to the global tween manager + * (which starts it automatically). Shorthand for create, add and start, matching HaxeFlixel's FlxTween.num. * * @param from The starting floating point value. * @param to The ending floating point value. @@ -96,9 +133,7 @@ public static FlixelTween tween(FlixelTweenSettings tweenSettings) { * @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(); + return globalManager.addTween(new FlixelNumTween(from, to, tweenSettings, updateCallback)); } /** 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 index 1c7f0b8..d2838f7 100644 --- a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTweenManager.java +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/FlixelTweenManager.java @@ -3,7 +3,13 @@ import com.badlogic.gdx.utils.Pool; import com.badlogic.gdx.utils.SnapshotArray; -/** Manager class for handling a list of active {@link FlixelTween}s. */ +/** + * Manager class for handling a list of active {@link FlixelTween}s. + * + *

Mirrors FlxTweenManager: + * normally used via {@link FlixelTween#getGlobalManager()} rather than instantiating separately. + * Adding a tween via {@link #addTween(FlixelTween)} automatically starts it. + */ public class FlixelTweenManager { /** Array where all current active tweens are stored. */ @@ -17,6 +23,18 @@ protected FlixelTween newObject() { } }; + /** + * Adds the tween to this manager and starts it immediately. + * + * @param tween The tween to add and start. + * @return The same tween for chaining. + */ + public FlixelTween addTween(FlixelTween tween) { + tween.setManager(this); + tween.start(); + return tween; + } + /** * Updates all active tweens that are stored and updated in {@code this} manager. * diff --git a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelAbstractTweenBuilder.java b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelAbstractTweenBuilder.java new file mode 100644 index 0000000..b78a176 --- /dev/null +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelAbstractTweenBuilder.java @@ -0,0 +1,94 @@ +package me.stringdotjar.flixelgdx.tween.builders; + +import me.stringdotjar.flixelgdx.tween.FlixelEase; +import me.stringdotjar.flixelgdx.tween.FlixelTween; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenType; +import org.jetbrains.annotations.Nullable; + +/** + * Base for fluent tween builders using the recursive generic pattern (CRTP). Holds common + * configuration (duration, ease, type, delays, callbacks) and applies it to a + * {@link FlixelTweenSettings} instance. Use {@link FlixelTween#tween(Class, Class)} with the + * concrete builder class so the return type has the correct type-specific methods. + * + * @param The tween type (e.g. {@link me.stringdotjar.flixelgdx.tween.type.FlixelPropertyTween}). + * @param The concrete builder type (e.g. {@link FlixelPropertyTweenBuilder}), for fluent return types. + */ +public abstract class FlixelAbstractTweenBuilder> implements FlixelTweenBuilder { + + protected float duration = 1f; + protected FlixelTweenType type = FlixelTweenType.ONESHOT; + protected FlixelEase.FunkinEaseFunction ease = FlixelEase::linear; + protected float startDelay; + protected float loopDelay; + protected float framerate; + protected FlixelEase.FunkinEaseStartCallback onStart; + protected FlixelEase.FunkinEaseUpdateCallback onUpdate; + protected FlixelEase.FunkinEaseCompleteCallback onComplete; + + /** + * Returns {@code this} as the concrete builder type for fluent chaining. + */ + protected abstract B self(); + + /** + * Applies the current common configuration to the given settings instance. + */ + protected void applyTo(FlixelTweenSettings settings) { + settings.setDuration(duration); + settings.setType(type); + settings.setEase(ease); + settings.setStartDelay(startDelay); + settings.setLoopDelay(loopDelay); + settings.setFramerate(framerate); + settings.setOnStart(onStart); + settings.setOnUpdate(onUpdate); + settings.setOnComplete(onComplete); + } + + public B setDuration(float duration) { + this.duration = duration; + return self(); + } + + public B setType(FlixelTweenType type) { + this.type = type; + return self(); + } + + public B setEase(FlixelEase.FunkinEaseFunction ease) { + this.ease = ease; + return self(); + } + + public B setStartDelay(float startDelay) { + this.startDelay = startDelay; + return self(); + } + + public B setLoopDelay(float loopDelay) { + this.loopDelay = loopDelay; + return self(); + } + + public B setFramerate(float framerate) { + this.framerate = framerate; + return self(); + } + + public B setOnStart(@Nullable FlixelEase.FunkinEaseStartCallback onStart) { + this.onStart = onStart; + return self(); + } + + public B setOnUpdate(@Nullable FlixelEase.FunkinEaseUpdateCallback onUpdate) { + this.onUpdate = onUpdate; + return self(); + } + + public B setOnComplete(@Nullable FlixelEase.FunkinEaseCompleteCallback onComplete) { + this.onComplete = onComplete; + return self(); + } +} diff --git a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelNumTweenBuilder.java b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelNumTweenBuilder.java new file mode 100644 index 0000000..cea9694 --- /dev/null +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelNumTweenBuilder.java @@ -0,0 +1,59 @@ +package me.stringdotjar.flixelgdx.tween.builders; + +import me.stringdotjar.flixelgdx.tween.FlixelTween; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings; +import me.stringdotjar.flixelgdx.tween.type.FlixelNumTween; +import org.jetbrains.annotations.Nullable; + +/** + * Fluent builder for {@link FlixelNumTween}. Requires {@link #from(float)}, {@link #to(float)}, + * and {@link #setCallback}. {@link #start()} throws if any of these are missing. + */ +public final class FlixelNumTweenBuilder extends FlixelAbstractTweenBuilder { + + private static final float UNSET = Float.NaN; + + private float from = UNSET; + private float to = UNSET; + private FlixelNumTween.FlixelNumTweenUpdateCallback callback; + + /** Creates a new num tween builder. Use {@link FlixelTween#tween(Class, Class) FlixelTween.tween(FlixelNumTween.class, FlixelNumTweenBuilder.class)}. */ + public FlixelNumTweenBuilder() {} + + @Override + protected FlixelNumTweenBuilder self() { + return this; + } + + public FlixelNumTweenBuilder from(float from) { + this.from = from; + return this; + } + + public FlixelNumTweenBuilder to(float to) { + this.to = to; + return this; + } + + public FlixelNumTweenBuilder setCallback(@Nullable FlixelNumTween.FlixelNumTweenUpdateCallback callback) { + this.callback = callback; + return this; + } + + @Override + public FlixelNumTween start() { + if (Float.isNaN(from)) { + throw new IllegalStateException("FlixelNumTween requires from(float) before start()"); + } + if (Float.isNaN(to)) { + throw new IllegalStateException("FlixelNumTween requires to(float) before start()"); + } + if (callback == null) { + throw new IllegalStateException("FlixelNumTween requires setCallback(callback) before start()"); + } + FlixelTweenSettings settings = new FlixelTweenSettings(type, ease); + applyTo(settings); + FlixelNumTween tween = new FlixelNumTween(from, to, settings, callback); + return (FlixelNumTween) FlixelTween.getGlobalManager().addTween(tween); + } +} diff --git a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelPropertyTweenBuilder.java b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelPropertyTweenBuilder.java new file mode 100644 index 0000000..8843619 --- /dev/null +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelPropertyTweenBuilder.java @@ -0,0 +1,45 @@ +package me.stringdotjar.flixelgdx.tween.builders; + +import com.badlogic.gdx.utils.Array; +import me.stringdotjar.flixelgdx.tween.FlixelTween; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings.FlixelTweenPropertyGoal; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings.FlixelTweenPropertyGoal.FlixelTweenPropertyFloatGetter; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings.FlixelTweenPropertyGoal.FlixelTweenPropertyFloatSetter; +import me.stringdotjar.flixelgdx.tween.type.FlixelPropertyTween; + +import org.jetbrains.annotations.NotNull; + +/** + * Fluent builder for {@link FlixelPropertyTween}. Use getter/setter goals via {@link #addGoal}. + * Chain ends with {@link #start()}. + */ +public final class FlixelPropertyTweenBuilder extends FlixelAbstractTweenBuilder { + + private final Array propertyGoals = new Array<>(); + + /** Creates a new property tween builder. Use {@link FlixelTween#tween(Class, Class) FlixelTween.tween(FlixelPropertyTween.class, FlixelPropertyTweenBuilder.class)}. */ + public FlixelPropertyTweenBuilder() {} + + @Override + protected FlixelPropertyTweenBuilder self() { + return this; + } + + public FlixelPropertyTweenBuilder addGoal(@NotNull FlixelTweenPropertyFloatGetter getter, float toValue, @NotNull FlixelTweenPropertyFloatSetter setter) { + propertyGoals.add(new FlixelTweenPropertyGoal(getter, toValue, setter)); + return this; + } + + @Override + public FlixelPropertyTween start() { + FlixelTweenSettings settings = new FlixelTweenSettings(type, ease); + applyTo(settings); + for (int i = 0; i < propertyGoals.size; i++) { + var goal = propertyGoals.get(i); + settings.addGoal(goal.getter(), goal.toValue(), goal.setter()); + } + FlixelPropertyTween tween = new FlixelPropertyTween(settings); + return (FlixelPropertyTween) FlixelTween.getGlobalManager().addTween(tween); + } +} diff --git a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelTweenBuilder.java b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelTweenBuilder.java new file mode 100644 index 0000000..c398d16 --- /dev/null +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelTweenBuilder.java @@ -0,0 +1,21 @@ +package me.stringdotjar.flixelgdx.tween.builders; + +import me.stringdotjar.flixelgdx.tween.FlixelTween; + +/** + * Fluent builder for creating and starting a {@link FlixelTween} of a specific type. + * Configuration methods return the builder for chaining; the chain ends with {@link #start()}, + * which creates the tween, adds it to a {@link FlixelTweenManager}, starts it, and returns the concrete tween instance. + * + * @param The concrete tween type (e.g. {@link me.stringdotjar.flixelgdx.tween.type.FlixelPropertyTween}). + */ +public interface FlixelTweenBuilder { + + /** + * Builds the tween from the current configuration, adds it to the global tween manager, + * starts it, and returns the started tween. + * + * @return The started tween instance. + */ + T start(); +} diff --git a/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelVarTweenBuilder.java b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelVarTweenBuilder.java new file mode 100644 index 0000000..d8d8da9 --- /dev/null +++ b/flixelgdx-core/src/main/java/me/stringdotjar/flixelgdx/tween/builders/FlixelVarTweenBuilder.java @@ -0,0 +1,62 @@ +package me.stringdotjar.flixelgdx.tween.builders; + +import com.badlogic.gdx.utils.Array; +import me.stringdotjar.flixelgdx.tween.FlixelTween; +import me.stringdotjar.flixelgdx.tween.settings.FlixelTweenSettings; +import me.stringdotjar.flixelgdx.tween.type.FlixelVarTween; +import org.jetbrains.annotations.NotNull; + +/** + * Fluent builder for {@link FlixelVarTween} (reflection-based). Requires {@link #setObject(Object)}, + * at least one {@link #addGoal(String, float)}, and {@link #setCallback}. Chain ends with {@link #start()}. + */ +public final class FlixelVarTweenBuilder extends FlixelAbstractTweenBuilder { + + private final Array goals = new Array<>(); + private Object object; + private FlixelVarTween.FunkinVarTweenUpdateCallback callback; + + /** Creates a new var tween builder. Use {@link FlixelTween#tween(Class, Class) FlixelTween.tween(FlixelVarTween.class, FlixelVarTweenBuilder.class)}. */ + public FlixelVarTweenBuilder() {} + + @Override + protected FlixelVarTweenBuilder self() { + return this; + } + + public FlixelVarTweenBuilder setObject(@NotNull Object object) { + this.object = object; + return this; + } + + public FlixelVarTweenBuilder addGoal(@NotNull String field, float value) { + goals.add(new FlixelTweenSettings.FlixelTweenVarGoal(field, value)); + return this; + } + + public FlixelVarTweenBuilder setCallback(@NotNull FlixelVarTween.FunkinVarTweenUpdateCallback callback) { + this.callback = callback; + return this; + } + + @Override + public FlixelVarTween start() { + if (object == null) { + throw new IllegalStateException("FlixelVarTween requires setObject(object) before start()"); + } + if (callback == null) { + throw new IllegalStateException("FlixelVarTween requires setCallback(callback) before start()"); + } + if (goals.isEmpty()) { + throw new IllegalStateException("FlixelVarTween requires at least one addGoal(field, value) before start()"); + } + FlixelTweenSettings settings = new FlixelTweenSettings(type, ease); + applyTo(settings); + for (int i = 0; i < goals.size; i++) { + var goal = goals.get(i); + settings.addGoal(goal.field(), goal.value()); + } + FlixelVarTween tween = new FlixelVarTween(object, settings, callback); + return (FlixelVarTween) FlixelTween.getGlobalManager().addTween(tween); + } +} diff --git a/flixelgdx-core/src/main/java/module-info.java b/flixelgdx-core/src/main/java/module-info.java index d47632e..c66ffa0 100644 --- a/flixelgdx-core/src/main/java/module-info.java +++ b/flixelgdx-core/src/main/java/module-info.java @@ -10,6 +10,7 @@ exports me.stringdotjar.flixelgdx.logging; exports me.stringdotjar.flixelgdx.signal; exports me.stringdotjar.flixelgdx.tween; + exports me.stringdotjar.flixelgdx.tween.builders; exports me.stringdotjar.flixelgdx.tween.settings; exports me.stringdotjar.flixelgdx.tween.type; exports me.stringdotjar.flixelgdx.util;