fix : 修复积分榜问题

This commit is contained in:
flykhan 2026-04-26 11:01:16 +08:00
parent 1a215a4b8f
commit d201ae48eb
4 changed files with 175 additions and 42 deletions

View File

@ -21,8 +21,15 @@ import com.unogame.ui.theme.*
fun GameOverScreen(
winnerName: String,
isYouWinner: Boolean,
onBackToMenu: () -> Unit
onBackToMenu: () -> Unit,
points: Int = 0,
difficulty: String = "",
duration: Int = 0,
turnNumber: Int = 0,
playerCount: Int = 0
) {
val durationText = if (duration >= 60) "${duration / 60}${duration % 60}" else "${duration}"
Box(
modifier = Modifier
.fillMaxSize()
@ -61,6 +68,38 @@ fun GameOverScreen(
textAlign = TextAlign.Center
)
if (isYouWinner && points > 0) {
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "+$points",
fontSize = 32.sp,
fontWeight = FontWeight.Black,
color = GoldAccent
)
Spacer(modifier = Modifier.height(12.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("难度", color = Color.White.copy(alpha = 0.5f), fontSize = 12.sp)
Text(difficulty, color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Bold)
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("时长", color = Color.White.copy(alpha = 0.5f), fontSize = 12.sp)
Text(durationText, color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Bold)
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("人数", color = Color.White.copy(alpha = 0.5f), fontSize = 12.sp)
Text("${playerCount}", color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Bold)
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("轮次", color = Color.White.copy(alpha = 0.5f), fontSize = 12.sp)
Text("$turnNumber", color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Bold)
}
}
}
Spacer(modifier = Modifier.height(48.dp))
Button(

View File

@ -14,10 +14,19 @@ import com.unogame.model.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
data class ScoreEntry(val name: String, val wins: Int, val mode: String)
data class ScoreEntry(
val name: String,
val mode: String,
val points: Int,
val difficulty: String,
val duration: Int,
val playerCount: Int,
val turnNumber: Int,
val date: Long
)
object Scoreboard {
private const val PREFS_KEY = "uno_scores"
private const val PREFS_KEY = "uno_scoreboard"
private val gson = Gson()
fun loadScores(context: Context): List<ScoreEntry> {
@ -33,15 +42,30 @@ object Scoreboard {
.edit().putString(PREFS_KEY, gson.toJson(scores)).apply()
}
fun addWin(context: Context, name: String, mode: GameMode) {
fun addEntry(
context: Context,
name: String,
mode: String,
points: Int,
difficulty: String,
duration: Int,
playerCount: Int,
turnNumber: Int
) {
val scores = loadScores(context).toMutableList()
val existing = scores.indexOfFirst { it.name == name && it.mode == mode.displayName }
if (existing >= 0) {
scores[existing] = scores[existing].copy(wins = scores[existing].wins + 1)
} else {
scores.add(ScoreEntry(name, 1, mode.displayName))
}
saveScores(context, scores.sortedByDescending { it.wins }.take(20))
scores.add(
ScoreEntry(
name = name,
mode = mode,
points = points,
difficulty = difficulty,
duration = duration,
playerCount = playerCount,
turnNumber = turnNumber,
date = System.currentTimeMillis()
)
)
saveScores(context, scores.sortedByDescending { it.points }.take(50))
}
}
@ -57,6 +81,7 @@ fun LocalGameScreen(
val rules = remember { GameRules.forMode(mode) }
val engine = remember { GameEngine(rules) }
val aiDiff = remember { AIDifficulty.load(context) }
val gameStartTime = remember { System.currentTimeMillis() }
val players = remember {
val list = mutableListOf<Player>()
@ -75,6 +100,10 @@ fun LocalGameScreen(
var winnerName by remember { mutableStateOf("") }
var isYouWinner by remember { mutableStateOf(false) }
var scoreSaved by remember { mutableStateOf(false) }
var gamePoints by remember { mutableIntStateOf(0) }
var gameDuration by remember { mutableIntStateOf(0) }
var gameDifficulty by remember { mutableStateOf("") }
var gameTurnNumber by remember { mutableIntStateOf(0) }
val myPlayerId = "human"
val currentPlayer = gameState.currentPlayer
@ -90,7 +119,25 @@ fun LocalGameScreen(
isYouWinner = state.winner?.id == myPlayerId
if (isYouWinner && !scoreSaved) {
scoreSaved = true
Scoreboard.addWin(context, humanPlayerName, mode)
gameTurnNumber = state.turnNumber
gameDuration = ((System.currentTimeMillis() - gameStartTime) / 1000).toInt()
gameDifficulty = aiDiff.displayName
gamePoints = state.players.filter { it.id != myPlayerId }.sumOf { player ->
player.cards.sumOf { card ->
val active = if (state.flipped && card.flipSide != null) card.flipSide else card
active.score
}
}
Scoreboard.addEntry(
context = context,
name = humanPlayerName,
mode = mode.displayName,
points = gamePoints,
difficulty = gameDifficulty,
duration = gameDuration,
playerCount = totalPlayers,
turnNumber = gameTurnNumber
)
}
}
}
@ -145,7 +192,12 @@ fun LocalGameScreen(
GameOverScreen(
winnerName = winnerName,
isYouWinner = isYouWinner,
onBackToMenu = onBackToMenu
onBackToMenu = onBackToMenu,
points = gamePoints,
difficulty = gameDifficulty,
duration = gameDuration,
turnNumber = gameTurnNumber,
playerCount = totalPlayers
)
} else {
GameScreen(

View File

@ -1,7 +1,9 @@
package com.unogame.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
@ -19,6 +21,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.unogame.game.GameMode
import com.unogame.ui.theme.*
import java.text.SimpleDateFormat
import java.util.*
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -48,7 +52,9 @@ fun ScoreboardScreen(onBack: () -> Unit) {
// Mode filter chips
if (scores.isNotEmpty()) {
Row(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
modes.forEach { mode ->
@ -95,16 +101,17 @@ fun ScoreboardScreen(onBack: () -> Unit) {
2 -> Color(0xFFCD7F32)
else -> Color.White.copy(alpha = 0.5f)
}
val dateFormat = remember { SimpleDateFormat("MM-dd HH:mm", Locale.getDefault()) }
val durationText = if (entry.duration >= 60) "${entry.duration / 60}${entry.duration % 60}"
else "${entry.duration}"
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(containerColor = if (index < 3) DarkSurface else DarkCard)
) {
Row(
modifier = Modifier.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Rank
Column(modifier = Modifier.padding(12.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "#${index + 1}",
color = rankColor,
@ -112,24 +119,57 @@ fun ScoreboardScreen(onBack: () -> Unit) {
fontWeight = FontWeight.Black,
modifier = Modifier.width(44.dp)
)
// Name
Column(modifier = Modifier.weight(1f)) {
Text(entry.name, color = Color.White, fontWeight = FontWeight.Bold, fontSize = 15.sp)
Text(
entry.mode,
color = Color.White.copy(alpha = 0.5f),
color = GoldAccent,
fontSize = 12.sp
)
}
// Wins
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Star, null, tint = GoldAccent, modifier = Modifier.size(18.dp))
Spacer(modifier = Modifier.width(4.dp))
Column(horizontalAlignment = Alignment.End) {
Text(
"${entry.wins}",
"${entry.points}",
color = GoldAccent,
fontWeight = FontWeight.Bold,
fontSize = 16.sp
fontWeight = FontWeight.Black,
fontSize = 20.sp
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.SmartToy, null, tint = Color.White.copy(alpha = 0.5f), modifier = Modifier.size(14.dp))
Spacer(modifier = Modifier.width(2.dp))
Text(entry.difficulty, color = Color.White.copy(alpha = 0.5f), fontSize = 11.sp)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Timer, null, tint = Color.White.copy(alpha = 0.5f), modifier = Modifier.size(14.dp))
Spacer(modifier = Modifier.width(2.dp))
Text(durationText, color = Color.White.copy(alpha = 0.5f), fontSize = 11.sp)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Group, null, tint = Color.White.copy(alpha = 0.5f), modifier = Modifier.size(14.dp))
Spacer(modifier = Modifier.width(2.dp))
Text("${entry.playerCount}", color = Color.White.copy(alpha = 0.5f), fontSize = 11.sp)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Loop, null, tint = Color.White.copy(alpha = 0.5f), modifier = Modifier.size(14.dp))
Spacer(modifier = Modifier.width(2.dp))
Text("${entry.turnNumber}", color = Color.White.copy(alpha = 0.5f), fontSize = 11.sp)
}
}
Spacer(modifier = Modifier.height(4.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Schedule, null, tint = Color.White.copy(alpha = 0.3f), modifier = Modifier.size(12.dp))
Spacer(modifier = Modifier.width(2.dp))
Text(
dateFormat.format(Date(entry.date)),
color = Color.White.copy(alpha = 0.3f),
fontSize = 10.sp
)
}
}

2
gradlew vendored Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
exec java -jar "$(dirname "$0")/gradle/wrapper/gradle-wrapper.jar" "$@"