在地雷遊戲 (Minesweeper) 中,除了揭開格子之外,另一個非常重要的功能就是 旗子標記 (Flagging)。玩家可以透過右鍵點擊來標記懷疑有地雷的格子,避免誤觸。今天我們要完成的功能就是 右鍵旗子標記與取消,並讓遊戲能正確顯示剩餘旗子的數量。
1 紀錄目前所有剩餘可以標示的數目
// Board - 棋盤
type Board struct {
rows int // 總共格數
cols int // 總共列數
cells [][]*Cell // 整格棋盤狀態
minePositionShuffler positionShuffler // 亂序器用來安排地雷格子
RemainingFlags int // 剩餘標記數
}
2 偵測滑鼠右鍵點擊
func (g *GameLayout) Update() error {
// 偵測 mouse click 事件
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
xPos, yPos := ebiten.CursorPosition()
// 當在面板下方才處理
if yPos >= PanelHeight {
row := (yPos - PanelHeight) / gridSize
col := xPos / gridSize
if row >= 0 && row < Rows && col >= 0 && col < Cols {
// 執行 Flood Fill
g.gameInstance.Board.Reveal(row, col)
}
}
}
// 偵測 mouse 右鍵 click 事件
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) {
xPos, yPos := ebiten.CursorPosition()
// 當在面板下方才處理
if yPos >= PanelHeight {
row := (yPos - PanelHeight) / gridSize
col := xPos / gridSize
if row >= 0 && row < Rows && col >= 0 && col < Cols {
// 執行 ToggleFlag
g.gameInstance.Board.ToggleFlag(row, col)
}
}
}
return nil
}
// drawBoard - 畫出目前盤面狀態
func (g *GameLayout) drawBoard(screen *ebiten.Image) {
for row := 0; row < Rows; row++ {
for col := 0; col < Cols; col++ {
// 取出格子狀態
cell := g.gameInstance.Board.GetCell(row, col)
// 根據格子狀態,顯示對應的畫面
// 當格子沒有被掀開時,畫出原本的灰階
if !cell.Revealed {
g.drawUnTouchCell(screen, row, col)
if cell.Flagged {
g.drawFlag(screen, row, col)
}
} else {
g.drawTouchCellBackground(screen, row, col)
if cell.AdjacenetMines != 0 {
g.drawTouchCellAdjacency(screen, row, col, cell.AdjacenetMines)
}
if cell.IsMine {
g.drawTouchCellMine(screen, row, col)
}
}
}
}
}
func (g *GameLayout) drawRemainFlag(screen *ebiten.Image) {
panel := ebiten.NewImage(ScreenWidth, PanelHeight)
panel.Fill(color.RGBA{100, 100, 0x10, 0xFF})
screen.DrawImage(panel, nil)
// 畫旗子面板(固定在上方)
textValue := fmt.Sprintf("Flags: %d / %d", g.gameInstance.Board.RemainingFlags, MineCounts)
textXPos := PaddingX
textYPos := PaddingY
textOpts := &text.DrawOptions{}
textOpts.ColorScale.ScaleWithColor(getTileColor(-1))
textOpts.PrimaryAlign = text.AlignCenter
textOpts.SecondaryAlign = text.AlignCenter
textOpts.GeoM.Translate(float64(textXPos), float64(textYPos))
text.Draw(screen, textValue, &text.GoTextFace{
Source: mplusFaceSource,
Size: 20,
}, textOpts)
}
https://github.com/leetcode-golang-classroom/mine-sweeper-game/actions/runs/17334075303
今天完成了地雷遊戲中另一個關鍵功能 旗子標記,遊戲互動性大幅提升。玩家可以更有策略性地進行操作,而不是盲目翻格。