/* Author: Maple * Jan. 23 2026 * */ package org.openautonomousconnection.oacswing.animated; import javax.swing.*; import java.util.concurrent.atomic.AtomicInteger; // TODO: Implement pause functionality // (preferably not interfering with play() always reliably playing the animation from the start; aka define it as "setPaused(bool)" or "pause()" and "unpause()") public interface AnimatedComponent { void setCurrentRun(Timer timer); Timer getCurrentRun(); void setAnimationPath(AnimationPath animationPath); AnimationPath getAnimationPath(); void setBounds(int x, int y, int width, int height); //TODO: implement momentum /** * Plays this object's animation path * @param speed how fast the animation should play * @param loop if should the animation should loop * @param momentum basically how far an object "shoots off" from a specified keyframe when stopping at proportional speed * (linear keyframes are excluded from this) */ default void play(double speed, boolean loop, double momentum) { AtomicInteger ticksPassed = new AtomicInteger(); // cloning the animation path to not mess with the original, // if an extra frame is to be added because loop is set to true AnimationPath playedPath = this.getAnimationPath().clone(); if(loop) playedPath.add(playedPath.getNext()); this.setCurrentRun(new Timer(0, e -> { if (!playedPath.anyMore()) { if (loop) playedPath.reset(); else ((Timer) e.getSource()).stop(); return; } if(ticksPassed.get() * speed / (100) < 1) { ticksPassed.addAndGet(playedPath.getInbetweens()); return; } KeyFrame next = playedPath.getNext(); this.setBounds(next.position().x, next.position().y, next.width(), next.height()); ticksPassed.set(0); })); this.getCurrentRun().start(); } /** * Plays this object's animation path * @param speed how fast the animation should play * @param loop if should the animation should loop */ default void play(double speed, boolean loop) { this.play(speed, loop, 0); } /** * Plays this object's animation path * @param speed how fast the animation should play */ default void play(double speed) { this.play(speed, false); } /** * Plays this object's animation path */ default void play() { this.play(1, false); } /** * Stops and resets replay of this object's animation path */ default void stop() { if(this.getCurrentRun() != null) if(this.getCurrentRun().isRunning()) this.getCurrentRun().stop(); this.getAnimationPath().reset(); } }