package coffee.liz.ecs.animation import coffee.liz.ecs.Component import coffee.liz.ecs.Rect import kotlin.jvm.JvmInline /** * Loop modes for animation playback. */ enum class LoopMode { /** Play once **/ ONCE, /** Repeat **/ LOOP, /** Play forward, then backward, repeat **/ PING_PONG } /** * Name of an animation clip. */ @JvmInline value class AnimationName(val value: String) /** * Name of a frame. */ @JvmInline value class FrameName(val value: String) /** * Animation Clip details. */ data class AnimationClip( val frameNames: List, val frameTicks: Int, val loopMode: LoopMode = LoopMode.LOOP ) /** * Component containing sprite sheet data - the image and frame definitions. */ data class SpriteSheet( val imagePath: String, val frames: Map ) : Component enum class AnimationDirection(val step: Int) { /** Play in forward direction **/ FORWARD(step = 1), /** Play in reverse direction **/ BACKWARD(step = -1); } /** * Current state of an animation. */ data class Animator( val clips: Map, var currentClip: AnimationName, var frameIndex: Int = 0, var elapsedTicks: Int = 0, var playing: Boolean = true, var direction: AnimationDirection = AnimationDirection.FORWARD ) : Component { /** * Play a specific animation clip by name. */ fun play(clipName: AnimationName, restart: Boolean = true) { clipName.takeIf { currentClip != it || restart } .run { currentClip = clipName reset() } } /** * Pause the current animation. */ fun pause() { playing = false } /** * Resume the current animation. */ fun resume() { playing = true } /** * Get the current frame name being displayed. */ fun getCurrentFrameName(): FrameName? { val clip = clips[currentClip] ?: return null return clip.frameNames.getOrNull(frameIndex) } private fun reset() { frameIndex = 0 elapsedTicks = 0 direction = AnimationDirection.FORWARD playing = true } }