This repository has been archived by the owner on Aug 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Interface.py
350 lines (290 loc) · 11.9 KB
/
Interface.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
"""
作者:
杨贇
版权:
GPL (C) Copyright 2021, 杨贇.
联系方式:
smally@stu.ecnu.edu.cn
文件:
Interface.py
时间:
2021/4/13 23:04
"""
from abc import abstractmethod
import pygame
import pygame.image
from Button import Button
from Constant import ButtonEnum
from Constant import PlayerEnum
from Text import Text
from Settings import *
from Utils import resource_path
from Utils import get_chess_pos
class AbstractInterface(object):
"""界面超类。"""
@abstractmethod
def draw(self):
"""绘制界面抽象方法
绘制背景、按钮等界面上所存在的元素。
"""
pass
@abstractmethod
def check_buttons(self, _mouse_pos):
"""检查按钮点击抽象方法。
检查是否有按钮被点击。
Args:
_mouse_pos: 鼠标点击的坐标
Returns:
有按钮被点击时,返回 ButtonEnum 中对应按钮类型,\n
否则返回 ButtonEnum 中无按钮类型。
"""
pass
@abstractmethod
def reset(self):
"""重置页面抽象方法。
用于重置页面,将页面上元素恢复到初始状态。
"""
class FirstInterface(AbstractInterface):
"""首页类。"""
def __init__(self, _windows):
"""初始化首页方法。
Args:
_windows: 由 Pygame 创建的当前游戏窗口
"""
self.__windows = _windows
# 加载背景图并将其缩放至适合窗口的大小。
self.__background_img = pygame.transform.scale(
pygame.image.load('./resource/image/background.jpg'),
[SCREEN_WIDTH, SCREEN_HEIGHT])
# 创建首页上标题。
self.__title_text = Text(None, TITLE_HEIGHT, 'Gobang',
WHITE_COLOR, (TITLE_X, TITLE_Y))
# 创建首页上按钮。
self.__start_button = Button('Start', BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT))
self.__model_button = Button('PVE', MODULE_BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT + 60))
self.__exit_button = Button('Exit', BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT + 120))
def draw(self):
"""绘制首页方法。
绘制首页的背景与按钮。
"""
self.__draw_background()
self.__draw_button(self.__start_button)
self.__draw_button(self.__model_button)
self.__draw_button(self.__exit_button)
def check_buttons(self, _mouse_pos):
"""检查首页按钮点击方法。
检查首页是否有按钮被点击。
Args:
_mouse_pos: 鼠标点击的坐标
Returns:
有按钮被点击时,返回 ButtonEnum 中对应按钮类型,\n
否则返回 ButtonEnum 中无按钮类型。
"""
if self.__start_button.clicked(_mouse_pos):
return ButtonEnum.START_BUTTON
if self.__model_button.clicked(_mouse_pos):
return ButtonEnum.MODULE_BUTTON
if self.__exit_button.clicked(_mouse_pos):
return ButtonEnum.EXIT_BUTTON
return ButtonEnum.NO_BUTTON
def reset(self):
"""重置首页方法。
重新创建首页上的按钮。
"""
self.__start_button = Button('Start', BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT))
self.__model_button = Button('PVE', MODULE_BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT + 60))
self.__exit_button = Button('Exit', BUTTON_COLOR, True,
(TITLE_X - BUTTON_WIDTH // 2,
TITLE_Y + TITLE_HEIGHT + 120))
def __draw_background(self):
"""绘制首页背景。"""
pygame.draw.rect(self.__windows, WHITE_COLOR,
pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
self.__windows.blit(self.__background_img, (0, 0))
self.__windows.blit(*self.__title_text.text_element)
def __draw_button(self, _button):
"""绘制首页按钮。"""
self.__windows.fill(_button.color, _button.rect)
self.__windows.blit(*_button.text_element)
class GameInterface(AbstractInterface):
"""游戏界面类。"""
def __init__(self, _windows):
"""初始化游戏界面方法。
Args:
_windows: 由 Pygame 创建的当前游戏窗口
"""
self.__windows = _windows
# 加载 AI 用头像
self.__ai_img = pygame.transform.scale(pygame.image.load(
resource_path('./resource/image/ai.jpg')), (100, 100))
# 创建游戏界面上按钮。
self.__restart_button = Button('Restart', BUTTON_COLOR, False,
(BOARD_WIDTH + 30, 130))
self.__give_up_button = Button('GiveUp', BUTTON_COLOR, True,
(BOARD_WIDTH + 30, BUTTON_HEIGHT + 160))
self.__back_button = Button('Menu', BUTTON_COLOR, True,
(BOARD_WIDTH + 30, 2 * BUTTON_HEIGHT + 190))
def draw(self, _steps=None):
"""绘制游戏界面方法。
绘制游戏界面的棋盘、棋子与按钮。
Args:
_steps: 已落下的子的列表,格式为[(x 坐标,y 坐标,落子者)],默认为空
"""
if _steps is None:
_steps = []
self.__draw_background()
self.__draw_chess(_steps)
self.__draw_button(self.__restart_button)
self.__draw_button(self.__give_up_button)
self.__draw_button(self.__back_button)
def draw_ai(self):
"""绘制 ai 头像方法。"""
self.__windows.blit(self.__ai_img, (BOARD_WIDTH + 30, 15))
def show_winner(self, winner):
"""显示胜者方法。
在游戏界面右下角显示胜者。
Args:
winner: 胜利的玩家或 None,若无人胜利。
"""
if winner is None:
return
res = 'Winner is '
if winner == PlayerEnum.PLAYER_ONE:
res += 'Black.'
else:
res += 'White.'
text = Text(None, 30, res, BLUE_COLOR,
(BOARD_WIDTH + 100, SCREEN_HEIGHT - 45))
self.__windows.blit(*text.text_element)
def check_buttons(self, _mouse_pos):
"""检查游戏界面按钮点击方法。
检查游戏界面是否有按钮被点击。
Args:
_mouse_pos: 鼠标点击的坐标
Returns:
有按钮被点击时,返回 ButtonEnum 中对应按钮类型,\n
否则返回 ButtonEnum 中无按钮类型。
"""
if self.__restart_button.clicked(_mouse_pos):
return ButtonEnum.RESTART_BUTTON
if self.__give_up_button.clicked(_mouse_pos):
return ButtonEnum.GIVE_UP_BUTTON
if self.__back_button.clicked(_mouse_pos):
return ButtonEnum.BACK_BUTTON
return ButtonEnum.NO_BUTTON
def reset(self):
"""重置游戏界面方法。
清空棋盘、棋子并重新创建游戏界面上的按钮。
"""
self.__draw_background()
self.__restart_button = Button('Restart', BUTTON_COLOR, False,
(BOARD_WIDTH + 30, 130))
self.__give_up_button = Button('GiveUp', BUTTON_COLOR, True,
(BOARD_WIDTH + 30, BUTTON_HEIGHT + 160))
self.__back_button = Button('Menu', BUTTON_COLOR, True,
(BOARD_WIDTH + 30, 2 * BUTTON_HEIGHT + 190))
def enable_restart_button(self):
"""启用重新开始按钮。
启用重新开始按钮的同时需要禁用投降按钮。
"""
if not self.__restart_button.enabled:
self.__restart_button.reverse_enabled()
if self.__give_up_button.enabled:
self.__give_up_button.reverse_enabled()
def enable_give_up_button(self):
"""启用投降按钮。
启用投降按钮的同时需要禁用重新开始按钮。
"""
if not self.__give_up_button.enabled:
self.__give_up_button.reverse_enabled()
if self.__restart_button.enabled:
self.__restart_button.reverse_enabled()
@staticmethod
def check_in_board(_pos):
"""检查坐标是否在棋盘内方法。
Args:
_pos: 坐标
Returns:
坐标是否在棋盘内。
"""
x, y = _pos
return 0 < x < BOARD_WIDTH and 0 < y < BOARD_HEIGHT
def __draw_background(self):
"""绘制游戏界面背景。"""
# 绘制棋盘。
pygame.draw.rect(self.__windows, LIGHT_YELLOW,
(0, 0, BOARD_WIDTH, BOARD_HEIGHT))
# 绘制右侧白色背景。
pygame.draw.rect(self.__windows, WHITE_COLOR,
(BOARD_WIDTH, 0, INFO_WIDTH, BOARD_HEIGHT))
# 绘制棋盘上线。
for y in range(CHESS_MAX_NUM):
# 画横线。
start_pos = REC_SIZE // 2, REC_SIZE // 2 + REC_SIZE * y
end_pos = BOARD_WIDTH - REC_SIZE // 2, REC_SIZE // 2 + REC_SIZE * y
if y == CHESS_MAX_NUM // 2:
width = 2
else:
width = 1
pygame.draw.line(self.__windows, BLACK_COLOR, start_pos,
end_pos, width)
for x in range(CHESS_MAX_NUM):
# 画竖线。
start_pos = REC_SIZE // 2 + REC_SIZE * x, REC_SIZE // 2
end_pos = REC_SIZE // 2 + REC_SIZE * x, BOARD_HEIGHT - REC_SIZE // 2
if x == BOARD_HEIGHT // 2:
width = 2
else:
width = 1
pygame.draw.line(self.__windows, BLACK_COLOR, start_pos,
end_pos, width)
# 绘制棋盘上方块。
rec_size = 8
pos = [(3, 3), (11, 3), (3, 11), (11, 11), (7, 7)]
for x, y in pos:
pygame.draw.rect(self.__windows, BLACK_COLOR,
(REC_SIZE // 2 + REC_SIZE * x - rec_size // 2,
REC_SIZE // 2 + REC_SIZE * y - rec_size // 2,
rec_size, rec_size))
def __draw_chess(self, _steps):
"""绘制已落下的棋子。"""
player_color = {
PlayerEnum.PLAYER_ONE: PLAYER_ONE_COLOR,
PlayerEnum.PLAYER_TWO: PLAYER_TWO_COLOR
}
# 绘制已落下棋子。
for i in range(len(_steps)):
board_pos, turn = _steps[i]
x, y = get_chess_pos(board_pos)
pos = (x + REC_SIZE // 2, y + REC_SIZE // 2)
radius = CHESS_RADIUS
if turn == PlayerEnum.PLAYER_ONE:
op_turn = PlayerEnum.PLAYER_TWO
else:
op_turn = PlayerEnum.PLAYER_ONE
pygame.draw.circle(self.__windows, player_color[turn], pos, radius)
text = Text(None, REC_SIZE * 2 // 3, str(i),
player_color[op_turn], pos)
self.__windows.blit(*text.text_element)
# 圈出最后落下的棋子。
if len(_steps) > 0:
last_pos = _steps[-1]
x, y = get_chess_pos(last_pos[0])
line_list = [(x, y), (x + REC_SIZE, y),
(x + REC_SIZE, y + REC_SIZE),
(x, y + REC_SIZE)]
pygame.draw.lines(self.__windows, PURPLE_COLOR, True, line_list, 1)
def __draw_button(self, _button):
"""绘制游戏界面按钮。"""
self.__windows.fill(_button.color, _button.rect)
self.__windows.blit(*_button.text_element)