Game/main.py

315 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import pygame
import sys
pygame.init()
pygame.mixer.init()
# =====================================================
# НАСТРОЙКИ
# =====================================================
WIDTH, HEIGHT = 1000, 800
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Goblin & Knight")
CLOCK = pygame.time.Clock()
BLACK = (0, 0, 0)
GRAVITY = 0.9
GROUND_Y = HEIGHT - 60
FPS = 60
# =====================================================
# ЗАГРУЗКА ФОНОВ
# =====================================================
BACKGROUND = pygame.image.load("images/back.png")
BACK_MAIN = pygame.image.load("images/back_main.jpg")
BACK_MAIN = pygame.transform.scale(BACK_MAIN, (WIDTH, HEIGHT))
# Попытаться загрузить музыку/звуки, если есть
BG_MUSIC = None
try:
BG_MUSIC = pygame.mixer.music
pygame.mixer.music.load('music/theme.mp3')
pygame.mixer.music.set_volume(0.5)
except Exception:
BG_MUSIC = None
# Шрифты и HUD
FONT = pygame.font.SysFont(None, 32)
# Игровые счётчики
score_goblin = 0
score_knight = 0
# Пауза
paused = False
# =====================================================
# КЛАСС ИГРОКА
# =====================================================
class Player:
def __init__(self, x, y, sprites, scale, controls):
self.start_x = x
self.start_y = y
self.x = float(x)
self.y = float(y)
self.y_velocity = 0.0
self.jump_power = 18
self.jumping = False
self.facing_right = True
self.moving = False
self.speed = 5.5
self.controls = controls
self.anim_counter = 0
self.ANIM_SPEED = 8
# Загрузка спрайтов из файлов
self.stand = pygame.image.load(sprites["stand"]).convert_alpha()
self.walk_left = pygame.image.load(sprites["walk_left"]).convert_alpha()
self.walk_right = pygame.image.load(sprites["walk_right"]).convert_alpha()
self.jump_img = pygame.image.load(sprites["jump"]).convert_alpha()
# Масштабирование
self.stand = pygame.transform.scale(self.stand, (int(self.stand.get_width() * scale), int(self.stand.get_height() * scale)))
self.walk_left = pygame.transform.scale(self.walk_left, (int(self.walk_left.get_width() * scale), int(self.walk_left.get_height() * scale)))
self.walk_right = pygame.transform.scale(self.walk_right, (int(self.walk_right.get_width() * scale), int(self.walk_right.get_height() * scale)))
self.jump_img = pygame.transform.scale(self.jump_img, (int(self.jump_img.get_width() * scale), int(self.jump_img.get_height() * scale)))
self.surface = self.stand
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
# -------------------------
# СБРОС ПЕРСОНАЖА
# -------------------------
def reset(self):
self.x = self.start_x
self.y = self.start_y
self.y_velocity = 0
self.jumping = False
self.moving = False
self.anim_counter = 0
self.facing_right = True
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
# -------------------------
# УПРАВЛЕНИЕ
# -------------------------
def handle_input(self, keys):
self.moving = False
if keys[self.controls["right"]]:
self.x += self.speed
self.facing_right = True
self.moving = True
if keys[self.controls["left"]]:
self.x -= self.speed
self.facing_right = False
self.moving = True
if keys[self.controls["jump"]] and not self.jumping:
self.jumping = True
self.y_velocity = -self.jump_power
# Ограничение по экрану
if self.x < 0:
self.x = 0
if self.x > WIDTH:
self.x = WIDTH
# -------------------------
# ГРАВИТАЦИЯ
# -------------------------
def apply_gravity(self):
self.y_velocity += GRAVITY
self.y += self.y_velocity
if self.y >= GROUND_Y:
self.y = GROUND_Y
self.y_velocity = 0
self.jumping = False
# -------------------------
# АНИМАЦИЯ
# -------------------------
def update_animation(self):
if self.jumping:
self.surface = self.jump_img
elif self.moving:
self.anim_counter += 1
frame = (self.anim_counter // self.ANIM_SPEED) % 2
self.surface = self.walk_left if frame == 0 else self.walk_right
else:
self.surface = self.stand
if not self.facing_right:
self.surface = pygame.transform.flip(self.surface, True, False)
self.rect = self.surface.get_rect(midbottom=(int(self.x), int(self.y)))
# -------------------------
# ОТРИСОВКА
# -------------------------
def draw(self, screen):
screen.blit(self.surface, self.rect)
goblin = Player(
200, GROUND_Y,
{
"stand": "images/GoblinWorker/spritePics/stand_gob.png",
"walk_left": "images/GoblinWorker/spritePics/walkleft.png",
"walk_right": "images/GoblinWorker/spritePics/walkright.png",
"jump": "images/GoblinWorker/spritePics/Jump.png"
},
3,
{
"left": pygame.K_a,
"right": pygame.K_d,
"jump": pygame.K_SPACE
}
)
knight = Player(
500, GROUND_Y,
{
"stand": "images/sprites/knight.png",
"walk_left": "images/sprites/knight.png",
"walk_right": "images/sprites/knight.png",
"jump": "images/sprites/knight.png"
},
3,
{
"left": pygame.K_KP4,
"right": pygame.K_KP6,
"jump": pygame.K_KP8
}
)
# =====================================================
# ОБЪЕКТЫ УРОВНЯ
# =====================================================
door_image = pygame.image.load("images/door.png")
door_rect = door_image.get_rect(center=(800, 700))
button_play = pygame.image.load("images/play_button.png")
button_rect = button_play.get_rect(center=(500, 400))
# =====================================================
# ФУНКЦИЯ РЕСТАРТА
# =====================================================
def restart_level():
goblin.reset()
knight.reset()
# =====================================================
# GAME LOOP
# =====================================================
level = 0
level_start_time = None
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE and level == 1:
paused = not paused
if event.key == pygame.K_r:
restart_level()
level = 0
keys = pygame.key.get_pressed()
mouse_pos = pygame.mouse.get_pos()
SCREEN.fill((0, 0, 0))
# ================= MENU =================
if level == 0:
SCREEN.blit(BACK_MAIN, (0, 0))
SCREEN.blit(button_play, button_rect)
title_surf = FONT.render('Goblin & Knight', True, (255,255,255))
SCREEN.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 120))
if button_rect.collidepoint(mouse_pos) and pygame.mouse.get_pressed()[0]:
restart_level()
level = 1
level_start_time = pygame.time.get_ticks()
if BG_MUSIC:
try:
pygame.mixer.music.play(-1)
except Exception:
pass
# ================= GAME =================
elif level == 1:
SCREEN.blit(BACKGROUND, (0, 0))
SCREEN.blit(door_image, door_rect)
if not paused:
# --- Goblin ---
goblin.handle_input(keys)
goblin.apply_gravity()
goblin.update_animation()
# --- Knight ---
knight.handle_input(keys)
knight.apply_gravity()
knight.update_animation()
# Draw players (even when paused)
goblin.draw(SCREEN)
knight.draw(SCREEN)
elapsed = 0
if level_start_time:
elapsed = (pygame.time.get_ticks() - level_start_time) // 1000
hud_g = FONT.render(f'Goblin: {score_goblin}', True, (255,255,255))
hud_k = FONT.render(f'Knight: {score_knight}', True, (255,255,255))
hud_t = FONT.render(f'Time: {elapsed}s', True, (255,255,255))
SCREEN.blit(hud_g, (20, 20))
SCREEN.blit(hud_k, (WIDTH - hud_k.get_width() - 20, 20))
SCREEN.blit(hud_t, (WIDTH//2 - hud_t.get_width()//2, 20))
if paused:
p = FONT.render('PAUSED - press ESC to resume', True, (255,255,0))
SCREEN.blit(p, (WIDTH//2 - p.get_width()//2, HEIGHT//2 - 20))
# Победа
if goblin.rect.colliderect(door_rect) and keys[pygame.K_e]:
score_goblin += 1
restart_level()
level = 0
if BG_MUSIC:
try:
pygame.mixer.music.stop()
except Exception:
pass
if knight.rect.colliderect(door_rect) and keys[pygame.K_KP5]:
score_knight += 1
restart_level()
level = 0
if BG_MUSIC:
try:
pygame.mixer.music.stop()
except Exception:
pass
pygame.display.update()
CLOCK.tick(FPS)