package coffee.liz.abstractionengine.game import androidx.compose.foundation.Canvas import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import coffee.liz.ecs.World import kotlinx.coroutines.isActive /** * 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 */ @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 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, backgroundColor: Color = Color.Transparent, modifier: Modifier = Modifier ) { Canvas(modifier = modifier) { // Clear background drawRect(backgroundColor) // Render all sprites renderSystem.render(world, this) } }