Я работаю над очень простой игрой-змейкой, используя Kotlin и Jetpack Compose. Чтобы сделать его более эффективным, я подумал об использовании сопрограмм, но постоянно получаю вышеупомянутую ошибку.
Полная версия проекта доступна по адресу: https://github.com/tauqirnizami/SnakeGame
Модель просмотра — это:
class DifficultSnakeViewModel : ViewModel() {
/*Pair(length/y-coordinate, width/x-coordinate)*/
var coordinates = mutableStateListOf(Pair(31, 14), Pair(32, 14), Pair(33, 14))
private set
private var gameGoing by mutableStateOf(true)
var extraWallsCoordinates: List<Pair<Int, Int>>
init {
foodCoordinates = Pair(10, 9)
score = 0L
directions = mutableStateListOf(0) //Using a list instead of a single int to keep track when user changes directions too quickly while the viewModel is on delay (the one for speed controlling). Eg., if user enter up and suddenly left as well, the game earlier used to only register the latter command. Using a mutable list would keep track of all the given commands that currently hasn't been acted on.
giantFoodCoordinates = null
giantFoodCounter = 1
extraWallsCoordinates = walls()
viewModelScope.launch(Dispatchers.Default) {
delay(1000L) //This is to let the viewModel to setup properly before being used. I was getting error due to usage of state variable (probably "coordinates") before waiting for the viewModel to be able to initialize properly first
while (gameGoing) {
delay(if (score < 250) 500 - (score *2) else if (score<500) 1 else 0) //This controls the snake speed
coordinatesUpdation() //This is used to update the snake's coordinates according to the direction, i.e., user input.
}
}
}
//other code
}
Как видите, в простом и среднем режиме игры использования простой задержки (550L) было достаточно, чтобы избежать ошибки, но на сложном уровне это не работает, даже если я увеличил продолжительность задержки с 550 до 1000. или даже 3000 миллис.
Мой составной файл:
@Composable
fun DifficultDisplayGrid(
modifier: Modifier,
snakeViewModel: DifficultSnakeViewModel
) {
val colors = difficultGenerateColorGrid(coordinates = snakeViewModel.coordinates, walls = snakeViewModel.extraWallsCoordinates) //This function returns a list of colours according to snake, food, etc's coordinates, which would be used to display the grid
Column {
ColorGrid(colors = colors, modifier = modifier) //snake game grid
Text(text = "Score = $score")
}
}
@Composable
fun DifficultScreen(
modifier: Modifier = Modifier,
snakeViewModel: DifficultSnakeViewModel = DifficultSnakeViewModel()
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
DifficultDisplayGrid(modifier, snakeViewModel = snakeViewModel)
Row(
modifier = Modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Button(onClick = { directions.add(2) }) {
Icon(imageVector = Icons.Filled.KeyboardArrowLeft, contentDescription = "Left")
}
Column {
Button(onClick = { directions.add(0) }) {
Icon(imageVector = Icons.Filled.KeyboardArrowUp, contentDescription = "Up")
}
Spacer(modifier = Modifier.height(13.dp))
Button(onClick = { directions.add(1) }) {
Icon(imageVector = Icons.Filled.KeyboardArrowDown, contentDescription = "Down")
}
}
Button(onClick = { directions.add(3) }) {
Icon(imageVector = Icons.Filled.KeyboardArrowRight, contentDescription = "Right")
}
}
}
}
//other code
Я попытался использовать функцию задержки(), Thread.sleep(). Пытался использовать thread.sleep перед строкой viewModelScope.launch, пытался сделать это внутри этой области. Но ничего не работало. От 1000 до 50 000 милли ни одна функция или продолжительность не работают.
попробуй это
viewModelScope.launch(Dispatchers.Main) {
// delay(1000L) //This is to let the viewModel to setup properly before being used. I was getting error due to usage of state variable (probably "coordinates") before waiting for the viewModel to be able to initialize properly first
while (gameGoing) {
delay(if (score < 250) 500 - (score *2) else if (score<500) 1 else 0) //This controls the snake speed
coordinatesUpdation()
}
}
Чтобы узнать больше о Dispachers, вы можете прочитать здесь -> https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=es-419#main-safety
Я столкнулся с той же проблемой при изменении состояния, которое используется в составной функции, вне основного потока. в конце концов я решил проблему, используя основной поток для изменения состояния. в вашем случае, как упоминал @witodev, вы должны использовать:
viewModelScope.launch(Dispatchers.Main) { /* your operation */ }
Отвечает ли это на ваш вопрос? java.lang.IllegalStateException при использовании State в Android Jetpack Compose