BIN
images/door.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 500 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 908 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 15 KiB |
261
main.py
|
|
@ -87,6 +87,9 @@ class Player:
|
||||||
self.surface = self.stand
|
self.surface = self.stand
|
||||||
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
|
self.rect = self.surface.get_rect(midbottom=(self.x, self.y))
|
||||||
|
|
||||||
|
|
||||||
|
self.prev_y = self.y
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.x = self.start_x
|
self.x = self.start_x
|
||||||
self.y = self.start_y
|
self.y = self.start_y
|
||||||
|
|
@ -120,6 +123,8 @@ class Player:
|
||||||
self.x = WIDTH
|
self.x = WIDTH
|
||||||
|
|
||||||
def apply_gravity(self):
|
def apply_gravity(self):
|
||||||
|
|
||||||
|
self.prev_y = self.y
|
||||||
self.y_velocity += GRAVITY
|
self.y_velocity += GRAVITY
|
||||||
self.y += self.y_velocity
|
self.y += self.y_velocity
|
||||||
|
|
||||||
|
|
@ -190,7 +195,27 @@ knight = Player(
|
||||||
)
|
)
|
||||||
|
|
||||||
door_image = pygame.image.load("images/door.png")
|
door_image = pygame.image.load("images/door.png")
|
||||||
door_rect = door_image.get_rect(center=(800, 700))
|
door_image = pygame.transform.scale(door_image, (int(door_image.get_width() * 3), int(door_image.get_height() * 3)))
|
||||||
|
|
||||||
|
door_rect = door_image.get_rect(center=(WIDTH//2, GROUND_Y - door_image.get_height()//2))
|
||||||
|
|
||||||
|
def place_door_for_level(lvl):
|
||||||
|
"""Разместить дверь на одной из платформ уровня (предпочтительно над землёй, ближе к центру)."""
|
||||||
|
global door_rect
|
||||||
|
plats = build_platform_rects(lvl)
|
||||||
|
if not plats:
|
||||||
|
door_rect = door_image.get_rect(center=(WIDTH//2, GROUND_Y - door_image.get_height()//2))
|
||||||
|
return
|
||||||
|
candidates = [p for p in plats if p.top < GROUND_Y - 10]
|
||||||
|
if not candidates:
|
||||||
|
candidates = plats
|
||||||
|
|
||||||
|
candidates.sort(key=lambda p: abs(p.centerx - WIDTH//2))
|
||||||
|
chosen = candidates[0]
|
||||||
|
|
||||||
|
door_rect = door_image.get_rect(midbottom=(chosen.centerx, chosen.top))
|
||||||
|
|
||||||
|
door_rect.clamp_ip(pygame.Rect(0, 0, WIDTH, HEIGHT))
|
||||||
|
|
||||||
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))
|
||||||
|
|
@ -267,12 +292,221 @@ KEY_TO_LEVEL = {
|
||||||
pygame.K_F8: 8,
|
pygame.K_F8: 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dirt_smol = pygame.image.load("images/platforms-named/dirt_smol.png")
|
||||||
|
dirt_smol = pygame.transform.scale(dirt_smol, (int(dirt_smol.get_width() * 5), int(dirt_smol.get_height() * 3)))
|
||||||
|
dirt_big = pygame.image.load("images/platforms-named/dirt_big.png")
|
||||||
|
dirt_big = pygame.transform.scale(dirt_big, (int(dirt_big.get_width() * 5), int(dirt_big.get_height() * 3)))
|
||||||
|
grass_smol = pygame.image.load("images/platforms-named/grass_smol.png")
|
||||||
|
grass_smol = pygame.transform.scale(grass_smol, (int(grass_smol.get_width() * 5), int(grass_smol.get_height() * 3)))
|
||||||
|
grass_big = pygame.image.load("images/platforms-named/grass_big.png")
|
||||||
|
grass_big = pygame.transform.scale(grass_big, (int(grass_big.get_width() * 5), int(grass_big.get_height() * 3)))
|
||||||
|
sand_smol = pygame.image.load("images/platforms-named/sand_smol.png")
|
||||||
|
sand_smol = pygame.transform.scale(sand_smol, (int(sand_smol.get_width() * 5), int(sand_smol.get_height() * 3)))
|
||||||
|
sand_big = pygame.image.load("images/platforms-named/sand_big.png")
|
||||||
|
sand_big = pygame.transform.scale(sand_big, (int(sand_big.get_width() * 5), int(sand_big.get_height() * 3)))
|
||||||
|
ice_smol = pygame.image.load("images/platforms-named/ice_smol.png")
|
||||||
|
ice_smol = pygame.transform.scale(ice_smol, (int(ice_smol.get_width() * 5), int(ice_smol.get_height() * 3)))
|
||||||
|
ice_big = pygame.image.load("images/platforms-named/ice_big.png")
|
||||||
|
ice_big = pygame.transform.scale(ice_big, (int(ice_big.get_width() * 5), int(ice_big.get_height() * 3)))
|
||||||
|
|
||||||
|
PLATFORM_IMAGES = {
|
||||||
|
"dirt_smol": dirt_smol,
|
||||||
|
"dirt_big": dirt_big,
|
||||||
|
"grass_smol": grass_smol,
|
||||||
|
"grass_big": grass_big,
|
||||||
|
"sand_smol": sand_smol,
|
||||||
|
"sand_big": sand_big,
|
||||||
|
"ice_smol": ice_smol,
|
||||||
|
"ice_big": ice_big,
|
||||||
|
}
|
||||||
|
|
||||||
|
LEVEL_BLOCKS = {
|
||||||
|
1: [
|
||||||
|
("dirt_big", (80, GROUND_Y)),
|
||||||
|
("grass_smol",(220, GROUND_Y - 120)),
|
||||||
|
("dirt_smol", (360, GROUND_Y - 200)),
|
||||||
|
("sand_smol", (500, GROUND_Y - 260)),
|
||||||
|
("ice_smol", (640, GROUND_Y - 320)),
|
||||||
|
("grass_big", (780, GROUND_Y - 80)),
|
||||||
|
("sand_big", (920, GROUND_Y)),
|
||||||
|
("dirt_smol", (1060, GROUND_Y - 240)),
|
||||||
|
("grass_smol",(1200, GROUND_Y - 140)),
|
||||||
|
("ice_big", (1340, GROUND_Y)),
|
||||||
|
("dirt_big", (1480, GROUND_Y - 60)),
|
||||||
|
("sand_smol", (1620, GROUND_Y - 200)),
|
||||||
|
("grass_smol",(1760, GROUND_Y - 280)),
|
||||||
|
("ice_smol", (1000, GROUND_Y - 420)),
|
||||||
|
("dirt_smol", (400, GROUND_Y - 360)),
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
("sand_big", (120, GROUND_Y)),
|
||||||
|
("dirt_smol", (260, GROUND_Y - 160)),
|
||||||
|
("grass_smol",(400, GROUND_Y - 120)),
|
||||||
|
("ice_smol", (540, GROUND_Y - 300)),
|
||||||
|
("dirt_big", (680, GROUND_Y - 40)),
|
||||||
|
("sand_smol", (820, GROUND_Y - 220)),
|
||||||
|
("grass_big", (960, GROUND_Y)),
|
||||||
|
("ice_big", (1100, GROUND_Y - 20)),
|
||||||
|
("dirt_smol", (1240, GROUND_Y - 260)),
|
||||||
|
("sand_smol", (1380, GROUND_Y - 320)),
|
||||||
|
("grass_smol",(1520, GROUND_Y - 180)),
|
||||||
|
("dirt_big", (1660, GROUND_Y - 80)),
|
||||||
|
("ice_smol", (1800, GROUND_Y - 360)),
|
||||||
|
("grass_smol",(900, GROUND_Y - 420)),
|
||||||
|
("dirt_smol", (520, GROUND_Y - 360)),
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
("grass_big", (100, GROUND_Y)),
|
||||||
|
("sand_smol", (260, GROUND_Y - 200)),
|
||||||
|
("dirt_smol", (420, GROUND_Y - 140)),
|
||||||
|
("ice_smol", (580, GROUND_Y - 320)),
|
||||||
|
("grass_smol",(740, GROUND_Y - 240)),
|
||||||
|
("dirt_big", (900, GROUND_Y - 60)),
|
||||||
|
("sand_big", (1060, GROUND_Y)),
|
||||||
|
("ice_big", (1220, GROUND_Y - 40)),
|
||||||
|
("grass_smol",(1380, GROUND_Y - 300)),
|
||||||
|
("dirt_smol", (1540, GROUND_Y - 220)),
|
||||||
|
("sand_smol", (1700, GROUND_Y - 160)),
|
||||||
|
("grass_smol",(860, GROUND_Y - 420)),
|
||||||
|
("ice_smol", (480, GROUND_Y - 420)),
|
||||||
|
("dirt_big", (1320, GROUND_Y - 120)),
|
||||||
|
("grass_smol",(200, GROUND_Y - 320)),
|
||||||
|
],
|
||||||
|
4: [
|
||||||
|
("ice_big", (140, GROUND_Y)),
|
||||||
|
("ice_smol", (300, GROUND_Y - 140)),
|
||||||
|
("grass_smol",(460, GROUND_Y - 220)),
|
||||||
|
("sand_smol", (620, GROUND_Y - 180)),
|
||||||
|
("dirt_smol", (780, GROUND_Y - 360)),
|
||||||
|
("grass_big", (940, GROUND_Y - 80)),
|
||||||
|
("sand_big", (1100, GROUND_Y)),
|
||||||
|
("dirt_big", (1260, GROUND_Y - 40)),
|
||||||
|
("ice_smol", (1420, GROUND_Y - 300)),
|
||||||
|
("grass_smol",(1580, GROUND_Y - 240)),
|
||||||
|
("dirt_smol", (1740, GROUND_Y - 320)),
|
||||||
|
("ice_big", (820, GROUND_Y - 420)),
|
||||||
|
("sand_smol", (980, GROUND_Y - 260)),
|
||||||
|
("grass_smol",(540, GROUND_Y - 360)),
|
||||||
|
("dirt_big", (200, GROUND_Y - 80)),
|
||||||
|
],
|
||||||
|
5: [
|
||||||
|
("dirt_big", (60, GROUND_Y)),
|
||||||
|
("grass_big", (240, GROUND_Y - 80)),
|
||||||
|
("sand_smol", (420, GROUND_Y - 220)),
|
||||||
|
("ice_smol", (600, GROUND_Y - 320)),
|
||||||
|
("grass_smol",(780, GROUND_Y - 260)),
|
||||||
|
("dirt_smol", (960, GROUND_Y - 280)),
|
||||||
|
("sand_big", (1140, GROUND_Y)),
|
||||||
|
("ice_big", (1320, GROUND_Y - 40)),
|
||||||
|
("grass_smol",(1500, GROUND_Y - 200)),
|
||||||
|
("dirt_smol", (1680, GROUND_Y - 360)),
|
||||||
|
("sand_smol", (900, GROUND_Y - 420)),
|
||||||
|
("grass_big", (540, GROUND_Y - 140)),
|
||||||
|
("dirt_big", (1260, GROUND_Y - 120)),
|
||||||
|
("ice_smol", (300, GROUND_Y - 300)),
|
||||||
|
("grass_smol",(1740, GROUND_Y - 240)),
|
||||||
|
],
|
||||||
|
6: [
|
||||||
|
("sand_big", (140, GROUND_Y)),
|
||||||
|
("dirt_smol", (320, GROUND_Y - 160)),
|
||||||
|
("dirt_smol", (500, GROUND_Y - 160)),
|
||||||
|
("grass_smol",(680, GROUND_Y - 320)),
|
||||||
|
("ice_smol", (860, GROUND_Y - 300)),
|
||||||
|
("sand_smol", (1040, GROUND_Y - 300)),
|
||||||
|
("grass_big", (1220, GROUND_Y - 80)),
|
||||||
|
("dirt_big", (1400, GROUND_Y)),
|
||||||
|
("ice_big", (1580, GROUND_Y - 40)),
|
||||||
|
("grass_smol",(1760, GROUND_Y - 240)),
|
||||||
|
("dirt_smol", (940, GROUND_Y - 420)),
|
||||||
|
("sand_smol", (260, GROUND_Y - 260)),
|
||||||
|
("grass_smol",(460, GROUND_Y - 220)),
|
||||||
|
("dirt_big", (1100, GROUND_Y - 120)),
|
||||||
|
("ice_smol", (660, GROUND_Y - 360)),
|
||||||
|
],
|
||||||
|
7: [
|
||||||
|
("grass_big", (80, GROUND_Y)),
|
||||||
|
("ice_smol", (260, GROUND_Y - 180)),
|
||||||
|
("ice_smol", (440, GROUND_Y - 180)),
|
||||||
|
("sand_smol", (620, GROUND_Y - 260)),
|
||||||
|
("dirt_smol", (800, GROUND_Y - 350)),
|
||||||
|
("grass_smol",(980, GROUND_Y - 420)),
|
||||||
|
("sand_big", (1160, GROUND_Y)),
|
||||||
|
("dirt_big", (1340, GROUND_Y - 60)),
|
||||||
|
("ice_big", (1520, GROUND_Y - 20)),
|
||||||
|
("grass_smol",(1700, GROUND_Y - 300)),
|
||||||
|
("dirt_smol", (560, GROUND_Y - 320)),
|
||||||
|
("sand_smol", (920, GROUND_Y - 220)),
|
||||||
|
("grass_big", (1240, GROUND_Y - 100)),
|
||||||
|
("ice_smol", (420, GROUND_Y - 420)),
|
||||||
|
("dirt_smol", (140, GROUND_Y - 240)),
|
||||||
|
],
|
||||||
|
8: [
|
||||||
|
("ice_big", (100, GROUND_Y)),
|
||||||
|
("dirt_big", (300, GROUND_Y)),
|
||||||
|
("grass_smol",(500, GROUND_Y - 200)),
|
||||||
|
("sand_smol", (700, GROUND_Y - 320)),
|
||||||
|
("ice_smol", (900, GROUND_Y - 400)),
|
||||||
|
("dirt_smol", (1100, GROUND_Y - 360)),
|
||||||
|
("grass_smol",(1300, GROUND_Y - 300)),
|
||||||
|
("sand_big", (1500, GROUND_Y)),
|
||||||
|
("dirt_big", (1700, GROUND_Y - 40)),
|
||||||
|
("ice_big", (600, GROUND_Y - 420)),
|
||||||
|
("grass_big", (800, GROUND_Y - 120)),
|
||||||
|
("dirt_smol", (1000, GROUND_Y - 220)),
|
||||||
|
("sand_smol", (1200, GROUND_Y - 260)),
|
||||||
|
("ice_smol", (1400, GROUND_Y - 320)),
|
||||||
|
("grass_smol",(1600, GROUND_Y - 180)),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
current_level_bg = None
|
current_level_bg = None
|
||||||
|
|
||||||
def restart_level():
|
def restart_level():
|
||||||
goblin.reset()
|
goblin.reset()
|
||||||
knight.reset()
|
knight.reset()
|
||||||
|
|
||||||
|
def build_platform_rects(lvl):
|
||||||
|
"""Построить список rect'ов платформ текущего уровня."""
|
||||||
|
rects = []
|
||||||
|
for name, pos in LEVEL_BLOCKS.get(lvl, []):
|
||||||
|
img = PLATFORM_IMAGES.get(name)
|
||||||
|
if img:
|
||||||
|
rects.append(img.get_rect(midbottom=pos))
|
||||||
|
return rects
|
||||||
|
|
||||||
|
def resolve_platform_collision(player, platform_rects):
|
||||||
|
"""Простая обработка коллизий игрока с платформами (приземление и удар головой)."""
|
||||||
|
|
||||||
|
cur_rect = player.surface.get_rect(midbottom=(int(player.x), int(player.y)))
|
||||||
|
prev_rect = player.surface.get_rect(midbottom=(int(player.x), int(player.prev_y)))
|
||||||
|
|
||||||
|
for plat in platform_rects:
|
||||||
|
if cur_rect.colliderect(plat):
|
||||||
|
|
||||||
|
if prev_rect.bottom <= plat.top:
|
||||||
|
player.y = plat.top
|
||||||
|
player.y_velocity = 0
|
||||||
|
player.jumping = False
|
||||||
|
cur_rect = player.surface.get_rect(midbottom=(int(player.x), int(player.y)))
|
||||||
|
|
||||||
|
elif prev_rect.top >= plat.bottom:
|
||||||
|
|
||||||
|
top_offset = player.surface.get_rect().top
|
||||||
|
player.y = plat.bottom + (player.surface.get_height() - player.surface.get_rect().bottom)
|
||||||
|
player.y_velocity = 0.1
|
||||||
|
cur_rect = player.surface.get_rect(midbottom=(int(player.x), int(player.y)))
|
||||||
|
else:
|
||||||
|
|
||||||
|
if prev_rect.centerx < plat.centerx:
|
||||||
|
|
||||||
|
player.x = plat.left - cur_rect.width / 2
|
||||||
|
else:
|
||||||
|
|
||||||
|
player.x = plat.right + cur_rect.width / 2
|
||||||
|
cur_rect = player.surface.get_rect(midbottom=(int(player.x), int(player.y)))
|
||||||
|
|
||||||
|
player.rect = player.surface.get_rect(midbottom=(int(player.x), int(player.y)))
|
||||||
|
|
||||||
level = 0
|
level = 0
|
||||||
level_start_time = None
|
level_start_time = None
|
||||||
|
|
||||||
|
|
@ -294,6 +528,7 @@ while True:
|
||||||
level = target
|
level = target
|
||||||
level_start_time = pygame.time.get_ticks()
|
level_start_time = pygame.time.get_ticks()
|
||||||
current_level_bg = level_bgs[level]
|
current_level_bg = level_bgs[level]
|
||||||
|
place_door_for_level(level)
|
||||||
if BG_MUSIC:
|
if BG_MUSIC:
|
||||||
try: pygame.mixer.music.play(-1)
|
try: pygame.mixer.music.play(-1)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
@ -338,6 +573,7 @@ while True:
|
||||||
level = i
|
level = i
|
||||||
level_start_time = pygame.time.get_ticks()
|
level_start_time = pygame.time.get_ticks()
|
||||||
current_level_bg = level_bgs[level]
|
current_level_bg = level_bgs[level]
|
||||||
|
place_door_for_level(level)
|
||||||
if BG_MUSIC:
|
if BG_MUSIC:
|
||||||
try: pygame.mixer.music.play(-1)
|
try: pygame.mixer.music.play(-1)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
@ -349,6 +585,12 @@ while True:
|
||||||
else:
|
else:
|
||||||
SCREEN.blit(BACKGROUND, (0, 0))
|
SCREEN.blit(BACKGROUND, (0, 0))
|
||||||
|
|
||||||
|
for name, pos in LEVEL_BLOCKS.get(level, []):
|
||||||
|
img = PLATFORM_IMAGES.get(name)
|
||||||
|
if img:
|
||||||
|
rect = img.get_rect(midbottom=pos)
|
||||||
|
SCREEN.blit(img, rect)
|
||||||
|
|
||||||
SCREEN.blit(door_image, door_rect)
|
SCREEN.blit(door_image, door_rect)
|
||||||
|
|
||||||
if not paused:
|
if not paused:
|
||||||
|
|
@ -360,9 +602,26 @@ while True:
|
||||||
knight.apply_gravity()
|
knight.apply_gravity()
|
||||||
knight.update_animation()
|
knight.update_animation()
|
||||||
|
|
||||||
|
platform_rects = build_platform_rects(level)
|
||||||
|
resolve_platform_collision(goblin, platform_rects)
|
||||||
|
resolve_platform_collision(knight, platform_rects)
|
||||||
|
|
||||||
goblin.draw(SCREEN)
|
goblin.draw(SCREEN)
|
||||||
knight.draw(SCREEN)
|
knight.draw(SCREEN)
|
||||||
|
|
||||||
|
if not paused:
|
||||||
|
if goblin.rect.colliderect(door_rect) and knight.rect.colliderect(door_rect):
|
||||||
|
score_goblin += 1
|
||||||
|
score_knight += 1
|
||||||
|
|
||||||
|
if level == floor_score and floor_score < MAX_FLOOR_SCORE:
|
||||||
|
floor_score += 1
|
||||||
|
|
||||||
|
restart_level()
|
||||||
|
level = -1
|
||||||
|
level_start_time = None
|
||||||
|
current_level_bg = None
|
||||||
|
pygame.time.delay(150)
|
||||||
|
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
CLOCK.tick(FPS)
|
CLOCK.tick(FPS)
|
||||||