package coffee.liz.abstractionengine.game import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import coffee.liz.ecs.System import coffee.liz.ecs.World import coffee.liz.ecs.animation.AnimationSystem import coffee.liz.ecs.animation.Animator import coffee.liz.ecs.animation.Position import coffee.liz.ecs.animation.SpriteSheet import kotlin.reflect.KClass import kotlin.time.Duration /** * System that renders sprites to a DrawScope. * * This system queries all entities with Position, SpriteSheet, and Animator components, * then draws their current animation frame to the provided DrawScope. * * Depends on AnimationSystem to ensure animations are updated before rendering. */ class Renderer( private val imageCache: ImageCache, ) : System { override val dependencies: Set> = setOf(AnimationSystem::class) override fun update( world: World, duration: Duration, ) { // Rendering happens in render() method, not here } /** * Renders all entities with sprites to the given DrawScope. * This should be called from a Compose Canvas during the draw phase. */ fun render( world: World, drawScope: DrawScope, ) { // Query all entities that can be rendered world.query(Position::class, SpriteSheet::class, Animator::class).forEach { entity -> val position = entity.get(Position::class) ?: return@forEach val spriteSheet = entity.get(SpriteSheet::class) ?: return@forEach val animator = entity.get(Animator::class) ?: return@forEach // Get the current frame name from the animator val frameName = animator.getCurrentFrameName() ?: return@forEach // Look up the frame rectangle in the sprite sheet val frameRect = spriteSheet.frames[frameName] ?: return@forEach // Get the image from cache val image = imageCache.getImage(spriteSheet.imagePath) ?: return@forEach // Draw the sprite with(drawScope) { drawImage( image = image, srcOffset = IntOffset(frameRect.x, frameRect.y), srcSize = IntSize(frameRect.width, frameRect.height), dstOffset = IntOffset(position.x.toInt(), position.y.toInt()), dstSize = IntSize(frameRect.width, frameRect.height), ) } } } }