5
5
"image/color"
6
6
7
7
"github.com/hajimehoshi/ebiten/v2"
8
+ "github.com/hajimehoshi/ebiten/v2/inpututil"
8
9
"github.com/hajimehoshi/ebiten/v2/text/v2"
9
10
"github.com/hajimehoshi/ebiten/v2/vector"
10
11
"github.com/leetcode-golang-classroom/mine-sweeper/internal/game"
@@ -14,8 +15,11 @@ const (
14
15
gridSize = 32
15
16
Rows = 10
16
17
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
19
23
MineCounts = 9
20
24
)
21
25
@@ -31,11 +35,27 @@ func (g *GameLayout) Update() error {
31
35
// 偵測 mouse click 事件
32
36
if ebiten .IsMouseButtonPressed (ebiten .MouseButtonLeft ) {
33
37
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
+ }
39
59
}
40
60
}
41
61
return nil
@@ -46,7 +66,7 @@ func (g *GameLayout) drawUnTouchCell(screen *ebiten.Image, row, col int) {
46
66
vector .DrawFilledRect (
47
67
screen ,
48
68
float32 (col * gridSize ),
49
- float32 (row * gridSize ),
69
+ float32 (PanelHeight + row * gridSize ),
50
70
gridSize - 1 ,
51
71
gridSize - 1 ,
52
72
color.RGBA {100 , 100 , 100 , 0xff },
@@ -59,7 +79,7 @@ func (g *GameLayout) drawTouchCellBackground(screen *ebiten.Image, row, col int)
59
79
vector .DrawFilledRect (
60
80
screen ,
61
81
float32 (col * gridSize ),
62
- float32 (row * gridSize ),
82
+ float32 (PanelHeight + row * gridSize ),
63
83
gridSize - 1 ,
64
84
gridSize - 1 ,
65
85
color.RGBA {200 , 200 , 200 , 0xff },
@@ -72,7 +92,7 @@ func (g *GameLayout) drawTouchCellAdjacency(screen *ebiten.Image, row, col, valu
72
92
// 繪製數字 (置中)
73
93
textValue := fmt .Sprintf ("%d" , value )
74
94
textXPos := col * gridSize + (gridSize )/ 2
75
- textYPos := row * gridSize + (gridSize )/ 2
95
+ textYPos := PanelHeight + row * gridSize + (gridSize )/ 2
76
96
textOpts := & text.DrawOptions {}
77
97
textOpts .ColorScale .ScaleWithColor (getTileColor (value ))
78
98
textOpts .PrimaryAlign = text .AlignCenter
@@ -89,7 +109,7 @@ func (g *GameLayout) drawTouchCellMine(screen *ebiten.Image, row, col int) {
89
109
// 繪製數字 (置中)
90
110
textValue := "X"
91
111
textXPos := col * gridSize + (gridSize )/ 2
92
- textYPos := row * gridSize + (gridSize )/ 2
112
+ textYPos := PanelHeight + row * gridSize + (gridSize )/ 2
93
113
textOpts := & text.DrawOptions {}
94
114
textOpts .ColorScale .ScaleWithColor (getTileColor (- 1 ))
95
115
textOpts .PrimaryAlign = text .AlignCenter
@@ -101,7 +121,25 @@ func (g *GameLayout) drawTouchCellMine(screen *ebiten.Image, row, col int) {
101
121
}, textOpts )
102
122
}
103
123
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 ) {
105
143
for row := 0 ; row < Rows ; row ++ {
106
144
for col := 0 ; col < Cols ; col ++ {
107
145
// 取出格子狀態
@@ -111,6 +149,9 @@ func (g *GameLayout) Draw(screen *ebiten.Image) {
111
149
// 當格子沒有被掀開時,畫出原本的灰階
112
150
if ! cell .Revealed {
113
151
g .drawUnTouchCell (screen , row , col )
152
+ if cell .Flagged {
153
+ g .drawFlag (screen , row , col )
154
+ }
114
155
} else {
115
156
g .drawTouchCellBackground (screen , row , col )
116
157
if cell .AdjacenetMines != 0 {
@@ -124,6 +165,30 @@ func (g *GameLayout) Draw(screen *ebiten.Image) {
124
165
}
125
166
}
126
167
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
+
127
192
func (g * GameLayout ) Layout (outsideWidth , outsideHeight int ) (int , int ) {
128
193
return ScreenWidth , ScreenHeight
129
194
}
0 commit comments