summaryrefslogtreecommitdiff
path: root/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt
blob: 57511f3fd51dea558c1d99a65318fec00ea5745d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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<KClass<out System>> = 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)
                )
            }
        }
    }
}