diff --git a/.gitignore b/.gitignore
index d100851..159c8cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,7 @@ www-test/
## NetBeans:
+
/nbproject/private/
/android/nbproject/private/
/core/nbproject/private/
@@ -144,7 +145,7 @@ nbactions.xml
nb-configuration.xml
# VS Code
-/.vscode
+.vscode/
## OS-Specific:
.DS_Store
diff --git a/core/build.gradle b/core/build.gradle
index 9055240..ce9e3bf 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -10,6 +10,7 @@ dependencies {
api "org.mini2Dx:universal-tween-engine:$universalTweenVersion"
implementation "org.luaj:luaj-jse:3.0.1"
+ implementation 'org.jetbrains:annotations:15.0'
if(enableGraalNative == 'true') {
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
diff --git a/core/src/main/java/me/stringfromjava/funkin/game/menus/TitleScreen.java b/core/src/main/java/me/stringfromjava/funkin/game/menus/TitleScreen.java
index c2dd06b..f82a76b 100644
--- a/core/src/main/java/me/stringfromjava/funkin/game/menus/TitleScreen.java
+++ b/core/src/main/java/me/stringfromjava/funkin/game/menus/TitleScreen.java
@@ -16,7 +16,7 @@ public class TitleScreen extends FunkinScreen {
@Override
public void show() {
super.show();
- tickleFight = Funkin.playSound("shared/sounds/tickleFight.ogg");
+ tickleFight = new FunkinSound("shared/sounds/tickleFight.ogg");
Funkin.playMusic("preload/music/freakyMenu/freakyMenu.ogg", 0.5f);
}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTween.java b/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTween.java
index d2dea11..05dd7d6 100644
--- a/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTween.java
+++ b/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTween.java
@@ -1,10 +1,60 @@
package me.stringfromjava.funkin.tween;
+import me.stringfromjava.funkin.tween.settings.FunkinTweenSettings;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
/**
- * Core manager class for creating new tweens.
+ * Core class for creating new tweens to add nice and smooth animations to visual objects.
+ *
+ * Note that this doesn't have to be used on sprites, it can be used on just about anything!
*/
-public final class FunkinTween {
+public class FunkinTween {
+
+ /**
+ * The global tween manager for the entire game.
+ */
+ public static FunkinTweenManager globalManager = new FunkinTweenManager();
+
+ /**
+ * The object to tween.
+ */
+ protected Object object;
+
+ /**
+ * The settings used for how the tween is handled and calculated (aka how it looks and animates).
+ */
+ protected FunkinTweenSettings tweenSettings;
+
+ private final ArrayList cachedFields;
+
+ /**
+ * @param object The object to tween values.
+ * @param settings The settings that configure and determine how the tween should animate and last for.
+ */
+ public FunkinTween(Object object, FunkinTweenSettings settings) {
+ this.tweenSettings = settings;
+ this.cachedFields = new ArrayList<>();
+
+ Field[] allFields = object.getClass().getFields();
+ var neededFields = settings.getGoalFields();
+
+ // Due to how costly it is using Java reflect, we cache the fields we need
+ // before we actually do the real tweening functionality. This is so it
+ // doesn't cause lag while multiple tweens are being active.
+ for (Field field : allFields) {
+ String fName = field.getName();
+
+ if (!field.trySetAccessible() && !neededFields.contains(fName)) {
+ continue;
+ }
+
+ cachedFields.add(field);
+ }
+ }
- private FunkinTween() {
+ public FunkinTweenSettings getTweenSettings() {
+ return tweenSettings;
}
}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTweenManager.java b/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTweenManager.java
new file mode 100644
index 0000000..ccc99b6
--- /dev/null
+++ b/core/src/main/java/me/stringfromjava/funkin/tween/FunkinTweenManager.java
@@ -0,0 +1,18 @@
+package me.stringfromjava.funkin.tween;
+
+import java.util.ArrayList;
+
+/**
+ * Core manager class for handling all {@link FunkinTween}s that are currently active.
+ */
+public final class FunkinTweenManager {
+
+ /**
+ * A list where all current active tweens are stored.
+ */
+ public final ArrayList activeTweens = new ArrayList<>();
+
+ public void update(float delta) {
+ // TODO: Iterate through every active tween and update them!
+ }
+}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/accessors/SpriteAccessor.java b/core/src/main/java/me/stringfromjava/funkin/tween/accessors/SpriteAccessor.java
deleted file mode 100644
index 643e664..0000000
--- a/core/src/main/java/me/stringfromjava/funkin/tween/accessors/SpriteAccessor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package me.stringfromjava.funkin.tween.accessors;
-
-import aurelienribon.tweenengine.TweenAccessor;
-import com.badlogic.gdx.graphics.g2d.Sprite;
-
-/**
- * Tween accessor for {@link Sprite} objects.
- */
-public class SpriteAccessor implements TweenAccessor {
-
- public static final int X = 1;
- public static final int Y = 2;
- public static final int XY = 3;
- public static final int ALPHA = 4;
-
- @Override
- public int getValues(Sprite target, int tweenType, float[] returnValues) {
- switch (tweenType) {
- case X:
- returnValues[0] = target.getX();
- return 1;
- case Y:
- returnValues[0] = target.getY();
- return 1;
- case XY:
- returnValues[0] = target.getX();
- returnValues[1] = target.getY();
- return 2;
- case ALPHA:
- returnValues[0] = target.getColor().a;
- return 1;
- default:
- assert false;
- return -1;
- }
- }
-
- @Override
- public void setValues(Sprite target, int tweenType, float[] newValues) {
- switch (tweenType) {
- case X -> target.setX(newValues[0]);
- case Y -> target.setY(newValues[0]);
- case XY -> {
- target.setX(newValues[0]);
- target.setY(newValues[1]);
- }
- case ALPHA -> target.setColor(target.getColor().r, target.getColor().g, target.getColor().b, newValues[0]);
- default -> {
- assert false;
- }
- }
- }
-}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenEase.java b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenEase.java
new file mode 100644
index 0000000..3f416ed
--- /dev/null
+++ b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenEase.java
@@ -0,0 +1,210 @@
+package me.stringfromjava.funkin.tween.settings;
+
+import me.stringfromjava.funkin.tween.FunkinTween;
+
+/**
+ * Class where all easer functions are stored, mostly used for tweening.
+ */
+public final class FunkinTweenEase {
+
+ // 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 FunkinTweenEase() {
+ }
+
+ 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 FunkinTweenEaseFunction {
+ float compute(float t);
+ }
+
+ @FunctionalInterface
+ public interface FunkinTweenEaseStartCallback {
+ void run(FunkinTween tween);
+ }
+
+ @FunctionalInterface
+ public interface FunkinTweenEaseUpdateCallback {
+ void run(FunkinTween tween);
+ }
+
+ @FunctionalInterface
+ public interface FunkinTweenEaseCompleteCallback {
+ void run(FunkinTween tween);
+ }
+}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenSettings.java b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenSettings.java
new file mode 100644
index 0000000..4297a1f
--- /dev/null
+++ b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenSettings.java
@@ -0,0 +1,149 @@
+package me.stringfromjava.funkin.tween.settings;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+/**
+ * Class for holding basic data, containing configurations to be used on a {@link me.stringfromjava.funkin.tween.FunkinTween}.
+ */
+public class FunkinTweenSettings {
+
+ private float duration;
+ private FunkinTweenType type;
+ private FunkinTweenEase.FunkinTweenEaseFunction ease;
+ private FunkinTweenEase.FunkinTweenEaseStartCallback onStart;
+ private FunkinTweenEase.FunkinTweenEaseUpdateCallback onUpdate;
+ private FunkinTweenEase.FunkinTweenEaseCompleteCallback onComplete;
+ private ArrayList goals;
+
+ /**
+ * @param type The type of tween it should be.
+ */
+ public FunkinTweenSettings(@NotNull FunkinTweenType type) {
+ this(type, null, null, null, null);
+ }
+
+ /**
+ * @param type The type of tween it should be.
+ * @param ease The easer function the tween should use (aka how it should be animated).
+ */
+ public FunkinTweenSettings(@NotNull FunkinTweenType type, @Nullable FunkinTweenEase.FunkinTweenEaseFunction ease) {
+ this(type, ease, null, null, null);
+ }
+
+ /**
+ * @param type The type of tween it should be.
+ * @param ease The easer function the tween should use (aka how it should be animated).
+ * @param onStart Callback for when the tween starts.
+ */
+ public FunkinTweenSettings(@NotNull FunkinTweenType type, @Nullable FunkinTweenEase.FunkinTweenEaseFunction ease, @Nullable FunkinTweenEase.FunkinTweenEaseStartCallback onStart) {
+ this(type, ease, onStart, null, null);
+ }
+
+ /**
+ * @param type The type of tween it should be.
+ * @param ease The easer function the tween should use (aka how it should be animated).
+ * @param onStart Callback for when the tween starts.
+ * @param onUpdate Callback for when the tween updates.
+ */
+ public FunkinTweenSettings(@NotNull FunkinTweenType type, @Nullable FunkinTweenEase.FunkinTweenEaseFunction ease, @Nullable FunkinTweenEase.FunkinTweenEaseStartCallback onStart, @Nullable FunkinTweenEase.FunkinTweenEaseUpdateCallback onUpdate) {
+ this(type, ease, onStart, onUpdate, null);
+ }
+
+ /**
+ * @param type The type of tween it should be.
+ * @param ease The easer function the tween should use (aka how it should be animated).
+ * @param onStart Callback for when the tween starts.
+ * @param onUpdate Callback for when the tween updates.
+ * @param onComplete Callback for when the tween has been completed.
+ */
+ public FunkinTweenSettings(@NotNull FunkinTweenType type, @Nullable FunkinTweenEase.FunkinTweenEaseFunction ease, @Nullable FunkinTweenEase.FunkinTweenEaseStartCallback onStart, @Nullable FunkinTweenEase.FunkinTweenEaseUpdateCallback onUpdate, @Nullable FunkinTweenEase.FunkinTweenEaseCompleteCallback onComplete) {
+ this.duration = 1.0f;
+ this.type = type;
+ this.ease = ease;
+ this.onStart = onStart;
+ this.onUpdate = onUpdate;
+ this.onComplete = onComplete;
+ this.goals = new ArrayList<>();
+ }
+
+ /**
+ * Adds a new goal to tween an objects value to.
+ *
+ * @param field The field to tween.
+ * @param value The value to tween the field to.
+ * @return {@code this} tween settings object for chaining.
+ */
+ public FunkinTweenSettings addGoal(String field, float value) {
+ goals.add(new FunkinTweenGoal(field, value));
+ 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 FunkinTweenSettings setDuration(float duration) {
+ this.duration = duration;
+ return this;
+ }
+
+ public float getDuration() {
+ return duration;
+ }
+
+ public FunkinTweenType getType() {
+ return type;
+ }
+
+ public FunkinTweenEase.FunkinTweenEaseFunction getEase() {
+ return ease;
+ }
+
+ public FunkinTweenEase.FunkinTweenEaseStartCallback getOnStart() {
+ return onStart;
+ }
+
+ public FunkinTweenEase.FunkinTweenEaseUpdateCallback getOnUpdate() {
+ return onUpdate;
+ }
+
+ public FunkinTweenEase.FunkinTweenEaseCompleteCallback getOnComplete() {
+ return onComplete;
+ }
+
+ public ArrayList getGoals() {
+ return new ArrayList<>(goals);
+ }
+
+ public Collection getGoalFields() {
+ return goals.stream()
+ .map(FunkinTweenGoal::field)
+ .collect(Collectors.toList());
+ }
+
+ public Collection getGoalValues() {
+ return goals.stream()
+ .map(FunkinTweenGoal::value)
+ .collect(Collectors.toList());
+ }
+
+ public void clearGoals() {
+ goals.clear();
+ }
+
+ /**
+ * A record containing basic info for a tween goal (aka a field to tween a numeric value to).
+ *
+ * @param field The field to tween.
+ * @param value The value to tween the field to.
+ */
+ public record FunkinTweenGoal(@NotNull String field, float value) {
+ }
+}
diff --git a/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenType.java b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenType.java
new file mode 100644
index 0000000..35243ac
--- /dev/null
+++ b/core/src/main/java/me/stringfromjava/funkin/tween/settings/FunkinTweenType.java
@@ -0,0 +1,32 @@
+package me.stringfromjava.funkin.tween.settings;
+
+/**
+ * Enum containing all different tween types that can determine
+ */
+public enum FunkinTweenType {
+
+ /**
+ * Will stop and remove itself from the manager when it finishes.
+ */
+ ONESHOT,
+
+ /**
+ * Will stop when it finishes but remain in the manager.
+ */
+ PERSIST,
+
+ /**
+ * Will play tween in reverse direction
+ */
+ BACKWARD,
+
+ /**
+ * Will restart immediately when it finishes.
+ */
+ LOOPING,
+
+ /**
+ * "To and from", will play tween hither and thither. Also loops indefinitely.
+ */
+ PINGPONG;
+}