Word scramble

 Nama: Mohammad Ahnaf Fauzan

NRP: 5025211170

Aplikasi Word Scrambler



Pada pertemuan kali ini, diberikan sebuah tugas untuk membuat sebuah game yang bertujuan untuk menebak kata tersembunyi dari beberapa kumpulan karakter yang telah di acak. Aplikasi ini dibangun menggunakan source code sebagai berikut.

fun GameScreen(gameViewModel: GameViewModel = viewModel()) {
val gameUiState by gameViewModel.uiState.collectAsState()
val mediumPadding = dimensionResource(R.dimen.padding_medium)

Column(
modifier = Modifier
.statusBarsPadding()
.verticalScroll(rememberScrollState())
.safeDrawingPadding()
.padding(mediumPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {

Text(
text = stringResource(R.string.app_name),
style = typography.titleLarge,
)
GameLayout(
onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
wordCount = gameUiState.currentWordCount,
userGuess = gameViewModel.userGuess,
onKeyboardDone = { gameViewModel.checkUserGuess() },
currentScrambledWord = gameUiState.currentScrambledWord,
isGuessWrong = gameUiState.isGuessedWordWrong,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(mediumPadding)
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(mediumPadding),
verticalArrangement = Arrangement.spacedBy(mediumPadding),
horizontalAlignment = Alignment.CenterHorizontally
) {

Button(
modifier = Modifier.fillMaxWidth(),
onClick = { gameViewModel.checkUserGuess() }
) {
Text(
text = stringResource(R.string.submit),
fontSize = 16.sp
)
}

OutlinedButton(
onClick = { gameViewModel.skipWord() },
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(R.string.skip),
fontSize = 16.sp
)
}
}

GameStatus(score = gameUiState.score, modifier = Modifier.padding(20.dp))

if (gameUiState.isGameOver) {
FinalScoreDialog(
score = gameUiState.score,
onPlayAgain = { gameViewModel.resetGame() }
)
}
}
}

@Composable
fun GameStatus(score: Int, modifier: Modifier = Modifier) {
Card(
modifier = modifier
) {
Text(
text = stringResource(R.string.score, score),
style = typography.headlineMedium,
modifier = Modifier.padding(8.dp)
)

}
}

@Composable
fun GameLayout(
currentScrambledWord: String,
wordCount: Int,
isGuessWrong: Boolean,
userGuess: String,
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
modifier: Modifier = Modifier
) {
val mediumPadding = dimensionResource(R.dimen.padding_medium)

Card(
modifier = modifier,
elevation = CardDefaults.cardElevation(defaultElevation = 5.dp)
) {
Column(
verticalArrangement = Arrangement.spacedBy(mediumPadding),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(mediumPadding)
) {
Text(
modifier = Modifier
.clip(shapes.medium)
.background(colorScheme.surfaceTint)
.padding(horizontal = 10.dp, vertical = 4.dp)
.align(alignment = Alignment.End),
text = stringResource(R.string.word_count, wordCount),
style = typography.titleMedium,
color = colorScheme.onPrimary
)
Text(
text = currentScrambledWord,
style = typography.displayMedium
)
Text(
text = stringResource(R.string.instructions),
textAlign = TextAlign.Center,
style = typography.titleMedium
)
OutlinedTextField(
value = userGuess,
singleLine = true,
shape = shapes.large,
modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors(
focusedContainerColor = colorScheme.surface,
unfocusedContainerColor = colorScheme.surface,
disabledContainerColor = colorScheme.surface,
),
onValueChange = onUserGuessChanged,
label = {
if (isGuessWrong) {
Text(stringResource(R.string.wrong_guess))
} else {
Text(stringResource(R.string.enter_your_word))
}
},
isError = isGuessWrong,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { onKeyboardDone() }
)
)
}
}
}

/*
* Creates and shows an AlertDialog with final score.
*/
@Composable
private fun FinalScoreDialog(
score: Int,
onPlayAgain: () -> Unit,
modifier: Modifier = Modifier
) {
val activity = (LocalContext.current as Activity)

AlertDialog(
onDismissRequest = {
// Dismiss the dialog when the user clicks outside the dialog or on the back
// button. If you want to disable that functionality, simply use an empty
// onCloseRequest.
},
title = { Text(text = stringResource(R.string.congratulations)) },
text = { Text(text = stringResource(R.string.you_scored, score)) },
modifier = modifier,
dismissButton = {
TextButton(
onClick = {
activity.finish()
}
) {
Text(text = stringResource(R.string.exit))
}
},
confirmButton = {
TextButton(onClick = onPlayAgain) {
Text(text = stringResource(R.string.play_again))
}
}
)
}

@Preview(showBackground = true)
@Composable
fun GameScreenPreview() {
UnscrambleTheme {
GameScreen()
}
}
Dalam kode ini, saya fokus untuk mengatur tampilan UI game dan menghubungkannya dengan ViewModel, agar logika dan data permainan dapat langsung mempengaruhi tampilan. Pertama, saya membuat fungsi GameScreen sebagai tampilan utama. Di dalamnya, saya menggunakan Column untuk menyusun komponen secara vertikal, mulai dari judul game, layout permainan, tombol-tombol aksi, hingga status skor. Semua data diambil dari GameViewModel menggunakan collectAsState, sehingga tampilan akan otomatis terupdate jika ada perubahan pada data. Selanjutnya, saya membuat komponen GameLayout yang menampilkan kata acak yang harus ditebak, kolom input jawaban, serta indikator jika tebakan salah. Input sudah diatur sedemikian rupa, sehingga ketika pengguna menekan tombol "Done" pada keyboard, jawaban langsung diproses oleh ViewModel untuk diperiksa. Kemudian, ada dua tombol: Submit untuk mengecek jawaban dan Skip untuk melanjutkan ke kata berikutnya. Di bagian bawah, saya menampilkan skor menggunakan komponen GameStatus. Jika permainan selesai, akan muncul dialog FinalScoreDialog yang menampilkan skor akhir dan pilihan untuk bermain lagi atau keluar dari game. Saya menggunakan AlertDialog dari Compose untuk bagian ini. Terakhir, saya menambahkan anotasi @Preview agar tampilan bisa dilihat langsung di Android Studio tanpa perlu menjalankan aplikasi. Seluruh layout saya atur dengan padding, warna, dan gaya sesuai dengan tema aplikasi, agar tampilannya terlihat rapi.

Link Github

Komentar

Postingan populer dari blog ini

Tugas pertemuan 3

Tugas 1 PPB A

Tugas 4 (basic-android-kotlin-compose-training-dice-roller)