Update main.py

main
Romans Zubenko 2026-03-16 07:19:24 +00:00
parent aa1e623876
commit bfb2404349
1 changed files with 347 additions and 315 deletions

112
main.py
View File

@ -16,7 +16,6 @@ def load_s(path, size, alpha=True):
img = pygame.image.load(path).convert_alpha() if alpha else pygame.image.load(path).convert() img = pygame.image.load(path).convert_alpha() if alpha else pygame.image.load(path).convert()
return pygame.transform.scale(img, size) return pygame.transform.scale(img, size)
except: except:
# Если файл не найден, создаем заглушку
s = pygame.Surface(size); s.fill((100, 100, 100)); return s s = pygame.Surface(size); s.fill((100, 100, 100)); return s
# --- Загрузка ресурсов --- # --- Загрузка ресурсов ---
@ -35,7 +34,6 @@ lane_height = 100
line_thickness = 4 line_thickness = 4
total_height = 4 * line_thickness + 3 * lane_height total_height = 4 * line_thickness + 3 * lane_height
start_y = (SCREEN_HEIGHT - total_height) // 2 start_y = (SCREEN_HEIGHT - total_height) // 2
# lane_centers — это Y-координаты центров трёх дорожек
lane_centers = [start_y + line_thickness + i * (lane_height + line_thickness) + lane_height // 2 for i in range(3)] lane_centers = [start_y + line_thickness + i * (lane_height + line_thickness) + lane_height // 2 for i in range(3)]
class Player(pygame.sprite.Sprite): class Player(pygame.sprite.Sprite):
@ -108,45 +106,63 @@ class Boss(pygame.sprite.Sprite):
self.dir = 1 self.dir = 1
self.move_timer = pygame.time.get_ticks() self.move_timer = pygame.time.get_ticks()
self.state = "NORMAL" self.state = "NORMAL"
self.move_delay = 2000 # Начальная задержка движения self.move_delay = 2000
self.fire_rate_mod = 1.0 self.fire_rate_mod = 1.0
self.grow_start = 0 self.grow_start = 0
# Параметры анимации смерти
self.death_size = 100
self.death_center_x = 0
self.death_center_y = 0
def update(self): def update(self):
now = pygame.time.get_ticks() now = pygame.time.get_ticks()
if self.state == "NORMAL": if self.state == "NORMAL":
# Проверка таймера перемещения
if now - self.move_timer > self.move_delay: if now - self.move_timer > self.move_delay:
self.lane += self.dir self.lane += self.dir
if self.lane < 0 or self.lane > 2: if self.lane < 0 or self.lane > 2:
self.dir *= -1 self.dir *= -1
self.lane += self.dir * 2 self.lane += self.dir * 2
self.move_timer = now self.move_timer = now
# Строгое центрирование маленького босса
self.image = self.base_image self.image = self.base_image
self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane])) self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane]))
elif self.state == "GROWING": elif self.state == "GROWING":
# Состояние увеличения
self.image = pygame.transform.scale(self.base_image, (250, 250)) self.image = pygame.transform.scale(self.base_image, (250, 250))
self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane])) self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane]))
if now - self.grow_start > 2000: if now - self.grow_start > 2000:
self.state = "NORMAL" self.state = "NORMAL"
# Ускоряем движение в зависимости от HP при выходе из фазы роста
if self.lives <= 5: if self.lives <= 5:
self.move_delay = 600 self.move_delay = 600
elif self.lives <= 10: elif self.lives <= 10:
self.move_delay = 1100 self.move_delay = 1100
self.fire_rate_mod = max(0.5, self.fire_rate_mod - 0.15) self.fire_rate_mod = max(0.5, self.fire_rate_mod - 0.15)
self.rect = self.base_image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane])) self.rect = self.base_image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane]))
elif self.state == "DEAD": elif self.state == "DEAD":
self.image = pygame.transform.scale(self.base_image, (450, 450)) # Увеличиваемся до 500px
self.rect.x += 12; self.rect.y -= 12 if self.death_size < 500:
if self.rect.bottom < 0: self.kill() self.death_size = min(500, self.death_size + 8)
else:
# После достижения максимального размера — летим вправо
self.death_center_x += 18
# Перерисовываем с текущим размером
self.image = pygame.transform.scale(self.base_image, (int(self.death_size), int(self.death_size)))
self.rect = self.image.get_rect(center=(int(self.death_center_x), int(self.death_center_y)))
# Когда улетел за экран — уничтожаем спрайт
if self.rect.left > SCREEN_WIDTH + 50:
self.kill()
def start_death(self):
# Запускает анимацию смерти из текущей позиции босса.
self.state = "DEAD"
self.death_size = 100
self.death_center_x = float(self.rect.centerx)
self.death_center_y = float(self.rect.centery)
# --- Инициализация объектов --- # --- Инициализация объектов ---
player = Player() player = Player()
@ -157,14 +173,15 @@ boss_group = pygame.sprite.GroupSingle()
victory_pizza = pygame.sprite.GroupSingle() victory_pizza = pygame.sprite.GroupSingle()
score, speed, game_over, win = 0, 10, False, False score, speed, game_over, win = 0, 10, False, False
boss_dying = False # Флаг: босс сейчас проигрывает анимацию смерти
spawn_timer = pygame.time.get_ticks() spawn_timer = pygame.time.get_ticks()
p_timer = 0 p_timer = 0
k_timer = 0 k_timer = 0
font = pygame.font.Font(None, 40) font = pygame.font.Font(None, 40)
def reset(): def reset():
global score, speed, game_over, win, spawn_timer global score, speed, game_over, win, spawn_timer, boss_dying
score, speed, game_over, win = 0, 10, False, False score, speed, game_over, win, boss_dying = 0, 10, False, False, False
spawn_timer = pygame.time.get_ticks() spawn_timer = pygame.time.get_ticks()
player.lives, player.lane = 1, 1 player.lives, player.lane = 1, 1
enemies.empty(); projectiles.empty(); kotleta_group.empty(); boss_group.empty(); victory_pizza.empty() enemies.empty(); projectiles.empty(); kotleta_group.empty(); boss_group.empty(); victory_pizza.empty()
@ -196,7 +213,7 @@ while running:
if not game_over and not win: if not game_over and not win:
# Спавн обычных врагов # Спавн обычных врагов
if not boss_group and score < 50: if not boss_group and not boss_dying and score < 50:
delay = random.randint(1100, 1700) if score > 15 else 1500 delay = random.randint(1100, 1700) if score > 15 else 1500
if now - spawn_timer > delay: if now - spawn_timer > delay:
lanes = random.sample(range(3), 2) if score > 15 else [random.randint(0, 2)] lanes = random.sample(range(3), 2) if score > 15 else [random.randint(0, 2)]
@ -209,12 +226,14 @@ while running:
kotleta_group.add(Kotleta()) kotleta_group.add(Kotleta())
# Появление босса # Появление босса
if score >= 50 and not boss_group and not win: if score >= 50 and not boss_group and not boss_dying and not win:
boss_group.add(Boss()) boss_group.add(Boss())
enemies.empty(); kotleta_group.empty() enemies.empty(); kotleta_group.empty()
if boss_group: if boss_group:
b = boss_group.sprite b = boss_group.sprite
# Стрельба босса только в состоянии NORMAL
if b.state == "NORMAL": if b.state == "NORMAL":
if now - p_timer > 1400 * b.fire_rate_mod: if now - p_timer > 1400 * b.fire_rate_mod:
projectiles.add(Projectile(pizza_img, random.randint(0, 2), 12)) projectiles.add(Projectile(pizza_img, random.randint(0, 2), 12))
@ -223,26 +242,21 @@ while running:
projectiles.add(Projectile(pizza_kick_img, random.randint(0, 2), 9, True)) projectiles.add(Projectile(pizza_kick_img, random.randint(0, 2), 9, True))
k_timer = now k_timer = now
# Урон боссу # Урон боссу от брошенных снарядов
for p in projectiles: for p in list(projectiles):
if p.returned and b.rect.colliderect(p.rect): if p.returned and b.rect.colliderect(p.rect):
b.lives -= 1; p.kill() b.lives -= 1
p.kill()
if b.lives in [10, 5]: if b.lives in [10, 5]:
b.state = "GROWING" b.state = "GROWING"
b.grow_start = now b.grow_start = now
projectiles.empty() projectiles.empty()
if b.lives <= 0: elif b.lives <= 0:
b.state = "DEAD"; projectiles.empty() # Запускаем анимацию смерти
b.start_death()
# Проверка победы boss_dying = True
if boss_group and boss_group.sprite.state == "DEAD": projectiles.empty()
pass # Ждем пока улетит break # Прекращаем проверку остальных снарядов
elif score >= 50 and not boss_group and not win:
win = True
vp = pygame.sprite.Sprite()
vp.image = load_s('pizza.png', (450, 450))
vp.rect = vp.image.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
victory_pizza.add(vp)
# Обновление всех объектов # Обновление всех объектов
player.update() player.update()
@ -250,20 +264,34 @@ while running:
projectiles.update() projectiles.update()
kotleta_group.update() kotleta_group.update()
boss_group.update() boss_group.update()
victory_pizza.update()
# Коллизии # Если босс умирал и спрайт уже уничтожен — победа
if boss_dying and not boss_group:
win = True
boss_dying = False
# Коллизии с игроком (только если босс НЕ в режиме смерти)
if pygame.sprite.spritecollide(player, enemies, True): player.lives -= 1 if pygame.sprite.spritecollide(player, enemies, True): player.lives -= 1
if pygame.sprite.spritecollide(player, kotleta_group, True): player.lives += 1 if pygame.sprite.spritecollide(player, kotleta_group, True): player.lives += 1
for p in projectiles: if boss_group and boss_group.sprite.state != "DEAD":
for p in list(projectiles):
if player.rect.colliderect(p.rect) and not p.returned: if player.rect.colliderect(p.rect) and not p.returned:
if p.kickable: if p.kickable:
p.held = True; p.rect.center = player.rect.center p.held = True; p.rect.center = player.rect.center
else: else:
player.lives -= 1; p.kill() player.lives -= 1; p.kill()
elif p.held and not player.rect.colliderect(p.rect): elif p.held and not player.rect.colliderect(p.rect):
p.kill() # Снаряд исчезает, если игрок ушел с линии не кинув его p.kill()
elif not boss_group:
for p in list(projectiles):
if player.rect.colliderect(p.rect) and not p.returned:
if p.kickable:
p.held = True; p.rect.center = player.rect.center
else:
player.lives -= 1; p.kill()
elif p.held and not player.rect.colliderect(p.rect):
p.kill()
# Начисление очков # Начисление очков
for e in enemies: for e in enemies:
@ -276,7 +304,6 @@ while running:
# --- Отрисовка --- # --- Отрисовка ---
screen.blit(background_img, (0, 0)) screen.blit(background_img, (0, 0))
# Рисуем линии дорожек
for i in range(4): for i in range(4):
pygame.draw.rect(screen, (0, 0, 0), (0, start_y + i*(lane_height+line_thickness), SCREEN_WIDTH, line_thickness)) pygame.draw.rect(screen, (0, 0, 0), (0, start_y + i*(lane_height+line_thickness), SCREEN_WIDTH, line_thickness))
@ -296,19 +323,24 @@ while running:
screen.blit(font.render(f"Lives: {player.lives}", True, (0,0,0)), (850, 20)) screen.blit(font.render(f"Lives: {player.lives}", True, (0,0,0)), (850, 20))
if boss_group: if boss_group:
b = boss_group.sprite b = boss_group.sprite
screen.blit(font.render(f"BOSS HP: {b.lives}", True, (0,0,0)), (SCREEN_WIDTH - 300, 20)) hp_text = f"BOSS HP: {max(0, b.lives)}"
screen.blit(font.render(hp_text, True, (0,0,0)), (SCREEN_WIDTH - 300, 20))
# Экраны окончания # Экраны окончания
if game_over: if game_over:
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA) overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 200)); screen.blit(overlay, (0,0)) overlay.fill((0, 0, 0, 200)); screen.blit(overlay, (0,0))
screen.blit(end_img, (SCREEN_WIDTH//2 - 150, 50)) screen.blit(end_img, (SCREEN_WIDTH//2 - 150, 50))
msg = pygame.font.Font(None, 100).render("ИГРА ОКОНЧЕНА", True, (255, 50, 50)) msg = pygame.font.Font(None, 100).render("SPĒLE BEIGUSIES", True, (255, 50, 50))
screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, 400))) screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, 400)))
hint = font.render("R — vēlreiz | Q — padoties", True, (200, 200, 200))
screen.blit(hint, hint.get_rect(center=(SCREEN_WIDTH//2, 500)))
if win: if win:
msg = pygame.font.Font(None, 100).render("ПОБЕДА! СУПЕР ПИЦЦА ТВОЯ!", True, (255, 200, 0)) msg = pygame.font.Font(None, 100).render("UZVARA! PICA IR TAVA!", True, (255, 200, 0))
screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, 100))) screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 - 40)))
hint = font.render("R — vēlreiz | Q — iziet", True, (200, 200, 200))
screen.blit(hint, hint.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 60)))
pygame.display.flip() pygame.display.flip()
clock.tick(60) clock.tick(60)