2
0

2 Коммиты 3138bbd665 ... 6b6ed88f1a

Автор SHA1 Сообщение Дата
  michal.korcak 6b6ed88f1a refactor and improved collision 6 дней назад
  michal.korcak f209ac14ce maze and colision 6 дней назад
6 измененных файлов с 119 добавлено и 40 удалено
  1. 44 40
      main.py
  2. 29 0
      maze.py
  3. BIN
      meteor.png
  4. BIN
      requirements.txt
  5. 16 0
      rocket.py
  6. 30 0
      utils.py

+ 44 - 40
main.py

@@ -1,39 +1,38 @@
+import random
 import pygame
 
-# pygame setup
+from utils import get_empty_cells, get_cell_center, draw_arrow
+from maze import generate_maze, get_meteor_rects, draw_maze
+from rocket import load_rocket, rescale_rocket
+
+# --- pygame setup ---
 pygame.init()
 screen = pygame.display.set_mode((1280, 720))
 clock = pygame.time.Clock()
 running = True
 dt = 0
 
+# --- physics constants ---
 force_coef = 20
-player_applied_force = pygame.Vector2(0, 0)
 player_mass = 1
-player_pos = pygame.Vector2(screen.get_width() / 2, screen.get_height() / 2)
-player_speed = pygame.Vector2(0, 0)
-
-raketa_original = pygame.image.load("raketa.png").convert_alpha()
-raketa = pygame.transform.scale(raketa_original, (raketa_original.get_width() // 3, raketa_original.get_height() // 3))
 
+# --- maze setup ---
+maze_grid = generate_maze(width=7, height=4)
 
-def draw_arrow(surface, color, start, end, width=3):
-    pygame.draw.line(surface, color, start, end, width)
-    direction = (end - start).normalize()
-    arrow_size = 10
-    perpendicular = pygame.Vector2(-direction.y, direction.x)
-    point1 = end - direction * arrow_size + perpendicular * arrow_size / 2
-    point2 = end - direction * arrow_size - perpendicular * arrow_size / 2
-    pygame.draw.polygon(surface, color, [end, point1, point2])
+# --- player spawn ---
+empty_cells = get_empty_cells(maze_grid)
+spawn_x, spawn_y = random.choice(empty_cells)
+player_pos = get_cell_center(spawn_x, spawn_y)
+player_speed = pygame.Vector2(0, 0)
+player_applied_force = pygame.Vector2(0, 0)
 
-def rescale_rocket(raketa, speed):
-    scale_factor = 1 + player_speed.length() * 0.01
-    raketa_w, raketa_h = raketa.get_size()
-    raketa_w *= scale_factor
-    raketa_h /= scale_factor
-    scaled_raketa = pygame.transform.scale(raketa, (raketa_h, raketa_w))
-    return scaled_raketa
+# --- assets ---
+raketa = load_rocket()
+meteor_img = pygame.image.load("meteor.png").convert_alpha()
+meteor_scaled = pygame.transform.scale(meteor_img, (80, 80))
+meteor_mask = pygame.mask.from_surface(meteor_scaled)
 
+# --- game loop ---
 while running:
     for event in pygame.event.get():
         if event.type == pygame.QUIT:
@@ -41,17 +40,8 @@ while running:
 
     screen.fill("purple")
 
-    angle = player_speed.angle_to(pygame.Vector2(0, -1))
-
-    scaled_raketa = rescale_rocket(raketa, player_speed)
-
-    rotated_raketa = pygame.transform.rotate(scaled_raketa, angle)
-
-    raketa_rect = rotated_raketa.get_rect(center=player_pos)
-    screen.blit(rotated_raketa, raketa_rect)
-
+    # Input
     player_applied_force = pygame.Vector2(0, 0)
-
     keys = pygame.key.get_pressed()
     if keys[pygame.K_w]:
         player_applied_force.y -= force_coef
@@ -61,23 +51,37 @@ while running:
         player_applied_force.x -= force_coef
     if keys[pygame.K_d]:
         player_applied_force.x += force_coef
-
     if player_applied_force.length() > 0:
         player_applied_force.scale_to_length(force_coef)
 
+    # Physics
     acceleration = player_applied_force / player_mass
     player_speed += acceleration * dt
     player_pos += player_speed * dt
 
-    # Draw force arrow
-    if player_applied_force.length() > 0:
-        arrow_end = player_pos + player_applied_force * 2
-        draw_arrow(screen, "yellow", player_pos, arrow_end)
+    # Collision detection
+    scaled_raketa = rescale_rocket(raketa, player_speed)
+    angle = player_speed.angle_to(pygame.Vector2(0, -1))
+    rotated_raketa = pygame.transform.rotate(scaled_raketa, angle)
+    raketa_rect = rotated_raketa.get_rect(center=player_pos)
+    raketa_mask = pygame.mask.from_surface(rotated_raketa)
+
+    for meteor_rect in get_meteor_rects(maze_grid):
+        if raketa_rect.colliderect(meteor_rect):
+            offset = (meteor_rect.x - raketa_rect.x, meteor_rect.y - raketa_rect.y)
+            if raketa_mask.overlap(meteor_mask, offset):
+                player_speed = pygame.Vector2(0, 0)
+                break
+
+    # Draw
+    screen.blit(rotated_raketa, raketa_rect)
 
-    # Draw speed arrow
+    if player_applied_force.length() > 0:
+        draw_arrow(screen, "yellow", player_pos, player_pos + player_applied_force * 2)
     if player_speed.length() > 0:
-        arrow_end = player_pos + player_speed * 2
-        draw_arrow(screen, "cyan", player_pos, arrow_end)
+        draw_arrow(screen, "cyan", player_pos, player_pos + player_speed * 2)
+
+    draw_maze(screen, maze_grid, meteor_img)
 
     pygame.display.flip()
     dt = clock.tick(60) / 1000

+ 29 - 0
maze.py

@@ -0,0 +1,29 @@
+import pygame
+from mazelib import Maze
+from mazelib.generate.Prims import Prims
+
+
+def generate_maze(width, height):
+    m = Maze()
+    m.generator = Prims(height, width)
+    m.generate()
+    return m.grid
+
+
+def get_meteor_rects(grid, cell_size=80):
+    meteor_rects = []
+    for y, row in enumerate(grid):
+        for x, cell in enumerate(row):
+            if cell == 1:
+                rect = pygame.Rect(x * cell_size, y * cell_size, cell_size, cell_size)
+                meteor_rects.append(rect)
+    return meteor_rects
+
+
+def draw_maze(surface, grid, meteor_img, cell_size=80):
+    scaled = pygame.transform.scale(meteor_img, (cell_size, cell_size))
+    for y, row in enumerate(grid):
+        for x, cell in enumerate(row):
+            if cell == 1:
+                rect = pygame.Rect(x * cell_size, y * cell_size, cell_size, cell_size)
+                surface.blit(scaled, rect)


BIN
requirements.txt


+ 16 - 0
rocket.py

@@ -0,0 +1,16 @@
+import pygame
+
+
+def load_rocket(path="raketa.png", scale=3):
+    original = pygame.image.load(path).convert_alpha()
+    return pygame.transform.scale(
+        original, (original.get_width() // scale, original.get_height() // scale)
+    )
+
+
+def rescale_rocket(raketa, speed):
+    scale_factor = 1 + speed.length() * 0.01
+    raketa_w, raketa_h = raketa.get_size()
+    raketa_w *= scale_factor
+    raketa_h /= scale_factor
+    return pygame.transform.scale(raketa, (raketa_h, raketa_w))

+ 30 - 0
utils.py

@@ -0,0 +1,30 @@
+import pygame
+
+
+def get_empty_cells(grid):
+    """
+    Returns a list of (x, y) tuples for cells in grid that are empty (value 0).
+    """
+    empty = []
+    for y, row in enumerate(grid):
+        for x, cell in enumerate(row):
+            if cell == 0:
+                empty.append((x, y))
+    return empty
+
+
+def get_cell_center(x, y, cell_size=80):
+    """
+    Converts cell coordinates (x, y) to pixel coordinates of the cell center.
+    """
+    return pygame.Vector2(x * cell_size + cell_size / 2, y * cell_size + cell_size / 2)
+
+
+def draw_arrow(surface, color, start, end, width=3):
+    pygame.draw.line(surface, color, start, end, width)
+    direction = (end - start).normalize()
+    arrow_size = 10
+    perpendicular = pygame.Vector2(-direction.y, direction.x)
+    point1 = end - direction * arrow_size + perpendicular * arrow_size / 2
+    point2 = end - direction * arrow_size - perpendicular * arrow_size / 2
+    pygame.draw.polygon(surface, color, [end, point1, point2])