Got end of level working. Added floating coffins, shatter them and collect what comes out.
This commit is contained in:
@@ -20,7 +20,15 @@ class CoffinObject(Object):
|
||||
if not self.is_broken:
|
||||
self.is_broken = True
|
||||
self.sounds['coffin_shatter'].play()
|
||||
|
||||
|
||||
# Stop the ongoing coffin sound
|
||||
if self.channel:
|
||||
obj_stop(self.channel)
|
||||
self.channel = None
|
||||
|
||||
# Mark coffin as inactive since it's broken
|
||||
self.isActive = False
|
||||
|
||||
# Randomly choose item type
|
||||
item_type = random.choice(['hand_of_glory', 'jack_o_lantern'])
|
||||
|
||||
@@ -28,7 +36,7 @@ class CoffinObject(Object):
|
||||
direction = random.choice([-1, 1])
|
||||
drop_distance = random.randint(1, 2)
|
||||
drop_x = self.xPos + (direction * drop_distance)
|
||||
|
||||
|
||||
self.dropped_item = PowerUp(
|
||||
drop_x,
|
||||
self.yPos,
|
||||
|
71
src/level.py
71
src/level.py
@@ -7,7 +7,6 @@ from src.enemy import Enemy
|
||||
from src.object import Object
|
||||
from src.player import Player
|
||||
from src.projectile import Projectile
|
||||
from src.coffin import CoffinObject
|
||||
from src.powerup import PowerUp
|
||||
|
||||
class Level:
|
||||
@@ -17,10 +16,24 @@ class Level:
|
||||
self.enemies = []
|
||||
self.bouncing_items = []
|
||||
self.projectiles = [] # Track active projectiles
|
||||
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"])
|
||||
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"], sounds)
|
||||
self.edge_warning_channel = None
|
||||
self.weapon_hit_channel = None
|
||||
|
||||
self.leftBoundary = levelData["boundaries"]["left"]
|
||||
self.rightBoundary = levelData["boundaries"]["right"]
|
||||
self.levelId = levelData["level_id"]
|
||||
|
||||
# Create end of level object at right boundary
|
||||
endLevel = Object(
|
||||
self.rightBoundary,
|
||||
0, # Same y-level as player start
|
||||
"end_of_level",
|
||||
isStatic=True,
|
||||
isCollectible=False,
|
||||
isHazard=False
|
||||
)
|
||||
self.objects.append(endLevel)
|
||||
|
||||
# Load objects and enemies from level data
|
||||
for obj in levelData["objects"]:
|
||||
# Handle x position or range
|
||||
@@ -28,7 +41,7 @@ class Level:
|
||||
xPos = obj["x_range"]
|
||||
else:
|
||||
xPos = [obj["x"], obj["x"]] # Single position as range
|
||||
|
||||
|
||||
# Check if this is a catapult
|
||||
if obj.get("type") == "catapult":
|
||||
catapult = Catapult(
|
||||
@@ -40,6 +53,14 @@ class Level:
|
||||
firingRange=obj.get("range", 20)
|
||||
)
|
||||
self.objects.append(catapult)
|
||||
# Check if this is a coffin
|
||||
elif obj.get("type") == "coffin":
|
||||
coffin = CoffinObject(
|
||||
xPos[0],
|
||||
obj["y"],
|
||||
self.sounds
|
||||
)
|
||||
self.objects.append(coffin)
|
||||
# Check if this is an enemy
|
||||
elif "enemy_type" in obj:
|
||||
enemy = Enemy(
|
||||
@@ -66,6 +87,7 @@ class Level:
|
||||
self.objects.append(gameObject)
|
||||
|
||||
def update_audio(self):
|
||||
"""Update all audio and entity state."""
|
||||
currentTime = pygame.time.get_ticks()
|
||||
|
||||
# Update regular objects and check for zombie spawning
|
||||
@@ -156,7 +178,7 @@ class Level:
|
||||
if self.weapon_hit_channel is not None and not self.weapon_hit_channel.get_busy():
|
||||
self.weapon_hit_channel = None
|
||||
|
||||
# Check for coffin hits - only if we have any coffins
|
||||
# Check for coffin hits
|
||||
for obj in self.objects:
|
||||
if hasattr(obj, 'is_broken'): # Check if it's a coffin without using isinstance
|
||||
if (not obj.is_broken and
|
||||
@@ -164,25 +186,27 @@ class Level:
|
||||
obj.xPos <= attackRange[1] and
|
||||
self.player.isJumping): # Must be jumping to hit floating coffins
|
||||
|
||||
if obj.hit(self.player.xPos):
|
||||
self.bouncing_items.append(obj.dropped_item)
|
||||
speak(f"{obj.dropped_item.item_type} falls out!")
|
||||
if obj.hit(self.player.xPos):
|
||||
self.bouncing_items.append(obj.dropped_item)
|
||||
speak(f"{obj.dropped_item.item_type} falls out!")
|
||||
|
||||
def handle_collisions(self):
|
||||
"""Handle all collision checks and return True if level is complete."""
|
||||
# First check if player is dead
|
||||
if self.player.get_health() <= 0:
|
||||
return False
|
||||
|
||||
# Process object collisions for hazards and collectibles
|
||||
for obj in self.objects:
|
||||
if not obj.isActive:
|
||||
continue
|
||||
|
||||
|
||||
# Handle grave edge warnings
|
||||
if obj.isHazard:
|
||||
distance = abs(self.player.xPos - obj.xPos)
|
||||
# Check if within 1 tile and moving
|
||||
|
||||
if distance <= 2 and not self.player.isJumping:
|
||||
# Only play edge warning if not already playing
|
||||
if self.edge_warning_channel is None or not self.edge_warning_channel.get_busy():
|
||||
self.edge_warning_channel = self.sounds['edge'].play()
|
||||
|
||||
else:
|
||||
if self.edge_warning_channel is not None and not self.edge_warning_channel.get_busy():
|
||||
self.edge_warning_channel = None
|
||||
@@ -200,7 +224,26 @@ class Level:
|
||||
self.sounds[obj.soundName].play()
|
||||
speak("You fell in an open grave!")
|
||||
self.player.set_health(0)
|
||||
|
||||
return False
|
||||
|
||||
# Handle boundaries
|
||||
if self.player.xPos < self.leftBoundary:
|
||||
self.player.xPos = self.leftBoundary
|
||||
speak("Start of level!")
|
||||
|
||||
# Check for level completion - takes precedence over everything except death
|
||||
if self.player.get_health() > 0:
|
||||
for obj in self.objects:
|
||||
if obj.soundName == "end_of_level":
|
||||
# Check if player has reached or passed the end marker
|
||||
if self.player.xPos >= obj.xPos:
|
||||
# Stop all current sounds and play end level sound
|
||||
pygame.mixer.stop()
|
||||
self.sounds["end_of_level"].play()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def handle_projectiles(self, currentTime):
|
||||
"""Update projectiles and check for collisions"""
|
||||
for proj in self.projectiles[:]: # Copy list to allow removal
|
||||
|
@@ -1,6 +1,11 @@
|
||||
import pygame
|
||||
from libstormgames import *
|
||||
from src.weapon import Weapon
|
||||
|
||||
|
||||
class Player:
|
||||
def __init__(self, xPos, yPos):
|
||||
def __init__(self, xPos, yPos, sounds):
|
||||
self.sounds = sounds
|
||||
# Movement attributes
|
||||
self.xPos = xPos
|
||||
self.yPos = yPos
|
||||
@@ -98,15 +103,21 @@ class Player:
|
||||
return self._maxHealth
|
||||
|
||||
def set_health(self, value):
|
||||
"""Set health and handle death if needed"""
|
||||
"""Set health and handle death if needed."""
|
||||
if self.isInvincible:
|
||||
return # No damage while invincible
|
||||
|
||||
|
||||
old_health = self._health
|
||||
self._health = max(0, value) # Health can't go below 0
|
||||
if self._health == 0:
|
||||
|
||||
if self._health == 0 and old_health > 0:
|
||||
self._lives -= 1
|
||||
# Stop all current sounds before playing death sound
|
||||
pygame.mixer.stop()
|
||||
cut_scene(self.sounds, 'lose_a_life')
|
||||
if self._lives > 0:
|
||||
self._health = 10 # Reset health if we still have lives
|
||||
self._health = self._maxHealth # Reset health if we still have lives
|
||||
speak(f"{self._lives} lives remaining")
|
||||
|
||||
def set_max_health(self, value):
|
||||
"""Set max health"""
|
||||
|
@@ -14,19 +14,22 @@ class PowerUp(Object):
|
||||
self.speed = 0.05 # Base movement speed
|
||||
self.item_type = item_type
|
||||
self.channel = None
|
||||
self._currentX = x # Initialize the current x position
|
||||
|
||||
def update(self, current_time):
|
||||
"""Update item position"""
|
||||
if not self.isActive:
|
||||
return False
|
||||
|
||||
|
||||
# Update position
|
||||
self._currentX += self.direction * self.speed
|
||||
|
||||
# Keep bounce sound playing while moving
|
||||
|
||||
# Update positional audio
|
||||
if self.channel is None or not self.channel.get_busy():
|
||||
self.channel = self.sounds['item_bounce'].play(-1)
|
||||
|
||||
self.channel = obj_play(self.sounds, "item_bounce", self.xPos, self._currentX)
|
||||
else:
|
||||
self.channel = obj_update(self.channel, self.xPos, self._currentX)
|
||||
|
||||
# Check if item has gone too far (20 tiles)
|
||||
if abs(self._currentX - self.xRange[0]) > 20:
|
||||
self.isActive = False
|
||||
@@ -34,7 +37,7 @@ class PowerUp(Object):
|
||||
self.channel.stop()
|
||||
self.channel = None
|
||||
return False
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def apply_effect(self, player):
|
||||
|
Reference in New Issue
Block a user