434 lines
16 KiB
Python
434 lines
16 KiB
Python
import pygame
|
|
import random
|
|
|
|
# --- Inicializācija ---
|
|
pygame.init()
|
|
|
|
# Ekrāna iestatījumi
|
|
WIDTH, HEIGHT = 1024, 576
|
|
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
|
|
pygame.display.set_caption("Pixel Kombat: Ultimate")
|
|
CLOCK = pygame.time.Clock()
|
|
|
|
# --- Krāsas (PIEVIENOTS RED UN BLUE) ---
|
|
WHITE = (255, 255, 255)
|
|
BLACK = (0, 0, 0)
|
|
RED = (255, 0, 0) # <--- Šis trūka
|
|
BLUE = (0, 0, 255) # <--- Papildus
|
|
GRAY = (50, 50, 50)
|
|
DARK_GRAY = (20, 20, 20)
|
|
YELLOW = (255, 215, 0)
|
|
BROWN = (139, 69, 19)
|
|
GREEN = (50, 200, 50)
|
|
CYAN = (0, 255, 255)
|
|
PURPLE = (160, 32, 240)
|
|
|
|
# Pieejamās raksturu krāsas (saraksts)
|
|
COLORS = [
|
|
(235, 64, 52), # Red
|
|
(52, 119, 235), # Blue
|
|
(52, 235, 86), # Green
|
|
(255, 215, 0), # Gold
|
|
(160, 32, 240), # Purple
|
|
(255, 105, 180) # Pink
|
|
]
|
|
|
|
# --- Fonti ---
|
|
try:
|
|
FONT_BIG = pygame.font.Font(None, 74)
|
|
FONT_MED = pygame.font.Font(None, 50)
|
|
FONT_SMALL = pygame.font.Font(None, 32)
|
|
except:
|
|
FONT_BIG = pygame.font.SysFont("Arial", 74)
|
|
FONT_MED = pygame.font.SysFont("Arial", 50)
|
|
FONT_SMALL = pygame.font.SysFont("Arial", 32)
|
|
|
|
# --- Globālie mainīgie (Spēles stāvokļi) ---
|
|
STATE = "MENU" # MENU, CHAR_SELECT, BG_SELECT, DIALOGUE, GAME, GAMEOVER
|
|
SELECTED_BG = "CITY"
|
|
P1_COLOR = COLORS[0] # Noklusējums
|
|
P2_COLOR = COLORS[1] # Noklusējums
|
|
|
|
# --- UI Klases ---
|
|
|
|
class Button:
|
|
def __init__(self, x, y, w, h, text, color, hover_color, action_code):
|
|
self.rect = pygame.Rect(x, y, w, h)
|
|
self.text = text
|
|
self.color = color
|
|
self.hover_color = hover_color
|
|
self.action_code = action_code
|
|
|
|
def draw(self, surface):
|
|
mouse_pos = pygame.mouse.get_pos()
|
|
color = self.hover_color if self.rect.collidepoint(mouse_pos) else self.color
|
|
|
|
pygame.draw.rect(surface, color, self.rect)
|
|
pygame.draw.rect(surface, WHITE, self.rect, 2) # Apmale
|
|
|
|
text_surf = FONT_SMALL.render(self.text, True, WHITE)
|
|
surface.blit(text_surf, (self.rect.centerx - text_surf.get_width()//2, self.rect.centery - text_surf.get_height()//2))
|
|
|
|
def is_clicked(self, event):
|
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
if event.button == 1 and self.rect.collidepoint(event.pos):
|
|
return True
|
|
return False
|
|
|
|
# --- Klase Spēlētājam ---
|
|
class Fighter(pygame.sprite.Sprite):
|
|
def __init__(self, x, y, color, facing_right, controls):
|
|
super().__init__()
|
|
self.original_color = color
|
|
self.color = color
|
|
|
|
self.rect = pygame.Rect(x, y, 50, 100)
|
|
self.vel_y = 0
|
|
self.speed = 7
|
|
self.jump_power = -18
|
|
self.gravity = 0.8
|
|
self.on_ground = False
|
|
|
|
self.facing_right = facing_right
|
|
self.controls = controls
|
|
self.attacking = False
|
|
self.attack_cooldown = 0
|
|
self.attack_box = pygame.Rect(0, 0, 0, 0)
|
|
self.health = 100
|
|
self.hit_timer = 0
|
|
|
|
def move(self, keys):
|
|
dx = 0
|
|
if keys[self.controls['left']]:
|
|
dx = -self.speed
|
|
self.facing_right = False
|
|
if keys[self.controls['right']]:
|
|
dx = self.speed
|
|
self.facing_right = True
|
|
|
|
self.rect.x += dx
|
|
if self.rect.left < 0: self.rect.left = 0
|
|
if self.rect.right > WIDTH: self.rect.right = WIDTH
|
|
|
|
if keys[self.controls['jump']] and self.on_ground:
|
|
self.vel_y = self.jump_power
|
|
self.on_ground = False
|
|
|
|
self.vel_y += self.gravity
|
|
self.rect.y += self.vel_y
|
|
|
|
if self.rect.bottom >= HEIGHT - 50:
|
|
self.rect.bottom = HEIGHT - 50
|
|
self.vel_y = 0
|
|
self.on_ground = True
|
|
|
|
def attack(self):
|
|
if self.attack_cooldown == 0:
|
|
self.attacking = True
|
|
self.attack_cooldown = 20
|
|
if self.facing_right:
|
|
self.attack_box = pygame.Rect(self.rect.right, self.rect.y + 20, 60, 50)
|
|
else:
|
|
self.attack_box = pygame.Rect(self.rect.left - 60, self.rect.y + 20, 60, 50)
|
|
|
|
def update(self):
|
|
if self.attack_cooldown > 0: self.attack_cooldown -= 1
|
|
else: self.attacking = False
|
|
|
|
if self.hit_timer > 0:
|
|
self.hit_timer -= 1
|
|
self.color = WHITE
|
|
else:
|
|
self.color = self.original_color
|
|
|
|
def draw(self, surface):
|
|
pygame.draw.rect(surface, self.color, self.rect)
|
|
pygame.draw.rect(surface, BLACK, self.rect, 2)
|
|
|
|
head_rect = pygame.Rect(self.rect.x + 10, self.rect.y - 20, 30, 20)
|
|
pygame.draw.rect(surface, self.color, head_rect)
|
|
pygame.draw.rect(surface, BLACK, head_rect, 2)
|
|
|
|
eye_color = BLACK
|
|
if self.facing_right:
|
|
pygame.draw.rect(surface, eye_color, (self.rect.x + 30, self.rect.y - 15, 5, 5))
|
|
else:
|
|
pygame.draw.rect(surface, eye_color, (self.rect.x + 15, self.rect.y - 15, 5, 5))
|
|
|
|
if self.attacking:
|
|
pygame.draw.rect(surface, YELLOW, self.attack_box)
|
|
pygame.draw.rect(surface, WHITE, self.attack_box, 2)
|
|
|
|
def take_damage(self, amount):
|
|
self.health -= amount
|
|
self.hit_timer = 10
|
|
self.vel_y = -5
|
|
if self.rect.centerx < WIDTH // 2: self.rect.x -= 20
|
|
else: self.rect.x += 20
|
|
|
|
# --- Fona Zīmēšanas Funkcijas ---
|
|
|
|
def draw_city(surface):
|
|
surface.fill((20, 30, 50)) # Nakts debesis
|
|
pygame.draw.circle(surface, (200, 200, 200), (WIDTH//2, 100), 60) # Mēness
|
|
for i in range(5):
|
|
w = random.randint(50, 150)
|
|
h = random.randint(200, 400)
|
|
x = i * (WIDTH // 5) + 20
|
|
pygame.draw.rect(surface, (10, 10, 20), (x, HEIGHT - 50 - h, w-10, h)) # Ēkas
|
|
pygame.draw.rect(surface, BROWN, (0, HEIGHT - 50, WIDTH, 50)) # Zeme
|
|
|
|
def draw_forest(surface):
|
|
surface.fill((50, 150, 50)) # Gaiši zaļš debesis/ugs
|
|
pygame.draw.circle(surface, (255, 255, 100), (WIDTH - 100, 80), 50) # Saule
|
|
for i in range(8):
|
|
x = i * (WIDTH // 8) + 40
|
|
# Koku stumbri
|
|
pygame.draw.rect(surface, (80, 50, 20), (x, HEIGHT - 200, 40, 150))
|
|
# Koku vainagi (trīsstūri stilā)
|
|
pygame.draw.polygon(surface, (20, 100, 20), [(x-40, HEIGHT-200), (x+40, HEIGHT-200), (x, HEIGHT-300)])
|
|
pygame.draw.polygon(surface, (20, 100, 20), [(x-35, HEIGHT-240), (x+35, HEIGHT-240), (x, HEIGHT-340)])
|
|
pygame.draw.rect(surface, (30, 100, 30), (0, HEIGHT - 50, WIDTH, 50)) # Zāle
|
|
|
|
def draw_dojo(surface):
|
|
surface.fill((180, 100, 50)) # Koka sieni
|
|
# Girdīngs
|
|
pygame.draw.rect(surface, (100, 50, 0), (0, HEIGHT - 200, WIDTH, 50))
|
|
pygame.draw.rect(surface, (100, 50, 0), (0, 0, WIDTH, 50))
|
|
# Vairogzīmes
|
|
for i in range(1, 10):
|
|
x = i * (WIDTH // 10)
|
|
pygame.draw.line(surface, (50, 0, 0), (x, 50), (x, HEIGHT - 200), 2)
|
|
pygame.draw.rect(surface, (50, 0, 0), (0, HEIGHT - 50, WIDTH, 50)) # Sarkanā grīda
|
|
|
|
def get_bg_function(name):
|
|
if name == "CITY": return draw_city
|
|
if name == "FOREST": return draw_forest
|
|
return draw_dojo
|
|
|
|
# --- Dialogi ---
|
|
class DialogueManager:
|
|
def __init__(self):
|
|
self.lines = [
|
|
"PREPARE FOR BATTLE!",
|
|
"Who will win today?",
|
|
"Fight with honor!",
|
|
"Show me your moves!"
|
|
]
|
|
self.current_text = random.choice(self.lines)
|
|
self.active = False
|
|
self.timer = 0
|
|
|
|
def start(self):
|
|
self.active = True
|
|
self.timer = pygame.time.get_ticks()
|
|
self.current_text = random.choice(self.lines)
|
|
|
|
def draw(self, surface):
|
|
if not self.active: return
|
|
|
|
# Kaste
|
|
box_rect = pygame.Rect(WIDTH//2 - 300, HEIGHT//2 - 50, 600, 100)
|
|
pygame.draw.rect(surface, BLACK, box_rect)
|
|
pygame.draw.rect(surface, WHITE, box_rect, 4)
|
|
|
|
# Teksts
|
|
text_surf = FONT_MED.render(self.current_text, True, YELLOW)
|
|
surface.blit(text_surf, (box_rect.centerx - text_surf.get_width()//2, box_rect.centery - text_surf.get_height()//2))
|
|
|
|
# Instrukcija
|
|
sub_surf = FONT_SMALL.render("Nospiediet [SPACE] lai sāktu", True, WHITE)
|
|
surface.blit(sub_surf, (box_rect.centerx - sub_surf.get_width()//2, box_rect.bottom + 10))
|
|
|
|
# --- Galvenā Spēle ---
|
|
|
|
def main():
|
|
global STATE, P1_COLOR, P2_COLOR, SELECTED_BG
|
|
|
|
# Kontroles
|
|
controls_p1 = {'left': pygame.K_a, 'right': pygame.K_d, 'jump': pygame.K_w, 'attack': pygame.K_SPACE}
|
|
# P2 uzbrukums tagad ir Enter taustiņš
|
|
controls_p2 = {'left': pygame.K_LEFT, 'right': pygame.K_RIGHT, 'jump': pygame.K_UP, 'attack': pygame.K_RETURN}
|
|
|
|
dialogue_mgr = DialogueManager()
|
|
|
|
# Izveidojam pogas
|
|
menu_buttons = [
|
|
Button(WIDTH//2 - 100, 200, 200, 50, "Sakt Cīnu", GRAY, DARK_GRAY, "START"),
|
|
Button(WIDTH//2 - 100, 270, 200, 50, "Tēlu Izvēle", GRAY, DARK_GRAY, "CHARS"),
|
|
Button(WIDTH//2 - 100, 340, 200, 50, "Fona Izvēle", GRAY, DARK_GRAY, "BG"),
|
|
Button(WIDTH//2 - 100, 410, 200, 50, "Iziet", RED, (150, 0, 0), "QUIT")
|
|
]
|
|
|
|
bg_buttons = [
|
|
Button(200, 300, 150, 100, "CITY", (20, 30, 50), DARK_GRAY, "CITY"),
|
|
Button(425, 300, 150, 100, "FOREST", (50, 150, 50), DARK_GRAY, "FOREST"),
|
|
Button(650, 300, 150, 100, "DOJO", (180, 100, 50), DARK_GRAY, "DOJO"),
|
|
Button(WIDTH//2 - 100, 450, 200, 50, "Atpakaļ", GRAY, DARK_GRAY, "BACK")
|
|
]
|
|
|
|
back_btn = Button(20, 20, 100, 40, "Atpakaļ", GRAY, DARK_GRAY, "BACK")
|
|
|
|
# Spēlētāji (sākotnēji None, tiek veidoti pirms spēles)
|
|
fighter1 = None
|
|
fighter2 = None
|
|
|
|
run = True
|
|
while run:
|
|
CLOCK.tick(60)
|
|
mouse_pos = pygame.mouse.get_pos()
|
|
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
run = False
|
|
|
|
# Pogu apstrāde atkarībā no stāvokļa
|
|
if STATE == "MENU":
|
|
for btn in menu_buttons:
|
|
if btn.is_clicked(event):
|
|
if btn.action_code == "START":
|
|
dialogue_mgr.start()
|
|
STATE = "DIALOGUE"
|
|
elif btn.action_code == "CHARS":
|
|
STATE = "CHAR_SELECT"
|
|
elif btn.action_code == "BG":
|
|
STATE = "BG_SELECT"
|
|
elif btn.action_code == "QUIT":
|
|
run = False
|
|
|
|
elif STATE == "CHAR_SELECT":
|
|
# P1 izvēle (kreisā puse)
|
|
for i, color in enumerate(COLORS):
|
|
rect = pygame.Rect(150 + i*60, 200, 50, 50)
|
|
if event.type == pygame.MOUSEBUTTONDOWN and rect.collidepoint(event.pos):
|
|
P1_COLOR = color
|
|
|
|
# P2 izvēle (labā puse)
|
|
for i, color in enumerate(COLORS):
|
|
rect = pygame.Rect(WIDTH - 450 + i*60, 200, 50, 50)
|
|
if event.type == pygame.MOUSEBUTTONDOWN and rect.collidepoint(event.pos):
|
|
P2_COLOR = color
|
|
|
|
if back_btn.is_clicked(event):
|
|
STATE = "MENU"
|
|
|
|
elif STATE == "BG_SELECT":
|
|
for btn in bg_buttons:
|
|
if btn.is_clicked(event):
|
|
if btn.action_code == "BACK":
|
|
STATE = "MENU"
|
|
else:
|
|
SELECTED_BG = btn.action_code
|
|
|
|
elif STATE == "DIALOGUE":
|
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
|
|
dialogue_mgr.active = False
|
|
# Inicializējam spēli
|
|
fighter1 = Fighter(200, 300, P1_COLOR, True, controls_p1)
|
|
fighter2 = Fighter(800, 300, P2_COLOR, False, controls_p2)
|
|
STATE = "GAME"
|
|
|
|
elif STATE == "GAME":
|
|
if event.type == pygame.KEYDOWN:
|
|
if event.key == fighter1.controls['attack']: fighter1.attack()
|
|
if event.key == fighter2.controls['attack']: fighter2.attack()
|
|
|
|
elif STATE == "GAMEOVER":
|
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_r:
|
|
STATE = "MENU"
|
|
|
|
# --- Zīmēšanas Loģika ---
|
|
|
|
if STATE == "MENU":
|
|
SCREEN.fill(BLACK)
|
|
title = FONT_BIG.render("PIXEL KOMBAT", True, WHITE)
|
|
SCREEN.blit(title, (WIDTH//2 - title.get_width()//2, 100))
|
|
for btn in menu_buttons: btn.draw(SCREEN)
|
|
|
|
elif STATE == "CHAR_SELECT":
|
|
SCREEN.fill(DARK_GRAY)
|
|
|
|
title = FONT_MED.render("IZVĒLIES TĒLU", True, WHITE)
|
|
SCREEN.blit(title, (WIDTH//2 - title.get_width()//2, 50))
|
|
|
|
# Zīmējam P1 paneli
|
|
p1_text = FONT_SMALL.render("PLAYER 1", True, P1_COLOR)
|
|
SCREEN.blit(p1_text, (200, 150))
|
|
for i, color in enumerate(COLORS):
|
|
r = pygame.Rect(150 + i*60, 200, 50, 50)
|
|
pygame.draw.rect(SCREEN, color, r)
|
|
pygame.draw.rect(SCREEN, WHITE, r, 2 if color != P1_COLOR else 5)
|
|
|
|
# Zīmējam P2 paneli
|
|
p2_text = FONT_SMALL.render("PLAYER 2", True, P2_COLOR)
|
|
SCREEN.blit(p2_text, (WIDTH - 350, 150))
|
|
for i, color in enumerate(COLORS):
|
|
r = pygame.Rect(WIDTH - 450 + i*60, 200, 50, 50)
|
|
pygame.draw.rect(SCREEN, color, r)
|
|
pygame.draw.rect(SCREEN, WHITE, r, 2 if color != P2_COLOR else 5)
|
|
|
|
back_btn.draw(SCREEN)
|
|
|
|
elif STATE == "BG_SELECT":
|
|
SCREEN.fill(BLACK)
|
|
title = FONT_MED.render("IZVĒLIES VIDI", True, WHITE)
|
|
SCREEN.blit(title, (WIDTH//2 - title.get_width()//2, 50))
|
|
|
|
for btn in bg_buttons:
|
|
btn.draw(SCREEN)
|
|
|
|
elif STATE == "DIALOGUE":
|
|
# Rādam fona priekšskatījumu aiz dialoga
|
|
get_bg_function(SELECTED_BG)(SCREEN)
|
|
dialogue_mgr.draw(SCREEN)
|
|
|
|
elif STATE == "GAME":
|
|
keys = pygame.key.get_pressed()
|
|
|
|
# Spēles loģika
|
|
fighter1.move(keys)
|
|
fighter2.move(keys)
|
|
fighter1.update()
|
|
fighter2.update()
|
|
|
|
if fighter1.attacking and fighter1.attack_box.colliderect(fighter2.rect):
|
|
if fighter2.hit_timer == 0: fighter2.take_damage(5)
|
|
if fighter2.attacking and fighter2.attack_box.colliderect(fighter1.rect):
|
|
if fighter1.hit_timer == 0: fighter1.take_damage(5)
|
|
|
|
if fighter1.health <= 0 or fighter2.health <= 0:
|
|
STATE = "GAMEOVER"
|
|
winner = "PLAYER 1" if fighter2.health <= 0 else "PLAYER 2"
|
|
|
|
# Zīmēšana
|
|
bg_func = get_bg_function(SELECTED_BG)
|
|
bg_func(SCREEN)
|
|
|
|
fighter1.draw(SCREEN)
|
|
fighter2.draw(SCREEN)
|
|
|
|
# Health bars
|
|
pygame.draw.rect(SCREEN, BLACK, (20, 20, 400, 40))
|
|
pygame.draw.rect(SCREEN, RED, (20, 20, 400, 40))
|
|
pygame.draw.rect(SCREEN, P1_COLOR, (20, 20, (fighter1.health/100)*400, 40))
|
|
pygame.draw.rect(SCREEN, WHITE, (20, 20, 400, 40), 2)
|
|
|
|
pygame.draw.rect(SCREEN, BLACK, (WIDTH-420, 20, 400, 40))
|
|
pygame.draw.rect(SCREEN, RED, (WIDTH-420, 20, 400, 40))
|
|
pygame.draw.rect(SCREEN, P2_COLOR, (WIDTH-420, 20, (fighter2.health/100)*400, 40))
|
|
pygame.draw.rect(SCREEN, WHITE, (WIDTH-420, 20, 400, 40), 2)
|
|
|
|
elif STATE == "GAMEOVER":
|
|
SCREEN.fill(BLACK)
|
|
txt = FONT_BIG.render(f"{winner} WINS!", True, YELLOW)
|
|
restart = FONT_SMALL.render("Nospied [R] atgriezties uz izvēlni", True, WHITE)
|
|
|
|
SCREEN.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 50))
|
|
SCREEN.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT//2 + 50))
|
|
|
|
pygame.display.update()
|
|
|
|
pygame.quit()
|
|
|
|
if __name__ == "__main__":
|
|
main() |