From 395aa7d1c312e495517701be11c21425d9a5838e Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sun, 26 Oct 2025 17:25:13 -0700 Subject: Checkpoint --- .../abstractionengine/game/AbstractionEngine.kt | 5 ++ .../coffee/liz/abstractionengine/game/Game.kt | 37 ++---------- .../liz/abstractionengine/game/RenderSystem.kt | 70 ---------------------- .../coffee/liz/abstractionengine/game/Renderer.kt | 65 ++++++++++++++++++++ 4 files changed, 74 insertions(+), 103 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt delete mode 100644 composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt create mode 100644 composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt (limited to 'composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game') diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt new file mode 100644 index 0000000..18349c3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt @@ -0,0 +1,5 @@ +package coffee.liz.abstractionengine.game + +class AbstractionEngine { + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt index 9490f83..0c3a007 100644 --- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt +++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt @@ -6,64 +6,35 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import coffee.liz.ecs.World import kotlinx.coroutines.isActive +import kotlin.time.Duration.Companion.nanoseconds /** - * Manages the game loop for an ECS world. - * Syncs with Compose's frame rate (like requestAnimationFrame) and provides - * the world to child content for custom rendering/UI. - * - * @param world The ECS world containing entities and systems - * @param content Composable content that can use the world for rendering + * Manages and paints the [World]. */ @Composable fun Game( world: World, content: @Composable () -> Unit ) { - // Trigger recomposition when we need to redraw var frameCount by remember { mutableStateOf(0) } - // Game loop - syncs with Compose's frame rate like requestAnimationFrame LaunchedEffect(world) { - var lastFrameTimeNanos = 0L + var lastUpdate: Long? = null while (isActive) { - // Wait for next frame (like requestAnimationFrame) withFrameNanos { frameTimeNanos -> - val deltaTime = if (lastFrameTimeNanos != 0L) { - (frameTimeNanos - lastFrameTimeNanos) / 1_000_000_000f - } else { - 0f - } - lastFrameTimeNanos = frameTimeNanos - - // Update ECS world (runs all systems) - if (deltaTime > 0f) { - world.update(deltaTime) - } - - // Trigger recomposition to redraw frameCount++ } } } - // Render content content() } -/** - * A Canvas that renders sprites from an ECS world using a RenderSystem. - * - * @param world The ECS world containing entities to render - * @param renderSystem The system responsible for rendering sprites - * @param backgroundColor Background color for the canvas - * @param modifier Modifier for the Canvas - */ @Composable fun GameCanvas( world: World, - renderSystem: RenderSystem, + renderSystem: Renderer, backgroundColor: Color = Color.Transparent, modifier: Modifier = Modifier ) { diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt deleted file mode 100644 index 1d22ae6..0000000 --- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt +++ /dev/null @@ -1,70 +0,0 @@ -package coffee.liz.abstractionengine.game - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size -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 - -/** - * 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 RenderSystem( - private val imageCache: ImageCache -) : System { - - override val dependencies: Set> = setOf(AnimationSystem::class) - - /** - * The update method is required by the System interface, but rendering - * happens synchronously during Compose's draw phase via the render() method. - */ - override fun update(world: World, deltaTime: Float) { - // 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) - ) - } - } - } -} diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt new file mode 100644 index 0000000..57511f3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt @@ -0,0 +1,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> = 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) + ) + } + } + } +} -- cgit v1.2.3-70-g09d2