-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimulation.py
More file actions
152 lines (130 loc) · 5.37 KB
/
Simulation.py
File metadata and controls
152 lines (130 loc) · 5.37 KB
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
import pygame
import Obstacle
from Settings import Settings
import Car
import Wall
import math
class Simulation:
def __init__(self, scenario: str, drawing: bool = False):
"""
Creates a Simulation object. Doesn't initialize pygame
The creation of a window can be disabled to speed up simulation
:param scenario: path to scenario
:param drawing: if True a pygame window is created and the simulation is drawn on it
"""
self._drawing = drawing
self.running = False
self.window = None
self.display = None
self.obstacles = pygame.sprite.Group()
self.walls = pygame.sprite.Group()
self._scenario = scenario
self.settings = Settings(self._scenario)
self.window_sz = self.settings.window_sz
self.map_sz = self.settings.map_sz
self._start_pos = self.settings.start_pos
self._goal_pos = self.settings.goal_pos
self.car = None
self.result = False # False - collision, True - goal
self.camera = None
def setup(self) -> None:
"""Initializes pygame and creates a window if needed"""
pygame.init()
self.running = True
if self._drawing:
self.window = pygame.display.set_mode(size=self.window_sz)
self.display = pygame.Surface(self.map_sz)
self.obstacles = Obstacle.ObstacleLoader(self._scenario).create_obstacles()
self.car = Car.Car(self)
self._create_walls()
self.camera = Car.Camera(self)
def on_render(self) -> None:
"""Updates all object witihin simulation and draws them"""
self.obstacles.update()
self.walls.update()
self.car.update()
self.camera.update_pos(int(self.car.x), int(self.car.y), self.car.orientation)
self.display.fill((0, 0, 0))
self.obstacles.draw(self.display)
self.walls.draw(self.display)
self._blit_start_goal()
self.car.render()
if self._drawing:
self.window.fill((0, 0, 0))
self.camera.render(self.window)
rect = self.display.get_rect()
rect.topleft = (0, 0)
self.window.blit(self.display, rect)
pygame.display.flip()
def on_event(self, event) -> None:
"""Dispateches events"""
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
self._handle_keydown_events(event)
elif event.type == pygame.KEYUP:
self._handle_keyup_events(event)
elif event.type == pygame.MOUSEBUTTONDOWN:
self._handle_mouse_down(event)
def cleanup(self) -> None:
"""Stops pygame"""
pygame.quit()
def tick(self) -> None:
"""Periodic calls, to progress the simulation"""
for event in pygame.event.get():
self.on_event(event)
collision = self._check_collision()
goal = self._check_goal()
if collision:
self.running = False
self.result = False
if goal:
self.running = False
self.result = True
self.on_render()
def _blit_start_goal(self) -> None:
"""Draws start and goal positions"""
pygame.draw.circle(self.display, (0, 255, 0), self._start_pos, 20)
pygame.draw.circle(self.display, (0, 0, 255), self._goal_pos, 20)
def _handle_mouse_down(self, event) -> None:
"""Prints the position of a mouse click, used to help create scenarios"""
x, y = event.pos
print(f"[{x}, {y}]")
def _handle_keydown_events(self, event) -> None:
"""Used to manually drive the car, along with _handle_keyup_events"""
if event.key == pygame.K_RIGHT:
self.car.ang_spd = -0.2
elif event.key == pygame.K_LEFT:
self.car.ang_spd = +0.2
elif event.key == pygame.K_q:
self.running = False
def _handle_keyup_events(self, event) -> None:
"""Used to manually drive the car, along with _handle_keydown_events"""
if event.key == pygame.K_RIGHT:
self.car.ang_spd = 0
elif event.key == pygame.K_LEFT:
self.car.ang_spd = 0
def _create_walls(self) -> None:
"""Creates the walls for the simulation. The walls are positioned, so the camera is never off-screen"""
space = self.settings.cam_settings['view_sz']/2
w, h = self.map_sz
x_min = space
y_min = space
wall_w = 5
self.walls.add(Wall.Wall((x_min, y_min), wall_w, h)) # left
self.walls.add(Wall.Wall((x_min, y_min), w, wall_w)) # top
self.walls.add(Wall.Wall((w-wall_w, y_min), wall_w, h)) # right
self.walls.add(Wall.Wall((x_min, h-wall_w), w, wall_w)) # bottom
def _check_collision(self) -> bool:
"""Checks collision between car and obstacles and walls"""
coll_wall = pygame.sprite.spritecollideany(self.car, self.walls) is not None
coll_obs = pygame.sprite.spritecollideany(self.car, self.obstacles) is not None
return coll_obs or coll_wall
def _check_goal(self) -> bool:
"""checks if goal has been reached"""
goal_x = self._goal_pos[0]
goal_y = self._goal_pos[1]
car_x = self.car.x
car_y = self.car.y
dist_to_goal = math.sqrt(math.pow(goal_x-car_x, 2) + math.pow(goal_y-car_y, 2))
return dist_to_goal < 20