Compare commits
No commits in common. "a605a9f95513135300e0d5d9b58a7d35cc368ae0" and "8c6563db34c8f99925825b78285134859063ac9d" have entirely different histories.
a605a9f955
...
8c6563db34
|
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 263 B |
|
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 280 B |
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
|
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
|
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 269 B |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
220
main.py
|
|
@ -1,6 +1,18 @@
|
||||||
import pygame
|
import pygame
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
#floor_score = 0
|
||||||
|
#if level_1 complete floor_score = 1 if level_2 complete floor_score = 2
|
||||||
|
#if floor_score == 0:
|
||||||
|
# show level 1
|
||||||
|
#elif floor_score == 1:
|
||||||
|
# show level 2
|
||||||
|
#elif floor_score == 2:
|
||||||
|
# show level 3
|
||||||
|
# if floor_score =2 and level_1 complete floor_score stays 2, goes one up in higher level completed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pygame.init()
|
pygame.init()
|
||||||
pygame.mixer.init()
|
pygame.mixer.init()
|
||||||
|
|
||||||
|
|
@ -37,8 +49,6 @@ score_knight = 0
|
||||||
paused = False
|
paused = False
|
||||||
|
|
||||||
|
|
||||||
floor_score = 1
|
|
||||||
MAX_FLOOR_SCORE = 8
|
|
||||||
|
|
||||||
class Player:
|
class Player:
|
||||||
def __init__(self, x, y, sprites, scale, controls):
|
def __init__(self, x, y, sprites, scale, controls):
|
||||||
|
|
@ -64,6 +74,10 @@ class Player:
|
||||||
self.walk_left = pygame.image.load(sprites["walk_left"]).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.walk_right = pygame.image.load(sprites["walk_right"]).convert_alpha()
|
||||||
|
|
||||||
|
# support three-stage jump:
|
||||||
|
# - sprites["jump"] can be a list/tuple of 3 paths [start, mid, end]
|
||||||
|
# - or provide explicit keys "jump_start", "jump_mid", "jump_end"
|
||||||
|
# - otherwise fallback to a single jump image (same for all stages)
|
||||||
jump_entry = sprites.get("jump")
|
jump_entry = sprites.get("jump")
|
||||||
if isinstance(jump_entry, (list, tuple)) and len(jump_entry) == 3:
|
if isinstance(jump_entry, (list, tuple)) and len(jump_entry) == 3:
|
||||||
self.jump_start = pygame.image.load(jump_entry[0]).convert_alpha()
|
self.jump_start = pygame.image.load(jump_entry[0]).convert_alpha()
|
||||||
|
|
@ -99,8 +113,8 @@ class Player:
|
||||||
self.facing_right = True
|
self.facing_right = True
|
||||||
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
|
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
|
||||||
|
|
||||||
|
|
||||||
def handle_input(self, keys):
|
def handle_input(self, keys):
|
||||||
# classic per-frame movement (no dt)
|
|
||||||
self.moving = False
|
self.moving = False
|
||||||
|
|
||||||
if keys[self.controls["right"]]:
|
if keys[self.controls["right"]]:
|
||||||
|
|
@ -117,13 +131,14 @@ class Player:
|
||||||
self.jumping = True
|
self.jumping = True
|
||||||
self.y_velocity = -self.jump_power
|
self.y_velocity = -self.jump_power
|
||||||
|
|
||||||
|
|
||||||
if self.x < 0:
|
if self.x < 0:
|
||||||
self.x = 0
|
self.x = 0
|
||||||
if self.x > WIDTH:
|
if self.x > WIDTH:
|
||||||
self.x = WIDTH
|
self.x = WIDTH
|
||||||
|
|
||||||
|
|
||||||
def apply_gravity(self):
|
def apply_gravity(self):
|
||||||
# classic per-frame gravity (no dt)
|
|
||||||
self.y_velocity += GRAVITY
|
self.y_velocity += GRAVITY
|
||||||
self.y += self.y_velocity
|
self.y += self.y_velocity
|
||||||
|
|
||||||
|
|
@ -132,8 +147,13 @@ class Player:
|
||||||
self.y_velocity = 0
|
self.y_velocity = 0
|
||||||
self.jumping = False
|
self.jumping = False
|
||||||
|
|
||||||
|
|
||||||
def update_animation(self):
|
def update_animation(self):
|
||||||
if self.jumping:
|
if self.jumping:
|
||||||
|
# choose jump stage by vertical velocity:
|
||||||
|
# - strong negative: start (ascending)
|
||||||
|
# - near zero: mid (apex)
|
||||||
|
# - positive: end (descending)
|
||||||
up_thresh = -self.jump_power * 0.4
|
up_thresh = -self.jump_power * 0.4
|
||||||
down_thresh = self.jump_power * 0.4
|
down_thresh = self.jump_power * 0.4
|
||||||
if self.y_velocity < up_thresh:
|
if self.y_velocity < up_thresh:
|
||||||
|
|
@ -205,194 +225,100 @@ door_rect = door_image.get_rect(center=(800, 700))
|
||||||
button_play = pygame.image.load("images/play_button.png")
|
button_play = pygame.image.load("images/play_button.png")
|
||||||
button_rect = button_play.get_rect(center=(500, 400))
|
button_rect = button_play.get_rect(center=(500, 400))
|
||||||
|
|
||||||
# BUTTONS PLAY (original images)
|
|
||||||
buttonlvl1 = pygame.image.load("images/button_lvl/F1.png")
|
|
||||||
buttonlvl2 = pygame.image.load("images/button_lvl/F2.png")
|
|
||||||
buttonlvl3 = pygame.image.load("images/button_lvl/F3.png")
|
|
||||||
buttonlvl4 = pygame.image.load("images/button_lvl/F4.png")
|
|
||||||
buttonlvl5 = pygame.image.load("images/button_lvl/F5.png")
|
|
||||||
buttonlvl6 = pygame.image.load("images/button_lvl/F6.png")
|
|
||||||
buttonlvl7 = pygame.image.load("images/button_lvl/F7.png")
|
|
||||||
buttonlvl8 = pygame.image.load("images/button_lvl/F8.png")
|
|
||||||
|
|
||||||
# make level buttons larger
|
|
||||||
BUTTON_BIG_SIZE = (220, 140) # можно подправить под нужный размер
|
|
||||||
buttonlvl1_big = pygame.transform.scale(buttonlvl1, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl2_big = pygame.transform.scale(buttonlvl2, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl3_big = pygame.transform.scale(buttonlvl3, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl4_big = pygame.transform.scale(buttonlvl4, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl5_big = pygame.transform.scale(buttonlvl5, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl6_big = pygame.transform.scale(buttonlvl6, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl7_big = pygame.transform.scale(buttonlvl7, BUTTON_BIG_SIZE)
|
|
||||||
buttonlvl8_big = pygame.transform.scale(buttonlvl8, BUTTON_BIG_SIZE)
|
|
||||||
|
|
||||||
# rects (centers kept as before)
|
|
||||||
buttonlvl1_rect = buttonlvl1_big.get_rect(center=(300, 300))
|
|
||||||
buttonlvl2_rect = buttonlvl2_big.get_rect(center=(600, 300))
|
|
||||||
buttonlvl3_rect = buttonlvl3_big.get_rect(center=(900, 300))
|
|
||||||
buttonlvl4_rect = buttonlvl4_big.get_rect(center=(300, 600))
|
|
||||||
buttonlvl5_rect = buttonlvl5_big.get_rect(center=(600, 600))
|
|
||||||
buttonlvl6_rect = buttonlvl6_big.get_rect(center=(900, 600))
|
|
||||||
buttonlvl7_rect = buttonlvl7_big.get_rect(center=(300, 900))
|
|
||||||
buttonlvl8_rect = buttonlvl8_big.get_rect(center=(600, 900))
|
|
||||||
|
|
||||||
level_buttons = [
|
|
||||||
None,
|
|
||||||
(buttonlvl1_big, buttonlvl1_rect),
|
|
||||||
(buttonlvl2_big, buttonlvl2_rect),
|
|
||||||
(buttonlvl3_big, buttonlvl3_rect),
|
|
||||||
(buttonlvl4_big, buttonlvl4_rect),
|
|
||||||
(buttonlvl5_big, buttonlvl5_rect),
|
|
||||||
(buttonlvl6_big, buttonlvl6_rect),
|
|
||||||
(buttonlvl7_big, buttonlvl7_rect),
|
|
||||||
(buttonlvl8_big, buttonlvl8_rect),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Levels (backgrounds) - scale to screen size so entering level shows its background
|
|
||||||
level1 = pygame.image.load("images/Levels/floor1.png")
|
|
||||||
level2 = pygame.image.load("images/Levels/floor2.png")
|
|
||||||
level3 = pygame.image.load("images/Levels/floor3.png")
|
|
||||||
level4 = pygame.image.load("images/Levels/floor4.png")
|
|
||||||
level5 = pygame.image.load("images/Levels/floor5.png")
|
|
||||||
level6 = pygame.image.load("images/Levels/floor6.png")
|
|
||||||
level7 = pygame.image.load("images/Levels/floor7.png")
|
|
||||||
level8 = pygame.image.load("images/Levels/floor8.png")
|
|
||||||
|
|
||||||
level_bgs = [
|
|
||||||
None,
|
|
||||||
pygame.transform.scale(level1, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level2, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level3, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level4, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level5, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level6, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level7, (WIDTH, HEIGHT)),
|
|
||||||
pygame.transform.scale(level8, (WIDTH, HEIGHT)),
|
|
||||||
]
|
|
||||||
|
|
||||||
# helper: map F-key constants to level numbers
|
|
||||||
KEY_TO_LEVEL = {
|
|
||||||
pygame.K_F1: 1,
|
|
||||||
pygame.K_F2: 2,
|
|
||||||
pygame.K_F3: 3,
|
|
||||||
pygame.K_F4: 4,
|
|
||||||
pygame.K_F5: 5,
|
|
||||||
pygame.K_F6: 6,
|
|
||||||
pygame.K_F7: 7,
|
|
||||||
pygame.K_F8: 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
current_level_bg = None
|
|
||||||
|
|
||||||
def restart_level():
|
def restart_level():
|
||||||
goblin.reset()
|
goblin.reset()
|
||||||
knight.reset()
|
knight.reset()
|
||||||
|
|
||||||
|
|
||||||
level = 0 # 0 = initial splash (BACKGROUND + Play), -1 = level select (BACK_MAIN), 1..8 = playing levels
|
level = 0
|
||||||
level_start_time = None
|
level_start_time = None
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.KEYDOWN:
|
||||||
# ESC only toggles pause while playing a level
|
if event.key == pygame.K_ESCAPE and level == 1:
|
||||||
if event.key == pygame.K_ESCAPE and level > 0:
|
|
||||||
paused = not paused
|
paused = not paused
|
||||||
# R returns to initial splash
|
|
||||||
if event.key == pygame.K_r:
|
if event.key == pygame.K_r:
|
||||||
restart_level()
|
restart_level()
|
||||||
level = 0
|
level = 0
|
||||||
|
|
||||||
# Level hotkeys: F1..F8 available on level-select screen (level == -1)
|
|
||||||
if level == -1 and event.key in KEY_TO_LEVEL:
|
|
||||||
target = KEY_TO_LEVEL[event.key]
|
|
||||||
if target <= floor_score: # only if unlocked
|
|
||||||
restart_level()
|
|
||||||
level = target
|
|
||||||
level_start_time = pygame.time.get_ticks()
|
|
||||||
current_level_bg = level_bgs[level]
|
|
||||||
if BG_MUSIC:
|
|
||||||
try: pygame.mixer.music.play(-1)
|
|
||||||
except Exception: pass
|
|
||||||
|
|
||||||
keys = pygame.key.get_pressed()
|
keys = pygame.key.get_pressed()
|
||||||
mouse_pos = pygame.mouse.get_pos()
|
mouse_pos = pygame.mouse.get_pos()
|
||||||
|
|
||||||
SCREEN.fill((0, 0, 0))
|
SCREEN.fill((0, 0, 0))
|
||||||
|
|
||||||
# Initial splash: BACKGROUND with only Play button
|
|
||||||
if level == 0:
|
if level == 0:
|
||||||
SCREEN.blit(BACKGROUND, (0, 0))
|
SCREEN.blit(BACK_MAIN, (0, 0))
|
||||||
SCREEN.blit(button_play, button_rect)
|
SCREEN.blit(button_play, button_rect)
|
||||||
|
|
||||||
title_surf = FONT.render('Goblin & Knight', True, (255,255,255))
|
title_surf = FONT.render('Goblin & Knight', True, (255,255,255))
|
||||||
SCREEN.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 120))
|
SCREEN.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 120))
|
||||||
|
|
||||||
if button_rect.collidepoint(mouse_pos) and pygame.mouse.get_pressed()[0]:
|
if button_rect.collidepoint(mouse_pos) and pygame.mouse.get_pressed()[0]:
|
||||||
# go to level-select screen
|
restart_level()
|
||||||
level = -1
|
level = 1
|
||||||
|
level_start_time = pygame.time.get_ticks()
|
||||||
# Level-select screen: BACK_MAIN with level buttons (F1..F8)
|
if BG_MUSIC:
|
||||||
elif level == -1:
|
try:
|
||||||
SCREEN.blit(BACK_MAIN, (0, 0))
|
pygame.mixer.music.play(-1)
|
||||||
|
except Exception:
|
||||||
title_surf = FONT.render('Select Level (F1..F8) — unlocked in order', True, (255,255,255))
|
pass
|
||||||
SCREEN.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 80))
|
|
||||||
|
|
||||||
# draw level buttons (dim locked ones)
|
|
||||||
for i in range(1, 9):
|
|
||||||
btn_surf, btn_rect = level_buttons[i]
|
|
||||||
if i <= floor_score:
|
|
||||||
SCREEN.blit(btn_surf, btn_rect)
|
|
||||||
else:
|
|
||||||
# draw dimmed (locked) version
|
|
||||||
locked = btn_surf.copy()
|
|
||||||
locked.set_alpha(90)
|
|
||||||
SCREEN.blit(locked, btn_rect)
|
|
||||||
# draw small lock text
|
|
||||||
lock_txt = FONT.render('LOCKED', True, (200, 40, 40))
|
|
||||||
SCREEN.blit(lock_txt, (btn_rect.centerx - lock_txt.get_width()//2, btn_rect.centery - 10))
|
|
||||||
|
|
||||||
# mouse clicks on unlocked buttons start levels
|
|
||||||
if pygame.mouse.get_pressed()[0]:
|
|
||||||
for i in range(1, 9):
|
|
||||||
btn_surf, btn_rect = level_buttons[i]
|
|
||||||
if btn_rect.collidepoint(mouse_pos) and i <= floor_score:
|
|
||||||
restart_level()
|
|
||||||
level = i
|
|
||||||
level_start_time = pygame.time.get_ticks()
|
|
||||||
current_level_bg = level_bgs[level]
|
|
||||||
if BG_MUSIC:
|
|
||||||
try: pygame.mixer.music.play(-1)
|
|
||||||
except Exception: pass
|
|
||||||
break
|
|
||||||
|
|
||||||
# Playing any level (1..8)
|
|
||||||
elif level > 0:
|
|
||||||
if current_level_bg:
|
|
||||||
SCREEN.blit(current_level_bg, (0, 0))
|
|
||||||
else:
|
|
||||||
SCREEN.blit(BACKGROUND, (0, 0))
|
|
||||||
|
|
||||||
|
elif level == 1:
|
||||||
|
SCREEN.blit(BACKGROUND, (0, 0))
|
||||||
SCREEN.blit(door_image, door_rect)
|
SCREEN.blit(door_image, door_rect)
|
||||||
|
|
||||||
if not paused:
|
if not paused:
|
||||||
# reverted to per-frame calls (no dt)
|
|
||||||
goblin.handle_input(keys)
|
goblin.handle_input(keys)
|
||||||
goblin.apply_gravity()
|
goblin.apply_gravity()
|
||||||
goblin.update_animation()
|
goblin.update_animation()
|
||||||
|
|
||||||
|
|
||||||
knight.handle_input(keys)
|
knight.handle_input(keys)
|
||||||
knight.apply_gravity()
|
knight.apply_gravity()
|
||||||
knight.update_animation()
|
knight.update_animation()
|
||||||
|
|
||||||
goblin.draw(SCREEN)
|
goblin.draw(SCREEN)
|
||||||
knight.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))
|
||||||
|
|
||||||
# ...existing HUD and level-complete logic...
|
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()
|
pygame.display.update()
|
||||||
#CLOCK.tick(FPS)
|
CLOCK.tick(FPS)
|
||||||