2026-02-07 18:54:19 +01:00
/ * Author : Maple
* Jan . 23 2026
* * /
package org.openautonomousconnection.oacswing.animated ;
import javax.swing.* ;
import java.util.concurrent.atomic.AtomicInteger ;
2026-02-09 22:15:18 +01:00
// 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()")
2026-02-07 18:54:19 +01:00
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 ) ;
2026-02-09 22:15:18 +01:00
//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 ) {
2026-02-07 18:54:19 +01:00
AtomicInteger ticksPassed = new AtomicInteger ( ) ;
2026-02-08 22:31:29 +01:00
// cloning the animation path to not mess with the original,
// if an extra frame is to be added because loop is set to true
2026-02-07 18:54:19 +01:00
2026-02-08 22:31:29 +01:00
AnimationPath playedPath = this . getAnimationPath ( ) . clone ( ) ;
if ( loop )
playedPath . add ( playedPath . getNext ( ) ) ;
2026-02-07 18:54:19 +01:00
2026-02-08 22:31:29 +01:00
this . setCurrentRun ( new Timer ( 0 , e - > {
if ( ! playedPath . anyMore ( ) ) {
if ( loop )
playedPath . reset ( ) ;
2026-02-07 18:54:19 +01:00
else
( ( Timer ) e . getSource ( ) ) . stop ( ) ;
return ;
}
2026-02-08 22:31:29 +01:00
if ( ticksPassed . get ( ) * speed / ( 100 ) < 1 ) {
ticksPassed . addAndGet ( playedPath . getInbetweens ( ) ) ;
return ;
}
KeyFrame next = playedPath . getNext ( ) ;
2026-02-07 18:54:19 +01:00
this . setBounds ( next . position ( ) . x , next . position ( ) . y , next . width ( ) , next . height ( ) ) ;
ticksPassed . set ( 0 ) ;
} ) ) ;
this . getCurrentRun ( ) . start ( ) ;
}
2026-02-09 22:15:18 +01:00
/ * *
* 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
* /
2026-02-07 18:54:19 +01:00
default void play ( double speed ) {
this . play ( speed , false ) ;
}
2026-02-09 22:15:18 +01:00
/ * *
* Plays this object ' s animation path
* /
2026-02-07 18:54:19 +01:00
default void play ( ) {
this . play ( 1 , false ) ;
}
2026-02-09 22:15:18 +01:00
/ * *
* Stops and resets replay of this object ' s animation path
* /
2026-02-07 18:54:19 +01:00
default void stop ( ) {
if ( this . getCurrentRun ( ) ! = null )
if ( this . getCurrentRun ( ) . isRunning ( ) )
this . getCurrentRun ( ) . stop ( ) ;
this . getAnimationPath ( ) . reset ( ) ;
}
}