/* Author: Maple * Jan. 23 2026 * */ package org.openautonomousconnection.oacswing.animated; import javax.swing.*; import java.util.concurrent.atomic.AtomicInteger; 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); default void play(double speed, boolean loop) { 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()) { System.out.println("called"); if (loop) playedPath.reset(); else ((Timer) e.getSource()).stop(); return; } if(ticksPassed.get() * speed / (100) < 1) { ticksPassed.addAndGet(playedPath.getInbetweens()); return; } System.out.println("still executing"); KeyFrame next = playedPath.getNext(); this.setBounds(next.position().x, next.position().y, next.width(), next.height()); ticksPassed.set(0); })); this.getCurrentRun().start(); } default void play(double speed) { this.play(speed, false); } default void play() { this.play(1, false); } default void stop() { if(this.getCurrentRun() != null) if(this.getCurrentRun().isRunning()) this.getCurrentRun().stop(); this.getAnimationPath().reset(); } }