iT邦幫忙

2025 iThome 鐵人賽

DAY 25
2

主題

繪製盤面格子與 3x3 區塊分隔線
目標是讓遊戲螢幕能夠清楚呈現數獨盤面。

為什麼要畫盤面?

數獨的核心就是一個 9x9 的方格,玩家需要直觀地看到:

  • 每個單格(Cell)的邊界。
  • 3x3 的宮格(Subgrid)清晰分隔。
  • 之後還會加上數字(題目與玩家輸入)。

所以第一步就是先繪製格線,讓基礎盤面結構顯示出來。

設計規劃

1. 格子大小:

  • 每格固定 50x50 pixel。
  • 整個盤面大小:9 x 50 = 450px。

2. 細線:

  • 分隔每一格的直線與橫線(顏色淺灰)。

3. 粗線:

  • 每隔 3 格加粗的直線與橫線,方便辨識宮格(顏色黑)。

4. 中心點繪製:

用 Ebiten 的 Fill 或 DrawLine 畫線條。

範例程式碼

繪製畫面主要邏輯

func (gameLayout *GameLayout) Draw(screen *ebiten.Image) {
	// 畫出基本背景
	gameLayout.drawBoardBackground(screen)
	// 根據遊戲狀態來畫出盤面
	gameLayout.drawCellValuesOnBoard(screen)
	// 畫出盤面格線
	gameLayout.drawLinesOnBoard(screen)
}

繪製背景

// drawBoardBackground - 畫出盤面背景顏色
func (gameLayout *GameLayout) drawBoardBackground(screen *ebiten.Image) {
	boardBgColor := color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}
	boardBackground := ebiten.NewImage(ScreenWidth, ScreenHeight)
	boardBackground.Fill(boardBgColor)
	screen.DrawImage(boardBackground, nil)
}

繪製狀態

// drawCellValuesOnBoard - 根據遊戲狀態來畫出盤面
func (gameLayout *GameLayout) drawCellValuesOnBoard(screen *ebiten.Image) {
	board := gameLayout.gameInstance.Board
	for row := 0; row < game.BoardSize; row++ {
		for col := 0; col < game.BoardSize; col++ {
			// draw preset value
			if board.Cells[row][col].Type == game.Preset {
				gameLayout.drawCellBackground(screen, row, col, getTileBgColor(board.Cells[row][col].Type))
				gameLayout.drawCellValue(screen, row, col, board.Cells[row][col].Value,
					getTileColor(board.Cells[row][col].Type),
				)
			}
			// TODO: draw input
		}
	}
}

繪製格線

// drawLinesOnBoard - 畫出目前盤面所需要的格線
func (gameLayout *GameLayout) drawLinesOnBoard(screen *ebiten.Image) {
	// 畫出盤面格線
	for i := 0; i <= game.BoardSize; i++ {
		x := i * cellSize
		y := i * cellSize

		// 預設是細線
		var lineColor color.Color = color.RGBA{0x77, 0x77, 0x77, 0xFF}
		lineWidth := leanLineWidth
		if i%3 == 0 {
			lineColor = color.Black
			lineWidth = thinkLineWidth
		}
		// 畫直線
		ebitenUtilDrawLine(screen, x, 0, x, ScreenHeight, lineColor, lineWidth)
		// 畫橫線
		ebitenUtilDrawLine(screen, 0, y, ScreenWidth, y, lineColor, lineWidth)
	}
}

實際運行邏輯

func main() {
	ebiten.SetWindowSize(layout.ScreenWidth, layout.ScreenHeight)
	ebiten.SetWindowTitle("Sudoku Board")
	gameLayout := layout.NewGameLayout()
	if err := ebiten.RunGame(gameLayout); err != nil {
		log.Fatal(err)
	}
}

實際效果

執行後,畫面會顯示:

  • 9x9 格子
  • 每隔三格加粗的黑線,區分出 3x3 的宮格
  • 預期畫面就像一本數獨遊戲書上的空白棋盤 🎲
  • 載入設定好的數獨題目

執行畫面

https://ithelp.ithome.com.tw/upload/images/20250907/20111580tVV9Ka93yh.png

github action 測試結果

https://github.com/leetcode-golang-classroom/sudoku-game/actions/runs/17526715147/job/49778149726

驗收條件 ✅

  • 螢幕能正確顯示 9x9 格子。
  • 宮格分隔線(每 3 格)清晰顯示,線條比一般格線粗。
  • 整體盤面大小為 450x450 px,符合設計規格。

今日收穫

  • 我們已經能夠在 Ebiten 畫出數獨棋盤的格子。
  • 學會區分「細線」與「粗線」的繪製方式,讓盤面更符合數獨的結構。

明日預期

接下來,我們將進一步,設計操作遊戲畫面的 ui


上一篇
Sudoku 遊戲: 規則檢查與題目生成
下一篇
Sudoku 遊戲: 游標控制與玩家輸入
系列文
在 ai 時代 gopher 遊戲開發者的 30 天自我養成30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言