贪吃蛇游戏食物更新在 ViewModel 协程中随机工作

问题描述 投票:0回答:1

我正在尝试为 Android 构建一个基本的贪吃蛇游戏。除了食物更新之外,一切都运转良好。它是随机工作的,有时,当你从食物旁边经过时,它会被认为正在吃它,有时食物只是在上次吃完食物后几秒钟后才出现在屏幕上,有时,只是什么也没发生!

整个项目上传于:https://github.com/tauqirnizami/SnakeGame

视图模型文件:

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
    }
}

和可组合文件:

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)
            )
        }
    }
}

我知道我的代码看起来很疯狂,但我这样编写只是为了尽可能防止延迟并使其尽可能优化。 bcz 屏幕已经每秒更新多次,我想尽可能多地进行优化。

我认为这可能是由于坐标更新()函数需要太多时间才能正确执行,因此我尝试将坐标更新()函数中的所有 if else 块放入一个单独的函数中,并在单独的协程中运行这个新函数,但这造成了更大的危害,因为现在我们同时读取和更新“坐标”变量!

android kotlin mvvm android-jetpack-compose kotlin-coroutines
1个回答
0
投票

一切正常,只是将食物显示在错误的位置:

Pair(j, i)
应该是
Pair(i, j)

© www.soinside.com 2019 - 2024. All rights reserved.