I’m trynna build a basic snake game for android. Everything is working just fine except for the food updation. It is working randomly, sometimes when you eat it, new food appears, sometimes literally nothing happens, and sometimes, when you pass from right next to the food, it gets considered as eating it, and sometimes the food just doesn’t appear on the screen until a few seconds pass by.
The whole project is uploaded on: https://github.com/tauqirnizami/SnakeGame
ViewModel file:
var foodCoordinates: Pair<Int, Int> = Pair(14, 13)
var score = 0L
var direction = 0
var giantFoodCoordinates: Pair<Int, Int>? = null
var giantFoodCounter: Int = 0
class SnakeViewModel() : ViewModel() {
/*Pair(length/y-coordinate, width/x-coordinate)*/
var coordinates = mutableStateListOf(Pair(16, 17), Pair(17, 17), Pair(18, 17))
private set
private var delayInMillis: Long = 500L
private var gameGoing by mutableStateOf(true)
private fun delayChange() {/*TODO*/
delayInMillis = if (score == 0L) 500 else if (score <= 500) 500 / score else 0
}
init {
viewModelScope.launch(Dispatchers.Default) {
delay(1000L)
while (gameGoing) {
delay(delayInMillis)
delayChange()
coordinatesUpdation()
}
}
}
private suspend fun coordinatesUpdation() {
// Compute the new head position based on the direction
val head = coordinates.first()
val newHead = when (direction) {
0 -> Pair(if (head.first > 1) head.first - 1 else gridLength, head.second) // UP
1 -> Pair(if (head.first < gridLength) head.first + 1 else 1, head.second) // DOWN
2 -> Pair(head.first, if (head.second > 1) head.second - 1 else gridWidth) // LEFT
else -> Pair(head.first, if (head.second < gridWidth) head.second + 1 else 1) // RIGHT
}
// Update the coordinates with the new head and shift the body
coordinates.add(0, newHead)
coordinates.removeLast()
//Eating Food
if (newHead == foodCoordinates) {
foodCoordinates = food(giantFoodCoordinates)
score++
giantFoodCounter++
val tail = coordinates.last()
coordinates.add(tail)
}
if (coordinates.drop(1).any { it == newHead }) {
gameGoing = false
}
if (giantFoodCounter % 8 == 0 && giantFoodCounter!=0) {
giantFoodCoordinates = food(foodCoordinates)
viewModelScope.launch(Dispatchers.Default) {
delay((if (score < 30) 15 else if (score < 100) 10 else if (score < 300) 6 else 4) * 1000L)
giantFoodCoordinates = null
giantFoodCounter = 0
}
}
if (newHead == giantFoodCoordinates) {
giantFoodCounter = 0
score += 5
var tail = coordinates.last()
coordinates.add(tail)
tail = coordinates.last()
coordinates.add(tail)
tail = coordinates.last()
coordinates.add(tail)
tail = coordinates.last()
coordinates.add(tail)
tail = coordinates.last()
coordinates.add(tail)
}
}
private fun food(otherFood: Pair<Int, Int>?): Pair<Int, Int> {
var a: Pair<Int, Int>
do {
a = Pair((1..gridLength).random(), (1..gridWidth).random())
} while (coordinates.any { it == a } || otherFood == a)
return a
}
}
and the composable file:
val gridWidth: Int = 20
val gridLength: Int = 35
@Composable
fun DisplayGrid(
modifier: Modifier,
snakeViewModel: SnakeViewModel
) {
val colors = generateColorGrid(coordinates = snakeViewModel.coordinates)
ColorGrid(colors, gridWidth, modifier = modifier, cellSize = 18.dp)
}
@Composable
fun Screen(
modifier: Modifier = Modifier,
snakeViewModel: SnakeViewModel = SnakeViewModel()
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
DisplayGrid(modifier, snakeViewModel = snakeViewModel)
Row(
modifier = Modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
//Buttns and score display
}
}
}
fun generateColorGrid(coordinates: List<Pair<Int, Int>>): List<Color> {
val coloursList: MutableList<Color> = mutableListOf()
for (i in 1..gridLength) {
for (j in 1..gridWidth) {
if (coordinates.any { it == Pair(i, j) }) {
coloursList.add(Color.White)
} else if (Pair(j, i) == foodCoordinates) {
coloursList.add(Color.LightGray)
} else if (Pair(j, i) == giantFoodCoordinates) {
coloursList.add(Color.DarkGray)
} else {
coloursList.add(Color.Yellow)
}
}
}
return coloursList
}
@Composable
fun ColorGrid(colors: List<Color>, width: Int, cellSize: Dp, modifier: Modifier = Modifier) {
LazyVerticalGrid(
columns = GridCells.Fixed(width),
modifier = modifier
) {
items(colors) { color ->
Box(
modifier = Modifier
.size(cellSize) // Sets the size of each cell
.background(color)
)
}
}
}
I know my code looks crazy, but I wrote it that way just to prevent as much lag as possible and to make it as optimized as possible. bcz the screen would already be updating many times per second, I thought of doing as much optimization as I could.
I thought this might be due to the coordinatesUpdation() funciton requiring too much time to execute properly, hence I tried to put all the if else blocks from the coordinatesUpdation() function into a separate funciton and run this new funciton in a separate coroutine, but this caused even more harm as now we were reading and updating the ‘coordinates’ variable at the same time!