Game Over screen

Hi! I’m working on some code for a game called “Slats”. Most of the code works, you get a start page and you can play the game, but when the slats disappear it’s supposed to have a game over page which never shows up. I’ve tried everything, what do I do?

//SlatsSlatsSlats

package com.example.slatsslatsslats

import android.os.Bundle

import androidx.activity.ComponentActivity

import androidx.activity.compose.setContent

import androidx.compose.foundation.Canvas

import androidx.compose.foundation.background

import androidx.compose.foundation.gestures.detectTapGestures

import androidx.compose.foundation.layout.*

import androidx.compose.material3.Text

import androidx.compose.runtime.*

import androidx.compose.ui.Alignment

import androidx.compose.ui.Modifier

import androidx.compose.ui.geometry.Offset

import androidx.compose.ui.graphics.Color

import androidx.compose.ui.input.pointer.pointerInput

import androidx.compose.ui.unit.dp

import androidx.compose.ui.unit.sp

import kotlinx.coroutines.delay

import kotlin.math.*

data class Slat(val x: Float, val y: Float, var size: Float = 0f, val growthSpeed: Float)

class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContent { SlatsGame() }

}

}

@Composable

fun SlatsGame() {

var screen by remember { mutableStateOf("start") }

var score by remember { mutableStateOf(0) }

var slats by remember { mutableStateOf(listOf<Slat>()) }

val lineLength = 40f

val hitDistance = 50f

BoxWithConstraints(modifier = Modifier.fillMaxSize().background(Color.Black)) {

    val w = constraints.maxWidth.toFloat()

    val h = constraints.maxHeight.toFloat()

    // Physics Engine

    LaunchedEffect(screen) {

        if (screen == "game") {

            while (screen == "game") {

                val nextSlats = slats.map { it.copy(size = it.size + it.growthSpeed) }

                    .filter { s ->

                        val maxReach = s.size + lineLength

                        (s.x + maxReach > 0 && s.x - maxReach < w && s.y + maxReach > 0 && s.y - maxReach < h)

                    }

                

                slats = nextSlats

                

                // Force the check within the loop

                if (slats.isEmpty()) {

                    screen = "gameover"

                }

                delay(16)

            }

        }

    }

    when (screen) {

        "start" -> StartScreen {

            score = 0

            slats = listOf(Slat(w / 2, h / 2, 0f, 5f))

            screen = "game"

        }

        "game" -> {

            Canvas(modifier = Modifier.fillMaxSize().pointerInput(Unit) {

                detectTapGestures { offset ->

                    val hit = slats.any { s ->

                        val directions = listOf(1f to -1f, -1f to -1f, 1f to 1f, -1f to 1f, 1f to 0f, -1f to 0f, 0f to 1f, 0f to -1f)

                        directions.any { (dx, dy) ->

                            val start = Offset(s.x + dx \* s.size, s.y + dy \* s.size)

                            val end = Offset(s.x + dx \* (s.size + lineLength), s.y + dy \* (s.size + lineLength))

                            distToSegment(offset, start, end) < hitDistance

                        }

                    }

                    if (hit) {

                        val speed = 5f + (5f \* (1f - exp(-score \* 0.06f)))

                        slats = slats + Slat(offset.x, offset.y, 0f, speed)

                        score++

                    }

                }

            }) {

                slats.forEach { s ->

                    val directions = listOf(1f to -1f, -1f to -1f, 1f to 1f, -1f to 1f, 1f to 0f, -1f to 0f, 0f to 1f, 0f to -1f)

                    directions.forEach { (dx, dy) ->

                        drawLine(Color.White, Offset(s.x + dx \* s.size, s.y + dy \* s.size),

                            Offset(s.x + dx \* (s.size + lineLength), s.y + dy \* (s.size + lineLength)), strokeWidth = 3f)

                    }

                }

            }

            Text("Points: $score", color = Color.White, fontSize = 20.sp, modifier = Modifier.padding(16.dp))

        }

        "gameover" -> GameOverScreen(score) { screen = "start" }

    }

}

}

fun distToSegment(p: Offset, v: Offset, w: Offset): Float {

val l2 = (v.x - w.x).pow(2) + (v.y - w.y).pow(2)

if (l2 == 0f) return (p - v).getDistance()

var t = ((p.x - v.x) \* (w.x - v.x) + (p.y - v.y) \* (w.y - v.y)) / l2

t = max(0f, min(1f, t))

return (p - Offset(v.x + t \* (w.x - v.x), v.y + t \* (w.y - v.y))).getDistance()

}

@Composable

fun StartScreen(onTap: () → Unit) {

Column(

    modifier = Modifier.fillMaxSize(),

    verticalArrangement = Arrangement.Center,

    horizontalAlignment = Alignment.CenterHorizontally

) {

    Text("Slats", color = Color.White, fontSize = 48.sp)

    Spacer(modifier = Modifier.height(16.dp))

    Text(

        text = "Tap to Start",

        color = Color.White,

        fontSize = 20.sp,

        modifier = Modifier.pointerInput(Unit) {

            detectTapGestures { onTap() }

        }

    )

}

}

@Composable

fun GameOverScreen(score: Int, onRestart: () → Unit) {

Column(

    modifier = Modifier.fillMaxSize(),

    verticalArrangement = Arrangement.Center,

    horizontalAlignment = Alignment.CenterHorizontally

) {

    Text("GAME OVER", color = Color.White, fontSize = 48.sp)

    Text("Total Score: $score", color = Color.White, fontSize = 24.sp)

    Spacer(modifier = Modifier.height(16.dp))

    Text(

        text = "Tap to Restart",

        color = Color.White,

        fontSize = 20.sp,

        modifier = Modifier.pointerInput(Unit) {

            detectTapGestures { onRestart() }

        }

    )

}

}