From 59efcba73e29e928f4f53d1685807d435b1dd69c Mon Sep 17 00:00:00 2001 From: kojtech Date: Sun, 25 Oct 2026 21:22:56 +0100 Subject: [PATCH] Menu done, 3 gamemodes done, 3 enemies spawning done. Deathscreen sooon maybe --- background.png | Bin 0 -> 4614 bytes button.png | Bin 0 -> 2729 bytes button_hover.png | Bin 0 -> 2570 bytes main.py | 320 +++++++++++++++++++++++++++++++++++++---------- panel.png | Bin 0 -> 697 bytes quit.png | Bin 0 -> 2497 bytes quit_hover.png | Bin 0 -> 2511 bytes titles.png | Bin 0 -> 2992 bytes 8 files changed, 254 insertions(+), 66 deletions(-) create mode 100644 background.png create mode 100644 button.png create mode 100644 button_hover.png create mode 100644 panel.png create mode 100644 quit.png create mode 100644 quit_hover.png create mode 100644 titles.png diff --git a/background.png b/background.png new file mode 100644 index 0000000000000000000000000000000000000000..53f42128de941aa7c523bc28da473e23107ff2ff GIT binary patch literal 4614 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 literal 0 HcmV?d00001 diff --git a/button_hover.png b/button_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..45187d8d3d9ff4c55e91a34699da511c972730cd GIT binary patch literal 2570 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 6324704..6b9c0d3 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,8 @@ font = pygame.font.SysFont(None, 36) big_font = pygame.font.SysFont(None, 64) small_font = pygame.font.SysFont(None, 26) +tiny_font = pygame.font.SysFont(None, 20) + MENU_OPTIONS = ["Play", "Quit"] MODE_NAMES = ["easy", "medium", "hard"] @@ -33,7 +35,7 @@ class ChaserEnemy: self.rect.y = random.randint(0, HEIGHT - 36) if abs(self.rect.x - avoid_rect.x) > 150 or abs(self.rect.y - avoid_rect.y) > 150: break - self.speed = 2 + self.speed = 1 self.spawn_timer = 60 def update(self, target): @@ -46,6 +48,10 @@ class ChaserEnemy: elif self.rect.centery > target.centery: self.rect.y -= self.speed class DasherEnemy: + WAIT_BEFORE_FIRST_DASH = 90 + DASH_FRAMES = 30 + WAIT_AFTER_DASH = 120 + DASH_SPEED = 6 def __init__(self, avoid_rect): self.rect = pygame.Rect(0, 0, 36, 36) while True: @@ -58,29 +64,36 @@ class DasherEnemy: self.vx = 0 self.vy = 0 self.state = "wait" - self.timer = 90 + self.timer = self.WAIT_BEFORE_FIRST_DASH self.spawn_timer = 60 def update(self, target): self.timer -= 1 + if self.state == "wait": + if self.timer > 0: + return dx = target.centerx - self.rect.centerx dy = target.centery - self.rect.centery dist = max(1, (dx ** 2 + dy ** 2) ** 0.5) - self.vx = dx / dist * 9 - self.vy = dy / dist * 9 + self.vx = dx / dist * self.DASH_SPEED + self.vy = dy / dist * self.DASH_SPEED self.state = "dash" - self.timer = 30 - else: - self.x += self.vx - self.y += self.vy - self.rect.x = int(self.x) - self.rect.y = int(self.y) - self.rect.clamp_ip(screen.get_rect()) - self.x, self.y = float(self.rect.x), float(self.rect.y) - if self.timer <= 0: - self.state = "wait" - self.timer = 90 + self.timer = self.DASH_FRAMES + return + + self.x += self.vx + self.y += self.vy + self.rect.x = int(self.x) + self.rect.y = int(self.y) + self.rect.clamp_ip(screen.get_rect()) + self.x, self.y = float(self.rect.x), float(self.rect.y) + + if self.timer <= 0: + self.state = "wait" + self.vx = 0 + self.vy = 0 + self.timer = self.WAIT_AFTER_DASH class BouncerEnemy: def __init__(self, avoid_rect): self.rect = pygame.Rect(0, 0, 36, 36) @@ -119,6 +132,12 @@ Chaser_img = pygame.transform.scale(Chaser_img, (30, 45)) Dasher_img = pygame.image.load("Dasher.png").convert_alpha() Dasher_img = pygame.transform.scale(Dasher_img, (30, 45)) +ENEMY_IMAGES = { + "Bouncer": Bouncer_img, + "Dasher": Dasher_img, + "Chaser": Chaser_img +} + sugar_img = pygame.image.load("honey.png").convert_alpha() sugar_img = pygame.transform.scale(sugar_img, (50, 50)) @@ -127,6 +146,19 @@ sugar_img = pygame.transform.scale(sugar_img, (50, 50)) heart_img = pygame.image.load("Heart.png").convert_alpha() heart_img = pygame.transform.scale(heart_img,(40, 40)) +background_img = pygame.image.load("background.png").convert_alpha() +background_img = pygame.transform.scale(background_img, (WIDTH, HEIGHT)) + +title_img = pygame.image.load("titles.png").convert_alpha() + +button_img = pygame.image.load("button.png").convert_alpha() +button_hover_img = pygame.image.load("button_hover.png").convert_alpha() + +quit_img = pygame.image.load("quit.png").convert_alpha() +quit_hover_img = pygame.image.load("quit_hover.png").convert_alpha() + +panel_img = pygame.image.load("panel.png").convert_alpha() + def new_sugar(): return pygame.Rect(random.randint(0, WIDTH - 20), @@ -152,69 +184,225 @@ def game_screen(mode): if event.type == pygame.QUIT: return "quit", score + if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + return "menu", score + + #movement - keys = pygame.key.get_pressed() - if keys[pygame.K_LEFT] or keys[pygame.K_a]: - player.x -= speed - if keys[pygame.K_RIGHT] or keys[pygame.K_d]: - player.x += speed - if keys[pygame.K_UP] or keys[pygame.K_w]: - player.y -= speed - if keys[pygame.K_DOWN] or keys[pygame.K_s]: - player.y += speed + keys = pygame.key.get_pressed() + if keys[pygame.K_LEFT] or keys[pygame.K_a]: + player.x -= speed + if keys[pygame.K_RIGHT] or keys[pygame.K_d]: + player.x += speed + if keys[pygame.K_UP] or keys[pygame.K_w]: + player.y -= speed + if keys[pygame.K_DOWN] or keys[pygame.K_s]: + player.y += speed - for enemy in Enemies: - if enemy.spawn_timer > 0: - enemy.spawn_timer -= 1 - else: - enemy.update(player) - if hit_timer > 0: - hit_timer -= 1 + for enemy in Enemies: + if enemy.spawn_timer > 0: + enemy.spawn_timer -= 1 else: - for enemy in Enemies: - if enemy.spawn_timer <= 0 and player.colliderect(enemy.rect): - lives -= 1 - hit_timer = 90 - break - if lives <= 0: - return "gameover", score + enemy.update(player) + if hit_timer > 0: + hit_timer -= 1 + else: + for enemy in Enemies: + if enemy.spawn_timer <= 0 and player.colliderect(enemy.rect): + lives -= 1 + hit_timer = 90 + break + if lives <= 0: + return "gameover", score #keep player in - player.clamp_ip(screen.get_rect()) + player.clamp_ip(screen.get_rect()) # score - if player.colliderect(sugar): - score += 1 - sugar = new_sugar() - if score % cfg["spawn_every"] == 0 and cfg["enemy_pool"]: - enemy_name = random.choice(cfg["enemy_pool"]) - Enemies.append(ENEMY_CLASSES[enemy_name](player)) + if player.colliderect(sugar): + score += 1 + sugar = new_sugar() + if score % cfg["spawn_every"] == 0 and cfg["enemy_pool"]: + enemy_name = random.choice(cfg["enemy_pool"]) + enemy = ENEMY_CLASSES[enemy_name](player) + enemy.image = ENEMY_IMAGES[enemy_name] + Enemies.append(enemy) - screen.fill((255, 228, 240)) # screen - screen.blit(sugar_img, sugar) #sugar - screen.blit(player_img, player) #player - if hit_timer % 10 < 5: - screen.blit(player_img, player) - text = font.render(f"score: {score}", True, (90, 30, 60)) - screen.blit(text, (10, 10)) - for enemy in Enemies: - if enemy.spawn_timer % 10 < 5: - screen.blit(Bouncer_img, enemy.rect) - screen.blit(player_img, player) - if hit_timer > 0 and hit_timer % 10 < 5: - red = player_img.copy() - red.fill((255, 40, 40, 0), special_flags=pygame.BLEND_RGBA_ADD) - screen.blit(red, player) - for i in range(lives): - screen.blit(heart_img, (10 + i * 35, 40)) - pygame.display.flip() - clock.tick(60) -pygame.quit() + screen.fill((255, 228, 240)) # screen + screen.blit(sugar_img, sugar) #sugar + text = font.render(f"score: {score}", True, (90, 30, 60)) + screen.blit(text, (10, 10)) + for enemy in Enemies: + if enemy.spawn_timer % 10 < 5: + screen.blit(enemy.image, enemy.image.get_rect(center=enemy.rect.center)) + screen.blit(player_img, player) + if hit_timer > 0 and hit_timer % 10 < 5: + red = player_img.copy() + red.fill((255, 40, 40, 0), special_flags=pygame.BLEND_RGBA_ADD) + screen.blit(red, player) + for i in range(lives): + screen.blit(heart_img, (10 + i * 35, 40)) + pygame.display.flip() + clock.tick(60) + + + +class MenuButton: + def __init__(self, center, action, image, hover_image): + self.action = action + self.image = image + self.hover_image = hover_image + self.rect = self.image.get_rect(center = center) + + def hovered(self, mouse_pos): + return self.rect.collidepoint(mouse_pos) + + def draw(self, surface, highlighted): + picture = self.hover_image if highlighted else self.image + surface.blit(picture, self.rect) def menu_screen(): selected = 0 + + buttons = [ + MenuButton((WIDTH // 2, 250), "mode", button_img, button_hover_img), + MenuButton((WIDTH // 2, 340), "quit", quit_img, quit_hover_img), + ] + + while True: - for + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return "quit" + + if event.type == pygame.KEYDOWN: + if event.key in (pygame.K_UP, pygame.K_w): + selected = (selected - 1) % len(buttons) + elif event.key in (pygame.K_DOWN, pygame.K_s): + selected = (selected + 1) % len(buttons) + elif event.key == pygame.K_RETURN: + if selected == -1: + selected = 0 + return buttons [selected].action + elif event.key == pygame.K_ESCAPE: + return "quit" + + if event.type == pygame.MOUSEMOTION: + selected = -1 + for i, button in enumerate(buttons): + if button.hovered(event.pos): + selected = i + + if event.type == pygame.WINDOWLEAVE: + selected = -1 + + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: + for button in buttons: + if button.hovered(event.pos): + return button.action + + screen.blit(background_img, (0, 0)) + screen.blit(title_img, title_img.get_rect(center=(WIDTH // 2, 80))) + + for i, button in enumerate(buttons): + button.draw(screen, i == selected) + pygame.display.flip() + clock.tick(60) + +def mode_screen(): + selected = 0 + hovered = -1 + + play_button = MenuButton((210, 405), "game", button_img, button_hover_img) + back_button = MenuButton((430, 405), "menu", quit_img, quit_hover_img) + buttons = [play_button, back_button] + + panel_rect = panel_img.get_rect(center=(WIDTH // 2, 225)) + slot_rects = [ + pygame.Rect(panel_rect.x + 22, panel_rect.y + 22, 78, 68), + pygame.Rect(panel_rect.x + 133, panel_rect.y + 22, 77, 68), + pygame.Rect(panel_rect.x + 234, panel_rect.y + 28, 73, 66), + ] + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return "quit", None + + if event.type == pygame.KEYDOWN: + if event.key in (pygame.K_LEFT, pygame.K_a): + selected = (selected - 1) % len(MODE_NAMES) + elif event.key in (pygame.K_RIGHT, pygame.K_d): + selected = (selected + 1) % len(MODE_NAMES) + elif event.key == pygame.K_RETURN: + return "game", MODE_NAMES[selected] + elif event.key == pygame.K_ESCAPE: + return "menu", None + + if event.type == pygame.MOUSEMOTION: + hovered = -1 + for i, button in enumerate(buttons): + if button.hovered(event.pos): + hovered = i + + if event.type == pygame.WINDOWLEAVE: + hovered = -1 + + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: + for i, slot in enumerate(slot_rects): + if slot.collidepoint(event.pos): + selected = i + for button in buttons: + if button.hovered(event.pos): + if button.action == "game": + return "game", MODE_NAMES[selected] + return "menu", None + + screen.blit(background_img, (0, 0)) + screen.blit(title_img, title_img.get_rect(center=(WIDTH // 2, 70))) + + pygame.draw.rect(screen, (255, 129, 195), panel_rect) + screen.blit(panel_img, panel_rect) + + for i, slot in enumerate(slot_rects): + fill = (255, 200, 225) if i == selected else (227, 89, 161) + pygame.draw.rect(screen, fill, slot.inflate (-4, -4), border_radius=6) + + for i, slot in enumerate(slot_rects): + name = small_font.render(MODE_NAMES[i].upper(), True, (255, 240, 8)) + screen.blit(name, name.get_rect(center=slot.center)) + + cfg = MODES[MODE_NAMES[selected]] + first_sentence, second_sentence = cfg["desc"].split(". ", 1) + line1 = tiny_font.render(first_sentence + ".", True, (255, 240, 8)) + line2 = tiny_font.render(second_sentence, True, (255, 240, 8)) + screen.blit(line1, line1.get_rect(center=(panel_rect.centerx, panel_rect.top + 108))) + screen.blit(line2, line2.get_rect(center=(panel_rect.centerx, panel_rect.top + 132))) + + for i, button in enumerate(buttons): + button.draw(screen, i == hovered) + + pygame.display.flip() + clock.tick(60) + + +if __name__ == "__main__": + state = "menu" + mode = None + score = 0 + + while state != "quit": + if state == "menu": + state = menu_screen() + elif state == "mode": + state, mode = mode_screen() + elif state == "game": + state, score = game_screen(mode) + elif state == "gameover": + print(f"Game Over - score: {score}") + state = "menu" + + pygame.quit() diff --git a/panel.png b/panel.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c4cbb0d17ea33649d48c061dfc20f276011fc0 GIT binary patch literal 697 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