-
Notifications
You must be signed in to change notification settings - Fork 0
/
gui.py
318 lines (259 loc) · 12.9 KB
/
gui.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
import os
import sys
import pygame
from util import *
from classes import *
from paths import pathTypes
from copy import deepcopy
folder = os.path.dirname(os.path.realpath(__file__))
background = os.path.join(folder, "background.jpg")
IMG_WIDTH = 1487
IMG_HEIGHT = 1006
SCALE = 0.5
class GUI():
def __init__(self):
pygame.init()
pygame.font.init()
pygame.display.set_caption("Paul")
self.window = pygame.display.set_mode((int(IMG_WIDTH * SCALE), int(IMG_HEIGHT * SCALE)))
self.bg = pygame.image.load(background).convert_alpha()
self.white = (255, 255, 255)
self.orange = (255, 150, 0)
self.blue = (0, 120, 255)
self.black = (0, 0, 0)
self.purple = (148, 0, 211)
self.red = (255, 0, 0)
self.green = (0, 255, 0)
self.grey = (150, 150, 150)
self.event_text = pygame.font.Font('freesansbold.ttf', 10)
self.editing = True # a new path will replace the existing path
self.event_editing = False # locks newlines and editing
self.new_line = False
def update(self, game, agent):
# start and end are flags for mouse events, arm is for triggering an event edit or creating a new event
start_flag = end_flag = arm_edit = arm_new = up_flag = down_flag = False
close_event = None
# drawing background
self.render(self.bg, 0, 0, int(IMG_WIDTH * SCALE), int(IMG_HEIGHT * SCALE))
# recording mouse events
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 or event.button == 3:
start_flag = True
elif event.button == 4:
# up scroll
up_flag = True
elif event.button == 5:
# down scroll
down_flag = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1 or event.button == 3:
end_flag = True
self.new_line = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
agent.path = deepcopy(pathTypes.basicShot)
elif event.key == pygame.K_2:
agent.path = pathTypes.basicShot
elif event.key == pygame.K_3:
agent.path = pathTypes.basicShot
elif event.key == pygame.K_4:
agent.path = pathTypes.basicShot
elif event.key == pygame.K_5:
agent.path = pathTypes.basicShot
if event.type == pygame.QUIT: # no more hanging on exit
pygame.quit()
sys.exit()
mouse_position = pygame.mouse.get_pos()
mouse_buttons = pygame.mouse.get_pressed()
if len(agent.path.lines) > 0:
# Drawing path and finding closest line to the mouse
close_dist = dist2d(line_projection(*agent.path.get_points(), self.game_coords(mouse_position)),
self.game_coords(mouse_position))
close_line = agent.path.get_line()
for item in agent.path.lines:
temp = dist2d(line_projection(item.start, item.end, self.game_coords(mouse_position)),
self.game_coords(mouse_position))
if temp < close_dist:
close_dist = temp
close_line = item
self.line(self.gui_coords(*a2(item.start)), self.gui_coords(*a2(item.end)), self.purple)
# draws events on line
for event in item.events:
event_loc = set_dist2d(item.start, item.end, event.distance)
self.circle(*self.gui_coords(*a2(event_loc)), 2, self.black)
# drawing the mouse projection
mouse_distance = dist2d(close_line.start, line_projection(
close_line.start, close_line.end, self.game_coords(mouse_position)))
# arming event_editing, causes start flag to trigger editing mode instead of newline
if (close_dist < 200 and mouse_distance - 50 < dist2d(close_line.start, close_line.end) and
dist2d(line_projection(close_line.start, close_line.end, self.game_coords(mouse_position)),
close_line.end) - 50 < dist2d(close_line.start, close_line.end)):
# changing the projection circle color if we are over a line or event
highlight = self.black
for event in close_line.events:
if event.distance + 50 > mouse_distance and event.distance - 50 < mouse_distance:
if start_flag:
event.active_editing = True
arm_edit = True
close_event = event
highlight = self.blue
break
elif event.active_editing:
highlight = self.blue
break
if not arm_edit:
if close_dist < 70:
highlight = self.green
arm_new = True
self.circle(*self.gui_coords(*line_projection(close_line.start, close_line.end,
self.game_coords(mouse_position))), 5, highlight, 2)
# entry circle
if hasattr(agent, "circle_center"):
self.circle(*self.gui_coords(*a2(agent.circle_center)),
self.gui_rescale(agent.circle_radius), self.grey, 1)
# Flags and Mouse clicks are handled below
# Drawing with the rightmousebutton turns editing back on so that a new path can be created
if self.editing:
if start_flag:
self.line_start = mouse_position
if end_flag:
self.line_end = mouse_position
if mouse_buttons[2] == 1 or mouse_buttons[0] == 1:
self.line(self.line_start, mouse_position, self.purple)
if self.new_line:
temp = line(a3([*self.game_coords(self.line_start), 20]),
a3([*self.game_coords(self.line_end), 20]), 1400)
agent.path = path([temp])
self.editing = False
self.new_line = False
elif self.event_editing:
if mouse_buttons[0] == 1:
for event in close_line.events:
if event.active_editing and not event.anchored:
event.distance = mouse_distance
if end_flag is True:
for event in close_line.events:
event.active_editing = False
self.event_editing = False
else:
if start_flag:
if arm_new:
close_line.events.append(Event(mouse_distance, 1400))
elif arm_edit:
self.event_editing = True
self.editing = False
else:
self.line_start = mouse_position
elif end_flag:
self.line_end = mouse_position
if mouse_buttons[2] == 1:
self.line(self.line_start, mouse_position, self.purple)
self.editing = True
agent.path.clean()
if mouse_buttons[0] == 1:
if not arm_new and not arm_edit:
self.line(self.line_start, mouse_position, self.purple)
else:
self.new_line = False
if self.new_line:
if not arm_new and not arm_edit:
temp = line(a3([*self.game_coords(self.line_start), 20]),
a3([*self.game_coords(self.line_end), 20]), 1400)
agent.path.lines.append(temp)
self.editing = False
self.new_line = False
else:
self.new_line = False
if up_flag and close_event is not None:
close_event.speed += 10
elif down_flag and close_event is not None:
close_event.speed -= 10
ball_loc = game.gameball.Location
# drawing the ball
self.circle(*self.gui_coords(ball_loc.X, ball_loc.Y), 5, self.black)
# drawing each car
for i in range(game.numCars):
car = game.gamecars[i]
if car.Team == 0:
car_color = self.blue
else:
car_color = self.orange
self.circle(*self.gui_coords(car.Location.X, car.Location.Y), 5, car_color)
# player only
if i == agent.index and len(agent.path.lines) > 0:
# drawing nearest point on the user-made line
line_projected_point = line_projection(*agent.path.get_points(), (car.Location.X, car.Location.Y))
self.circle(*self.gui_coords(*line_projected_point), 1, car_color)
# drawing lines to both goals
for team in range(2):
# enemy near post location (2D)
near_post = (GOAL_WIDTH / 2 * sign(ball_loc.X), FIELD_LENGTH / 2 * sign(team))
far_post = ((GOAL_WIDTH / 2 - BALL_RADIUS) * -sign(ball_loc.X), FIELD_LENGTH / 2 * sign(team))
# drawing a circle around the near post
self.circle(*self.gui_coords(*near_post), 5, self.white, 1)
tangent_x, tangent_y = tangent_point(near_post, BALL_RADIUS, ball_loc, sign(team) * sign(ball_loc.X))
# (ball, tangent_point) line intersection with the the goal line
x_point = line_intersect([(1, near_post[1]), (-1, near_post[1])], [(ball_loc.X, ball_loc.Y),
(tangent_x, tangent_y)])[0]
# extending the lines from starting point by a fixed ammount
line_length = 11000
extended_tangent_point = set_dist2d([x_point, near_post[1]], ball_loc, line_length)
extended_far_point = set_dist2d(far_post, ball_loc, line_length)
if team == 0:
line_color = self.blue
else:
line_color = self.orange
# drawing tangent line passing near post
self.line(self.gui_coords(x_point, near_post[1]), self.gui_coords(*extended_tangent_point), line_color)
# drawing line to far post
self.line(self.gui_coords(*far_post), self.gui_coords(*extended_far_point), line_color)
# drawing near post entrance indication point
self.circle(*self.gui_coords(x_point, near_post[1]), 1, self.white)
# drawing far post indication point
self.circle(*self.gui_coords(*far_post), 1, self.white)
if hasattr(agent, "player_circle"):
# drawing the circle showing the current min turn radius
self.circle(*self.gui_coords(*a2(agent.player_circle)),
self.gui_rescale(agent.player_radius), self.purple, 1)
# This draws the point the agent is currently targeting
self.circle(*self.gui_coords(*a2(agent.target_loc)), 2, self.red)
if arm_edit:
self.draw_event_box(close_event, *mouse_position)
pygame.display.update()
def post_update(self, agent):
pygame.display.update()
def draw_event_box(self, event, x, y):
text = []
text.append(str(int(event.distance)))
text.append(str(event.speed))
self.rectangle(x + 10, y + 10, 50, 40, self.grey)
height = 0
for z in text:
text_surface = pygame.font.Font.render(self.event_text, z, True, self.black)
text_rect = text_surface.get_rect()
text_rect.x = x + 15
text_rect.y = y + 15 + (10 * height)
self.window.blit(text_surface, text_rect)
height += 1
def rectangle(self, x, y, width, height, color):
pygame.draw.rect(self.window, color, (x, y, width, height))
def circle(self, x, y, radius, color, outline=0):
pygame.draw.circle(self.window, color, (x, y), radius, outline)
def line(self, point1, point2, color):
pygame.draw.line(self.window, color, point1, point2)
def render(self, image, x, y, width, height):
image = pygame.transform.scale(image, (width, height))
surface = pygame.Rect(x, y, width, height)
self.window.blit(image, surface)
# rescales from game to gui size
def gui_rescale(self, x):
return int(x * 0.11763 * SCALE)
def x_coord(self, x):
return int((x * 0.11693 + 744) * SCALE)
def y_coord(self, y):
return int((-y * 0.11833 + 505) * SCALE)
def gui_coords(self, x, y): # converts 2d coordinates from the game to the gui
return self.x_coord(y), self.y_coord(x)
def game_coords(self, point): # converts a point/pixel in the gui to game coordinates
return (-(point[1] / SCALE - 505) / 0.11833, (point[0] / SCALE - 744) / 0.11693)