55 "image/color"
66
77 "github.com/hajimehoshi/ebiten/v2"
8+ "github.com/hajimehoshi/ebiten/v2/inpututil"
89 "github.com/hajimehoshi/ebiten/v2/text/v2"
910 "github.com/hajimehoshi/ebiten/v2/vector"
1011 "github.com/leetcode-golang-classroom/mine-sweeper/internal/game"
@@ -14,8 +15,11 @@ const (
1415 gridSize = 32
1516 Rows = 10
1617 Cols = 10
17- ScreenWidth = gridSize * Rows
18- ScreenHeight = gridSize * Cols
18+ PanelHeight = 36 // 上方面板高度
19+ PaddingX = 60 // 面板內文字左邊距
20+ PaddingY = 20 // 面板
21+ ScreenHeight = PanelHeight + gridSize * Rows
22+ ScreenWidth = gridSize * Cols
1923 MineCounts = 9
2024)
2125
@@ -31,11 +35,27 @@ func (g *GameLayout) Update() error {
3135 // 偵測 mouse click 事件
3236 if ebiten .IsMouseButtonPressed (ebiten .MouseButtonLeft ) {
3337 xPos , yPos := ebiten .CursorPosition ()
34- row := yPos / gridSize
35- col := xPos / gridSize
36- if row >= 0 && row < Rows && col >= 0 && col < Cols {
37- // 執行 Flood Fill
38- g .gameInstance .Board .Reveal (row , col )
38+ // 當在面板下方才處理
39+ if yPos >= PanelHeight {
40+ row := (yPos - PanelHeight ) / gridSize
41+ col := xPos / gridSize
42+ if row >= 0 && row < Rows && col >= 0 && col < Cols {
43+ // 執行 Flood Fill
44+ g .gameInstance .Board .Reveal (row , col )
45+ }
46+ }
47+ }
48+ // 偵測 mouse 右鍵 click 事件
49+ if inpututil .IsMouseButtonJustPressed (ebiten .MouseButtonRight ) {
50+ xPos , yPos := ebiten .CursorPosition ()
51+ // 當在面板下方才處理
52+ if yPos >= PanelHeight {
53+ row := (yPos - PanelHeight ) / gridSize
54+ col := xPos / gridSize
55+ if row >= 0 && row < Rows && col >= 0 && col < Cols {
56+ // 執行 ToggleFlag
57+ g .gameInstance .Board .ToggleFlag (row , col )
58+ }
3959 }
4060 }
4161 return nil
@@ -46,7 +66,7 @@ func (g *GameLayout) drawUnTouchCell(screen *ebiten.Image, row, col int) {
4666 vector .DrawFilledRect (
4767 screen ,
4868 float32 (col * gridSize ),
49- float32 (row * gridSize ),
69+ float32 (PanelHeight + row * gridSize ),
5070 gridSize - 1 ,
5171 gridSize - 1 ,
5272 color.RGBA {100 , 100 , 100 , 0xff },
@@ -59,7 +79,7 @@ func (g *GameLayout) drawTouchCellBackground(screen *ebiten.Image, row, col int)
5979 vector .DrawFilledRect (
6080 screen ,
6181 float32 (col * gridSize ),
62- float32 (row * gridSize ),
82+ float32 (PanelHeight + row * gridSize ),
6383 gridSize - 1 ,
6484 gridSize - 1 ,
6585 color.RGBA {200 , 200 , 200 , 0xff },
@@ -72,7 +92,7 @@ func (g *GameLayout) drawTouchCellAdjacency(screen *ebiten.Image, row, col, valu
7292 // 繪製數字 (置中)
7393 textValue := fmt .Sprintf ("%d" , value )
7494 textXPos := col * gridSize + (gridSize )/ 2
75- textYPos := row * gridSize + (gridSize )/ 2
95+ textYPos := PanelHeight + row * gridSize + (gridSize )/ 2
7696 textOpts := & text.DrawOptions {}
7797 textOpts .ColorScale .ScaleWithColor (getTileColor (value ))
7898 textOpts .PrimaryAlign = text .AlignCenter
@@ -89,7 +109,7 @@ func (g *GameLayout) drawTouchCellMine(screen *ebiten.Image, row, col int) {
89109 // 繪製數字 (置中)
90110 textValue := "X"
91111 textXPos := col * gridSize + (gridSize )/ 2
92- textYPos := row * gridSize + (gridSize )/ 2
112+ textYPos := PanelHeight + row * gridSize + (gridSize )/ 2
93113 textOpts := & text.DrawOptions {}
94114 textOpts .ColorScale .ScaleWithColor (getTileColor (- 1 ))
95115 textOpts .PrimaryAlign = text .AlignCenter
@@ -101,7 +121,25 @@ func (g *GameLayout) drawTouchCellMine(screen *ebiten.Image, row, col int) {
101121 }, textOpts )
102122}
103123
104- func (g * GameLayout ) Draw (screen * ebiten.Image ) {
124+ // drawFlag - 標示 flag
125+ func (g * GameLayout ) drawFlag (screen * ebiten.Image , row , col int ) {
126+ // 繪製數字 (置中)
127+ textValue := "F"
128+ textXPos := col * gridSize + (gridSize )/ 2
129+ textYPos := PanelHeight + row * gridSize + (gridSize )/ 2
130+ textOpts := & text.DrawOptions {}
131+ textOpts .ColorScale .ScaleWithColor (getTileColor (- 1 ))
132+ textOpts .PrimaryAlign = text .AlignCenter
133+ textOpts .SecondaryAlign = text .AlignCenter
134+ textOpts .GeoM .Translate (float64 (textXPos ), float64 (textYPos ))
135+ text .Draw (screen , textValue , & text.GoTextFace {
136+ Source : mplusFaceSource ,
137+ Size : 30 ,
138+ }, textOpts )
139+ }
140+
141+ // drawBoard - 畫出目前盤面狀態
142+ func (g * GameLayout ) drawBoard (screen * ebiten.Image ) {
105143 for row := 0 ; row < Rows ; row ++ {
106144 for col := 0 ; col < Cols ; col ++ {
107145 // 取出格子狀態
@@ -111,6 +149,9 @@ func (g *GameLayout) Draw(screen *ebiten.Image) {
111149 // 當格子沒有被掀開時,畫出原本的灰階
112150 if ! cell .Revealed {
113151 g .drawUnTouchCell (screen , row , col )
152+ if cell .Flagged {
153+ g .drawFlag (screen , row , col )
154+ }
114155 } else {
115156 g .drawTouchCellBackground (screen , row , col )
116157 if cell .AdjacenetMines != 0 {
@@ -124,6 +165,30 @@ func (g *GameLayout) Draw(screen *ebiten.Image) {
124165 }
125166}
126167
168+ // drawRemainFlag
169+ func (g * GameLayout ) drawRemainFlag (screen * ebiten.Image ) {
170+ panel := ebiten .NewImage (ScreenWidth , PanelHeight )
171+ panel .Fill (color.RGBA {100 , 100 , 0x10 , 0xFF })
172+ screen .DrawImage (panel , nil )
173+ // 畫旗子面板(固定在上方)
174+ textValue := fmt .Sprintf ("Flags: %d / %d" , g .gameInstance .Board .RemainingFlags , MineCounts )
175+ textXPos := PaddingX
176+ textYPos := PaddingY
177+ textOpts := & text.DrawOptions {}
178+ textOpts .ColorScale .ScaleWithColor (getTileColor (- 1 ))
179+ textOpts .PrimaryAlign = text .AlignCenter
180+ textOpts .SecondaryAlign = text .AlignCenter
181+ textOpts .GeoM .Translate (float64 (textXPos ), float64 (textYPos ))
182+ text .Draw (screen , textValue , & text.GoTextFace {
183+ Source : mplusFaceSource ,
184+ Size : 20 ,
185+ }, textOpts )
186+ }
187+ func (g * GameLayout ) Draw (screen * ebiten.Image ) {
188+ g .drawBoard (screen )
189+ g .drawRemainFlag (screen )
190+ }
191+
127192func (g * GameLayout ) Layout (outsideWidth , outsideHeight int ) (int , int ) {
128193 return ScreenWidth , ScreenHeight
129194}
0 commit comments