昨天我們完成了 輸入違規提示與剩餘格數、錯誤格數的顯示,今天要進一步設計遊戲的 勝利檢查與結束畫面。這是數獨遊戲的最後一步之一,能讓玩家有完整的挑戰與回饋體驗。
我們在原本的 Game 結構中,加上遊戲狀態判斷:
type GameLayout struct {
gameInstance *game.Game
difficulty game.Difficulty
isPlayerWin bool
}
// checkIfPlayerWin - 檢查勝利狀態
func (gameLayout *GameLayout) checkIfPlayerWin() bool {
board := gameLayout.gameInstance.Board
remainingCount := board.TargetSolvedCount - board.FilledCount
conflictCount := board.ConflictCount
return remainingCount == 0 && conflictCount == 0
}
當玩家每次輸入數字時,重新計算 Remaining 與 Errors,並在 Update 時進行判斷:
func (gameLayout *GameLayout) Update() error {
gameLayout.handleRestartButton()
if gameLayout.isPlayerWin {
return nil
}
gameLayout.DetectCursor()
gameLayout.DetectInput()
// 檢查狀態
gameLayout.isPlayerWin = gameLayout.checkIfPlayerWin()
return nil
}
在 Ebiten 繪製畫面時,依照 IsPlayerWin 狀態繪製不同提示:
// drawBoardStatus - 根據是否勝利來畫出不同的提示詞
func (gameLayout *GameLayout) drawBoardStatus(screen *ebiten.Image) {
emojiValue := "⏳"
message := "Keep going"
iconColor := getIconColor(Playing)
if gameLayout.isPlayerWin {
emojiValue = "🏆"
message = "You Win!"
iconColor = getIconColor(Win)
}
emojiXPos := len(emojiValue)
emojiYPos := cellSize + cellSize/2
emojiOpts := &text.DrawOptions{}
emojiOpts.ColorScale.ScaleWithColor(iconColor)
emojiOpts.PrimaryAlign = text.AlignStart
emojiOpts.SecondaryAlign = text.AlignCenter
emojiOpts.GeoM.Translate(float64(emojiXPos), float64(emojiYPos))
text.Draw(screen, emojiValue, &text.GoTextFace{
Source: emojiFaceSource,
Size: 30,
}, emojiOpts)
textValue := message
textXPos := cellSize
textYPos := cellSize + cellSize/2
textOpts := &text.DrawOptions{}
textOpts.ColorScale.ScaleWithColor(color.Black)
textOpts.PrimaryAlign = text.AlignStart
textOpts.SecondaryAlign = text.AlignCenter
textOpts.GeoM.Translate(float64(textXPos), float64(textYPos))
text.Draw(screen, textValue, &text.GoTextFace{
Source: mplusFaceSource,
Size: 25,
}, textOpts)
}
// drawRestartButton - 繪製重新開始的 Button
func (gameLayout *GameLayout) drawRestartButton(screen *ebiten.Image) {
vector.DrawFilledCircle(screen, float32(8*cellSize+cellSize/2), cellSize+cellSize/2, 25,
getIconColor(Button),
true,
)
emojiValue := "🔃"
emojiXPos := 8*cellSize + len(emojiValue)
emojiYPos := cellSize + cellSize/2
emojiOpts := &text.DrawOptions{}
emojiOpts.ColorScale.ScaleWithColor(getIconColor(Restart))
emojiOpts.PrimaryAlign = text.AlignStart
emojiOpts.SecondaryAlign = text.AlignCenter
emojiOpts.GeoM.Translate(float64(emojiXPos), float64(emojiYPos))
text.Draw(screen, emojiValue, &text.GoTextFace{
Source: emojiFaceSource,
Size: 30,
}, emojiOpts)
}
// ResetBoardToDefault - 重開始功能
func (board *Board) ResetBoardToDefault() {
for row := 0; row < BoardSize; row++ {
for col := 0; col < BoardSize; col++ {
if board.Cells[row][col].Type != Preset {
board.Cells[row][col].Type = Empty
board.Cells[row][col].Value = 0
}
}
}
board.FilledCount = 0
board.ConflictCount = 0
}
// handleRestartButton
func (gameLayout *GameLayout) handleRestartButton() {
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
xPos, yPos := ebiten.CursorPosition()
if (xPos >= 8*cellSize && xPos <= 9*cellSize) &&
(yPos >= cellSize && yPos <= 2*cellSize) {
gameLayout.gameInstance.Board.ResetBoardToDefault()
}
}
gameLayout.isPlayerWin = gameLayout.checkIfPlayerWin()
}
https://github.com/leetcode-golang-classroom/sudoku-game/actions/runs/17590954625/job/49971332265
明日將會加入關卡難度選擇與顯示執行時間