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

662
main.py
View File

@ -1,316 +1,348 @@
import pygame import pygame
from pygame.locals import K_UP, K_DOWN, QUIT, KEYDOWN, K_r, K_q, K_1, K_2, K_3 from pygame.locals import K_UP, K_DOWN, QUIT, KEYDOWN, K_r, K_q, K_1, K_2, K_3
import random import random
# Инициализация # Инициализация
pygame.init() pygame.init()
# --- Настройки экрана --- # --- Настройки экрана ---
SCREEN_WIDTH, SCREEN_HEIGHT = 1600, 600 SCREEN_WIDTH, SCREEN_HEIGHT = 1600, 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Canteen Rush: The Final Battle") pygame.display.set_caption("Canteen Rush: The Final Battle")
clock = pygame.time.Clock() clock = pygame.time.Clock()
def load_s(path, size, alpha=True): def load_s(path, size, alpha=True):
try: try:
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
# --- Загрузка ресурсов ---
# --- Загрузка ресурсов --- background_img = load_s('background1.png', (SCREEN_WIDTH, SCREEN_HEIGHT), False)
background_img = load_s('background1.png', (SCREEN_WIDTH, SCREEN_HEIGHT), False) enemy_img = load_s('Sprite-0001.png', (90, 90))
enemy_img = load_s('Sprite-0001.png', (90, 90)) player_img = load_s('player1.jpg', (90, 90))
player_img = load_s('player1.jpg', (90, 90)) end_img = load_s('Sprite-0002.png', (300, 300))
end_img = load_s('Sprite-0002.png', (300, 300)) povar_img = load_s('povar.png', (150, 150))
povar_img = load_s('povar.png', (150, 150)) kotleta_img = load_s('kotleta.png', (60, 60))
kotleta_img = load_s('kotleta.png', (60, 60)) demon_img = load_s('demon.png', (100, 100))
demon_img = load_s('demon.png', (100, 100)) pizza_img = load_s('pizza.png', (65, 65))
pizza_img = load_s('pizza.png', (65, 65)) pizza_kick_img = load_s('pizza_kick.png', (70, 70))
pizza_kick_img = load_s('pizza_kick.png', (70, 70))
# --- Логика дорожек ---
# --- Логика дорожек --- lane_height = 100
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 = [start_y + line_thickness + i * (lane_height + line_thickness) + lane_height // 2 for i in range(3)]
# lane_centers — это Y-координаты центров трёх дорожек
lane_centers = [start_y + line_thickness + i * (lane_height + line_thickness) + lane_height // 2 for i in range(3)] class Player(pygame.sprite.Sprite):
def __init__(self):
class Player(pygame.sprite.Sprite): super().__init__()
def __init__(self): self.image = player_img
super().__init__() self.image.set_colorkey((255, 255, 255))
self.image = player_img self.lane = 1
self.image.set_colorkey((255, 255, 255)) self.lives = 1
self.lane = 1 self.rect = self.image.get_rect(center=(200, lane_centers[self.lane]))
self.lives = 1 def update(self):
self.rect = self.image.get_rect(center=(200, lane_centers[self.lane])) self.rect.centery = lane_centers[self.lane]
def update(self):
self.rect.centery = lane_centers[self.lane] class Enemy(pygame.sprite.Sprite):
def __init__(self, speed, lane, x_offset=0):
class Enemy(pygame.sprite.Sprite): super().__init__()
def __init__(self, speed, lane, x_offset=0): self.image = enemy_img
super().__init__() self.image.set_colorkey((0, 0, 0))
self.image = enemy_img self.speed = speed
self.image.set_colorkey((0, 0, 0)) self.rect = self.image.get_rect(center=(SCREEN_WIDTH + 100 + x_offset, lane_centers[lane]))
self.speed = speed self.passed = False
self.rect = self.image.get_rect(center=(SCREEN_WIDTH + 100 + x_offset, lane_centers[lane])) def update(self):
self.passed = False self.rect.x -= self.speed
def update(self): if self.rect.right < 0: self.kill()
self.rect.x -= self.speed
if self.rect.right < 0: self.kill() class Kotleta(pygame.sprite.Sprite):
def __init__(self):
class Kotleta(pygame.sprite.Sprite): super().__init__()
def __init__(self): self.image = kotleta_img
super().__init__() self.lane = random.randint(0, 2)
self.image = kotleta_img self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 50, lane_centers[self.lane]))
self.lane = random.randint(0, 2) self.timer = pygame.time.get_ticks()
self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 50, lane_centers[self.lane])) def update(self):
self.timer = pygame.time.get_ticks() self.rect.x -= 5
def update(self): if pygame.time.get_ticks() - self.timer > 1500:
self.rect.x -= 5 self.lane = random.randint(0, 2); self.timer = pygame.time.get_ticks()
if pygame.time.get_ticks() - self.timer > 1500: self.rect.centery = lane_centers[self.lane]
self.lane = random.randint(0, 2); self.timer = pygame.time.get_ticks() if self.rect.right < 0: self.kill()
self.rect.centery = lane_centers[self.lane]
if self.rect.right < 0: self.kill() class Projectile(pygame.sprite.Sprite):
def __init__(self, img, lane, speed, kickable=False):
class Projectile(pygame.sprite.Sprite): super().__init__()
def __init__(self, img, lane, speed, kickable=False): self.image = img
super().__init__() self.target_y = lane_centers[lane]
self.image = img self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 250, self.target_y - 40))
self.target_y = lane_centers[lane] self.speed = speed
self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 250, self.target_y - 40)) self.kickable = kickable
self.speed = speed self.returned = False
self.kickable = kickable self.held = False
self.returned = False self.v_speed = -4
self.held = False def update(self):
self.v_speed = -4 if self.held: return
def update(self): if self.returned:
if self.held: return self.rect.x += 25
if self.returned: else:
self.rect.x += 25 self.rect.x -= self.speed
else: if self.rect.centery < self.target_y:
self.rect.x -= self.speed self.rect.centery += self.v_speed; self.v_speed += 0.25
if self.rect.centery < self.target_y: else: self.rect.centery = self.target_y
self.rect.centery += self.v_speed; self.v_speed += 0.25 if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH: self.kill()
else: self.rect.centery = self.target_y
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH: self.kill() class Boss(pygame.sprite.Sprite):
def __init__(self):
class Boss(pygame.sprite.Sprite): super().__init__()
def __init__(self): self.base_image = demon_img
super().__init__() self.image = self.base_image
self.base_image = demon_img self.lives = 15
self.image = self.base_image self.lane = 1
self.lives = 15 self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane]))
self.lane = 1 self.dir = 1
self.rect = self.image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane])) self.move_timer = pygame.time.get_ticks()
self.dir = 1 self.state = "NORMAL"
self.move_timer = pygame.time.get_ticks() self.move_delay = 2000
self.state = "NORMAL" self.fire_rate_mod = 1.0
self.move_delay = 2000 # Начальная задержка движения self.grow_start = 0
self.fire_rate_mod = 1.0
self.grow_start = 0 # Параметры анимации смерти
self.death_size = 100
def update(self): self.death_center_x = 0
now = pygame.time.get_ticks() self.death_center_y = 0
if self.state == "NORMAL": def update(self):
# Проверка таймера перемещения now = pygame.time.get_ticks()
if now - self.move_timer > self.move_delay:
self.lane += self.dir if self.state == "NORMAL":
if self.lane < 0 or self.lane > 2: if now - self.move_timer > self.move_delay:
self.dir *= -1 self.lane += self.dir
self.lane += self.dir * 2 if self.lane < 0 or self.lane > 2:
self.move_timer = now self.dir *= -1
self.lane += self.dir * 2
# Строгое центрирование маленького босса 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" if self.lives <= 5:
# Ускоряем движение в зависимости от HP при выходе из фазы роста self.move_delay = 600
if self.lives <= 5: elif self.lives <= 10:
self.move_delay = 600 self.move_delay = 1100
elif self.lives <= 10: self.fire_rate_mod = max(0.5, self.fire_rate_mod - 0.15)
self.move_delay = 1100 self.rect = self.base_image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane]))
self.fire_rate_mod = max(0.5, self.fire_rate_mod - 0.15) elif self.state == "DEAD":
self.rect = self.base_image.get_rect(center=(SCREEN_WIDTH - 200, lane_centers[self.lane])) # Увеличиваемся до 500px
if self.death_size < 500:
elif self.state == "DEAD": self.death_size = min(500, self.death_size + 8)
self.image = pygame.transform.scale(self.base_image, (450, 450)) else:
self.rect.x += 12; self.rect.y -= 12 # После достижения максимального размера — летим вправо
if self.rect.bottom < 0: self.kill() self.death_center_x += 18
# --- Инициализация объектов --- # Перерисовываем с текущим размером
player = Player() self.image = pygame.transform.scale(self.base_image, (int(self.death_size), int(self.death_size)))
enemies = pygame.sprite.Group() self.rect = self.image.get_rect(center=(int(self.death_center_x), int(self.death_center_y)))
projectiles = pygame.sprite.Group()
kotleta_group = pygame.sprite.GroupSingle() # Когда улетел за экран — уничтожаем спрайт
boss_group = pygame.sprite.GroupSingle() if self.rect.left > SCREEN_WIDTH + 50:
victory_pizza = pygame.sprite.GroupSingle() self.kill()
score, speed, game_over, win = 0, 10, False, False def start_death(self):
spawn_timer = pygame.time.get_ticks() # Запускает анимацию смерти из текущей позиции босса.
p_timer = 0 self.state = "DEAD"
k_timer = 0 self.death_size = 100
font = pygame.font.Font(None, 40) self.death_center_x = float(self.rect.centerx)
self.death_center_y = float(self.rect.centery)
def reset():
global score, speed, game_over, win, spawn_timer
score, speed, game_over, win = 0, 10, False, False # --- Инициализация объектов ---
spawn_timer = pygame.time.get_ticks() player = Player()
player.lives, player.lane = 1, 1 enemies = pygame.sprite.Group()
enemies.empty(); projectiles.empty(); kotleta_group.empty(); boss_group.empty(); victory_pizza.empty() projectiles = pygame.sprite.Group()
kotleta_group = pygame.sprite.GroupSingle()
# --- Игровой цикл --- boss_group = pygame.sprite.GroupSingle()
running = True victory_pizza = pygame.sprite.GroupSingle()
while running:
now = pygame.time.get_ticks() score, speed, game_over, win = 0, 10, False, False
boss_dying = False # Флаг: босс сейчас проигрывает анимацию смерти
for event in pygame.event.get(): spawn_timer = pygame.time.get_ticks()
if event.type == QUIT: p_timer = 0
running = False k_timer = 0
if event.type == KEYDOWN: font = pygame.font.Font(None, 40)
if not game_over and not win:
if event.key == K_UP: player.lane = max(0, player.lane - 1) def reset():
if event.key == K_DOWN: player.lane = min(2, player.lane + 1) global score, speed, game_over, win, spawn_timer, boss_dying
t_lane = -1 score, speed, game_over, win, boss_dying = 0, 10, False, False, False
if event.key == K_1: t_lane = 0 spawn_timer = pygame.time.get_ticks()
if event.key == K_2: t_lane = 1 player.lives, player.lane = 1, 1
if event.key == K_3: t_lane = 2 enemies.empty(); projectiles.empty(); kotleta_group.empty(); boss_group.empty(); victory_pizza.empty()
if t_lane != -1:
for p in projectiles: # --- Игровой цикл ---
if p.held: running = True
p.held = False; p.returned = True while running:
p.target_y = lane_centers[t_lane]; p.rect.centery = p.target_y now = pygame.time.get_ticks()
else:
if event.key == K_r: reset() for event in pygame.event.get():
if event.key == K_q: running = False if event.type == QUIT:
running = False
if not game_over and not win: if event.type == KEYDOWN:
# Спавн обычных врагов if not game_over and not win:
if not boss_group and score < 50: if event.key == K_UP: player.lane = max(0, player.lane - 1)
delay = random.randint(1100, 1700) if score > 15 else 1500 if event.key == K_DOWN: player.lane = min(2, player.lane + 1)
if now - spawn_timer > delay: t_lane = -1
lanes = random.sample(range(3), 2) if score > 15 else [random.randint(0, 2)] if event.key == K_1: t_lane = 0
for i, l in enumerate(lanes): if event.key == K_2: t_lane = 1
enemies.add(Enemy(speed, l, x_offset=i*random.randint(300, 500))) if event.key == K_3: t_lane = 2
spawn_timer = now if t_lane != -1:
for p in projectiles:
# Повариха с котлетой if p.held:
if (25 <= score <= 29 or score == 42) and not kotleta_group: p.held = False; p.returned = True
kotleta_group.add(Kotleta()) p.target_y = lane_centers[t_lane]; p.rect.centery = p.target_y
else:
# Появление босса if event.key == K_r: reset()
if score >= 50 and not boss_group and not win: if event.key == K_q: running = False
boss_group.add(Boss())
enemies.empty(); kotleta_group.empty() if not game_over and not win:
# Спавн обычных врагов
if boss_group: if not boss_group and not boss_dying and score < 50:
b = boss_group.sprite delay = random.randint(1100, 1700) if score > 15 else 1500
if b.state == "NORMAL": if now - spawn_timer > delay:
if now - p_timer > 1400 * b.fire_rate_mod: lanes = random.sample(range(3), 2) if score > 15 else [random.randint(0, 2)]
projectiles.add(Projectile(pizza_img, random.randint(0, 2), 12)) for i, l in enumerate(lanes):
p_timer = now enemies.add(Enemy(speed, l, x_offset=i*random.randint(300, 500)))
if now - k_timer > 2800 * b.fire_rate_mod: spawn_timer = now
projectiles.add(Projectile(pizza_kick_img, random.randint(0, 2), 9, True))
k_timer = now # Повариха с котлетой
if (25 <= score <= 29 or score == 42) and not kotleta_group:
# Урон боссу kotleta_group.add(Kotleta())
for p in projectiles:
if p.returned and b.rect.colliderect(p.rect): # Появление босса
b.lives -= 1; p.kill() if score >= 50 and not boss_group and not boss_dying and not win:
if b.lives in [10, 5]: boss_group.add(Boss())
b.state = "GROWING" enemies.empty(); kotleta_group.empty()
b.grow_start = now
projectiles.empty() if boss_group:
if b.lives <= 0: b = boss_group.sprite
b.state = "DEAD"; projectiles.empty()
# Стрельба босса только в состоянии NORMAL
# Проверка победы if b.state == "NORMAL":
if boss_group and boss_group.sprite.state == "DEAD": if now - p_timer > 1400 * b.fire_rate_mod:
pass # Ждем пока улетит projectiles.add(Projectile(pizza_img, random.randint(0, 2), 12))
elif score >= 50 and not boss_group and not win: p_timer = now
win = True if now - k_timer > 2800 * b.fire_rate_mod:
vp = pygame.sprite.Sprite() projectiles.add(Projectile(pizza_kick_img, random.randint(0, 2), 9, True))
vp.image = load_s('pizza.png', (450, 450)) k_timer = now
vp.rect = vp.image.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
victory_pizza.add(vp) # Урон боссу от брошенных снарядов
for p in list(projectiles):
# Обновление всех объектов if p.returned and b.rect.colliderect(p.rect):
player.update() b.lives -= 1
enemies.update() p.kill()
projectiles.update() if b.lives in [10, 5]:
kotleta_group.update() b.state = "GROWING"
boss_group.update() b.grow_start = now
victory_pizza.update() projectiles.empty()
elif b.lives <= 0:
# Коллизии # Запускаем анимацию смерти
if pygame.sprite.spritecollide(player, enemies, True): player.lives -= 1 b.start_death()
if pygame.sprite.spritecollide(player, kotleta_group, True): player.lives += 1 boss_dying = True
projectiles.empty()
for p in projectiles: break # Прекращаем проверку остальных снарядов
if player.rect.colliderect(p.rect) and not p.returned:
if p.kickable: # Обновление всех объектов
p.held = True; p.rect.center = player.rect.center player.update()
else: enemies.update()
player.lives -= 1; p.kill() projectiles.update()
elif p.held and not player.rect.colliderect(p.rect): kotleta_group.update()
p.kill() # Снаряд исчезает, если игрок ушел с линии не кинув его boss_group.update()
# Начисление очков # Если босс умирал и спрайт уже уничтожен — победа
for e in enemies: if boss_dying and not boss_group:
if not e.passed and e.rect.right < player.rect.left: win = True
e.passed = True; score += 1 boss_dying = False
if score % 5 == 0 and speed < 35: speed += 1
# Коллизии с игроком (только если босс НЕ в режиме смерти)
if player.lives <= 0: game_over = True if pygame.sprite.spritecollide(player, enemies, True): player.lives -= 1
if pygame.sprite.spritecollide(player, kotleta_group, True): player.lives += 1
# --- Отрисовка ---
screen.blit(background_img, (0, 0)) if boss_group and boss_group.sprite.state != "DEAD":
for p in list(projectiles):
# Рисуем линии дорожек if player.rect.colliderect(p.rect) and not p.returned:
for i in range(4): if p.kickable:
pygame.draw.rect(screen, (0, 0, 0), (0, start_y + i*(lane_height+line_thickness), SCREEN_WIDTH, line_thickness)) p.held = True; p.rect.center = player.rect.center
else:
if kotleta_group: player.lives -= 1; p.kill()
screen.blit(povar_img, (SCREEN_WIDTH // 2 - 75, start_y - 145)) elif p.held and not player.rect.colliderect(p.rect):
p.kill()
enemies.draw(screen) elif not boss_group:
projectiles.draw(screen) for p in list(projectiles):
kotleta_group.draw(screen) if player.rect.colliderect(p.rect) and not p.returned:
boss_group.draw(screen) if p.kickable:
victory_pizza.draw(screen) p.held = True; p.rect.center = player.rect.center
screen.blit(player.image, player.rect) else:
player.lives -= 1; p.kill()
# Интерфейс elif p.held and not player.rect.colliderect(p.rect):
screen.blit(font.render(f"Score: {score}", True, (0,0,0)), (130, 20)) p.kill()
screen.blit(font.render(f"Speed: {speed}", True, (0,0,0)), (450, 20))
screen.blit(font.render(f"Lives: {player.lives}", True, (0,0,0)), (850, 20)) # Начисление очков
if boss_group: for e in enemies:
b = boss_group.sprite if not e.passed and e.rect.right < player.rect.left:
screen.blit(font.render(f"BOSS HP: {b.lives}", True, (0,0,0)), (SCREEN_WIDTH - 300, 20)) e.passed = True; score += 1
if score % 5 == 0 and speed < 35: speed += 1
# Экраны окончания
if game_over: if player.lives <= 0: game_over = True
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 200)); screen.blit(overlay, (0,0)) # --- Отрисовка ---
screen.blit(end_img, (SCREEN_WIDTH//2 - 150, 50)) screen.blit(background_img, (0, 0))
msg = pygame.font.Font(None, 100).render("ИГРА ОКОНЧЕНА", True, (255, 50, 50))
screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, 400))) for i in range(4):
pygame.draw.rect(screen, (0, 0, 0), (0, start_y + i*(lane_height+line_thickness), SCREEN_WIDTH, line_thickness))
if win:
msg = pygame.font.Font(None, 100).render("ПОБЕДА! СУПЕР ПИЦЦА ТВОЯ!", True, (255, 200, 0)) if kotleta_group:
screen.blit(msg, msg.get_rect(center=(SCREEN_WIDTH//2, 100))) screen.blit(povar_img, (SCREEN_WIDTH // 2 - 75, start_y - 145))
pygame.display.flip() enemies.draw(screen)
clock.tick(60) projectiles.draw(screen)
kotleta_group.draw(screen)
boss_group.draw(screen)
victory_pizza.draw(screen)
screen.blit(player.image, player.rect)
# Интерфейс
screen.blit(font.render(f"Score: {score}", True, (0,0,0)), (130, 20))
screen.blit(font.render(f"Speed: {speed}", True, (0,0,0)), (450, 20))
screen.blit(font.render(f"Lives: {player.lives}", True, (0,0,0)), (850, 20))
if boss_group:
b = boss_group.sprite
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:
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 200)); screen.blit(overlay, (0,0))
screen.blit(end_img, (SCREEN_WIDTH//2 - 150, 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)))
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:
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, 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()
clock.tick(60)
pygame.quit() pygame.quit()