-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrajectory_simulation.py
234 lines (197 loc) · 10.8 KB
/
trajectory_simulation.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
import pygame
from trajectory import draw_trajectory, draw_aim
from level import level
from save import display_life
screen_width, screen_height = 1536, 864
fps = 120
class TrajectorySimulation:
def __init__(self, circle_radius, screen, screen_width, screen_height, background_image):
self.transparent_surface = pygame.Surface((1536, 864), pygame.SRCALPHA)
self.circle_radius = circle_radius
self.screen = screen
self.screen_width = screen_width
self.screen_height = screen_height
self.sound_played = False
self.background_image = pygame.transform.scale(background_image, (screen_width, screen_height))
def level_display(self, level_number, full_level, time_step, level_attempts, rocket_x, rocket_y, object_state,
modified_obstacles=[]):
"""
Draw a level on a screen.
Parameters
----------
level_number(int) : Current level
full_level(bool) : Indicates whether the level should be fully displayed
time_step(int) : Current frame for character animation
level_attempts(int): Number of attempts left for the current level
rocket_x(int) : Initial x-coordinate
rocket_y(int) : Initial y-coordinate
object_state(bool) : True if the object should be on, otherwise False
modified_obstacles(list, optional) : List of modified obstacles
Returns
-------
orbit_radius(int) : The orbit's radius
position(tuple) : Coordinates of the planet
obstacles(list) : List of all the obstacles in the level
portals(list) : List of infos about the portals
"""
# Paths to the asteroid images
asteroid_paths = [
"Assets/Level/Asteroids/asteroid_1.png",
"Assets/Level/Asteroids/asteroid_2.png",
"Assets/Level/Asteroids/asteroid_3.png",
"Assets/Level/Asteroids/asteroid_4.png"
]
# Load asteroid images
asteroid_images = []
for path in asteroid_paths:
img = pygame.image.load(path).convert_alpha()
img = pygame.transform.scale(img, (48, 48))
asteroid_images.append(img)
# Index to keep track of current asteroid image
asteroid_index = 0
# Collect the level info and print it
orbit_radius, position, obstacles, objects ,portals = level(level_number, self.screen, self.transparent_surface,
time_step, rocket_x, rocket_y, object_state)
if len(obstacles) > len(modified_obstacles) and not full_level:
for obstacle, number in modified_obstacles:
# Determine the index of the asteroid image to be used based on the number associated with the obstacle
asteroid_index = (number - 1) % len(asteroid_images)
# Draw scaled asteroid image instead of rectangle
self.transparent_surface.blit(asteroid_images[asteroid_index], obstacle)
else:
for obstacle, number in obstacles:
# Determine the index of the asteroid image to be used based on the number associated with the obstacle
asteroid_index = (number - 1) % len(asteroid_images)
# Draw scaled asteroid image instead of rectangle
self.transparent_surface.blit(asteroid_images[asteroid_index], obstacle)
if portals :
portal_input_img = pygame.image.load("Assets/Level/Items/portal_in.png").convert_alpha()
portal_input_img = pygame.transform.scale(portal_input_img, (portals[0][2], portals[0][2]))
self.transparent_surface.blit(portal_input_img, (portals[0][0], portals[0][1]))
portal_ouput_img = pygame.image.load("Assets/Level/Items/portal_out.png").convert_alpha()
portal_ouput_img = pygame.transform.scale(portal_ouput_img, (portals[1][2], portals[1][2]))
self.transparent_surface.blit(portal_ouput_img, (portals[1][0], portals[1][1]))
for object in objects:
# Draw a shield icon for objects
if object[0] == "shield":
# Load and blit shield icon
shield_icon_img = pygame.image.load("Assets/Level/Items/shield_icon.png").convert_alpha()
shield_icon_img = pygame.transform.scale(shield_icon_img, (40, 40))
self.transparent_surface.blit(shield_icon_img, object[1])
# Draw a lamp icon for objects
if object[0] == "lamp":
# Load and blit lamp icon
lamp_icon_img = pygame.image.load("Assets/Level/Items/lamp.png").convert_alpha()
lamp_icon_img = pygame.transform.scale(lamp_icon_img, (50, 22))
self.transparent_surface.blit(lamp_icon_img, object[1])
display_life((3 - level_attempts), self.screen, "Assets/astronaut_image.png")
return orbit_radius, position, obstacles, objects, portals
def projectile_aim(self, g, v, h, alpha, time_step, level_number, level_attempts, object_status):
"""
Display the aim trajectory on the screen.
Parameters
----------
g(int) : Gravitational acceleration
v(int) : Initial velocity
h(int) : Initial height
alpha(int) : Launch angle in degrees
time_step(int): Current frame for character animation
level_number(int) : Current level number
object_status(bool) : True if the object should be on, otherwise False
Returns
-------
None
"""
self.screen.blit(self.background_image, (0, 0))
self.level_display(level_number, True, time_step, level_attempts, 0, screen_height, object_status)
draw_aim(self.screen, g, v, h, alpha, self.circle_radius, self.screen_height, 22)
def projectile_motion(self, rocket_x, rocket_y, g, v, h, alpha, level_number, level_attempts, clock, object_state):
"""
Display the motion of the projectile.
Parameters
----------
rocket_x(int) : Initial x-coordinate
rocket_y(int) : Initial y-coordinate
g(int) : Gravitational acceleration
v(int) : Initial velocity
h(int) : Initial height
alpha(int) : Launch angle in degrees
level_number(int) : Current level number
level_attempts(int) : Number of attempts on the current level
object_state(bool) : True if the object should be on, otherwise False
Returns
-------
shooting_trajectory(bool) : Indicates whether the projectile is still in motion
bool : Indicates whether the projectile has successfully hit the target
level_attemps(int) : Number of attempts in the level
"""
# Reset timer and position for shooting
time_step = 0
shooting_trajectory = False
object_status = False
teleport = False
orbit_radius, position, obstacles, objects, portals = self.level_display(level_number, True, time_step, level_attempts,
rocket_x, rocket_y, object_state)
# 'For' loop to avoid code locking with while and optimization in case of bugs, will stop after 1000 steps
for steps in range(1000):
if not (0 <= rocket_x <= screen_width and 0 <= rocket_y <= screen_height):
level_attempts += 1
sound = pygame.mixer.Sound("Assets/Music/asteroid_crash.mp3")
sound.set_volume(0.4)
sound.play()
self.sound_played = False
self.transparent_surface.fill((0, 0, 0, 0))
return shooting_trajectory, False, True, level_attempts, object_state
self.screen.blit(self.background_image, (0, 0))
self.level_display(level_number, False, time_step, level_attempts, rocket_x, rocket_y, object_state,
obstacles)
# Check for collisions with obstacles
for obstacle in obstacles:
if obstacle[0].collidepoint(rocket_x, rocket_y):
if not object_status:
level_attempts += 1
sound = pygame.mixer.Sound("Assets/Music/asteroid_crash.mp3")
sound.set_volume(0.4)
sound.play()
self.transparent_surface.fill((0, 0, 0, 0))
self.sound_played = False
return shooting_trajectory, False, True, level_attempts, object_state
else:
# Removes the obstacle if it touched with an object
obstacles.remove(obstacle)
self.transparent_surface.blit(self.background_image, (0, 0))
object_status = False
# Check for collisions with objects
for object in objects:
if object[1].collidepoint(rocket_x, rocket_y):
if not self.sound_played:
sound = pygame.mixer.Sound("Assets/Music/item_pick.mp3")
sound.set_volume(0.2)
sound.play()
self.sound_played = True
if object[0] == "shield":
object_status = True
if object[0] == "lamp":
object_state = True
# Draw a circle around the ball to indicate it has an object
if object_status:
shield_image = (pygame.image.load('Assets/Level/Items/shield.png'))
shield_image = pygame.transform.scale(shield_image, (50, 50))
shield_rect = shield_image.get_rect(center=(rocket_x, rocket_y))
self.screen.blit(shield_image, shield_rect)
# Call the draw_trajectory function from trajectory.py to change coordinates with the portal
if portals:
rocket_x, rocket_y, teleport = draw_trajectory(self.screen, g, v, h, alpha, time_step,
self.screen_height,True, teleport, portals[0],
portals[1])
else:
rocket_x, rocket_y, teleport = draw_trajectory(self.screen, g, v, h, alpha, time_step,
self.screen_height, False, False)
pygame.display.update()
time_step += clock.tick(fps) / 180 # Increment time step for the next iteration
# Check if the projectile enters the planet's orbit
if (rocket_x - position[0]) ** 2 + (rocket_y - position[1]) ** 2 <= orbit_radius ** 2:
shooting_trajectory = False
self.transparent_surface.fill((0, 0, 0, 0))
return shooting_trajectory, True, False, level_attempts, object_state
return shooting_trajectory, False, True, level_attempts, object_state