More content added, weapons, coin collecting, basic combat.
This commit is contained in:
109
src/level.py
109
src/level.py
@@ -1,76 +1,101 @@
|
||||
import pygame
|
||||
from libstormgames import *
|
||||
from src.player import Player
|
||||
from src.enemy import Enemy
|
||||
from src.object import Object
|
||||
from src.player import Player
|
||||
|
||||
class Level:
|
||||
def __init__(self, levelData, sounds):
|
||||
self.sounds = sounds
|
||||
self.objects = []
|
||||
self.enemies = []
|
||||
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"])
|
||||
|
||||
# Load objects from level data
|
||||
# Load objects and enemies from level data
|
||||
for obj in levelData["objects"]:
|
||||
gameObject = Object(
|
||||
obj["x"],
|
||||
obj["y"],
|
||||
obj["sound"],
|
||||
isStatic=obj.get("static", True),
|
||||
isCollectible=obj.get("collectible", False),
|
||||
isHazard=obj.get("hazard", False)
|
||||
)
|
||||
self.objects.append(gameObject)
|
||||
# Handle x position or range
|
||||
if "x_range" in obj:
|
||||
xPos = obj["x_range"]
|
||||
else:
|
||||
xPos = [obj["x"], obj["x"]] # Single position as range
|
||||
|
||||
# Check if this is an enemy
|
||||
if "enemy_type" in obj:
|
||||
enemy = Enemy(
|
||||
xPos,
|
||||
obj["y"],
|
||||
obj["enemy_type"],
|
||||
self.sounds,
|
||||
health=obj.get("health", 5),
|
||||
damage=obj.get("damage", 1),
|
||||
attack_range=obj.get("attack_range", 1),
|
||||
movement_range=obj.get("movement_range", 5)
|
||||
)
|
||||
self.enemies.append(enemy)
|
||||
else:
|
||||
gameObject = Object(
|
||||
xPos,
|
||||
obj["y"],
|
||||
obj["sound"],
|
||||
isStatic=obj.get("static", True),
|
||||
isCollectible=obj.get("collectible", False),
|
||||
isHazard=obj.get("hazard", False)
|
||||
)
|
||||
self.objects.append(gameObject)
|
||||
|
||||
def update_audio(self):
|
||||
# Update all object sounds based on player position
|
||||
currentTime = pygame.time.get_ticks()
|
||||
|
||||
# Update regular objects
|
||||
for obj in self.objects:
|
||||
if not obj.isActive:
|
||||
continue
|
||||
|
||||
# For non-static objects like goblins, ensure continuous sound
|
||||
if not obj.isStatic:
|
||||
# If channel doesn't exist or sound stopped playing, restart it
|
||||
if obj.channel is None or not obj.channel.get_busy():
|
||||
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
||||
else:
|
||||
# Original logic for static objects
|
||||
if obj.channel is None:
|
||||
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
|
||||
|
||||
# Update position-based audio for all objects
|
||||
if obj.channel is not None:
|
||||
obj.channel = obj_update(obj.channel, self.player.xPos, obj.xPos)
|
||||
|
||||
# Update enemies
|
||||
for enemy in self.enemies:
|
||||
if not enemy.isActive:
|
||||
continue
|
||||
|
||||
enemy.update(currentTime, self.player)
|
||||
|
||||
if enemy.channel is None or not enemy.channel.get_busy():
|
||||
enemy.channel = obj_play(self.sounds, enemy.enemyType, self.player.xPos, enemy.xPos)
|
||||
if enemy.channel is not None:
|
||||
enemy.channel = obj_update(enemy.channel, self.player.xPos, enemy.xPos)
|
||||
|
||||
def handle_combat(self, currentTime):
|
||||
"""Handle combat interactions between player and enemies"""
|
||||
attackRange = self.player.get_attack_range(currentTime)
|
||||
if attackRange:
|
||||
for enemy in self.enemies:
|
||||
if enemy.isActive and enemy.xPos >= attackRange[0] and enemy.xPos <= attackRange[1]:
|
||||
self.sounds[self.player.currentWeapon.hitSound].play()
|
||||
enemy.take_damage(self.player.currentWeapon.damage)
|
||||
|
||||
def handle_collisions(self):
|
||||
for obj in self.objects:
|
||||
if not obj.isActive:
|
||||
continue
|
||||
|
||||
# Single-tile collision detection (more precise)
|
||||
collision_threshold = 0.5 # Half a tile width from center
|
||||
distance = abs(self.player.xPos - obj.xPos)
|
||||
|
||||
if distance <= collision_threshold:
|
||||
if obj.isCollectible:
|
||||
# Coins must be collected while jumping
|
||||
if self.player.isJumping:
|
||||
if obj.is_in_range(self.player.xPos):
|
||||
if obj.isCollectible and self.player.isJumping:
|
||||
currentPos = round(self.player.xPos)
|
||||
if currentPos not in obj.collectedPositions:
|
||||
self.sounds[f'get_{obj.soundName}'].play()
|
||||
speak(f"Collected {obj.soundName}")
|
||||
obj.isActive = False
|
||||
obj_stop(obj.channel)
|
||||
obj.collect_at_position(currentPos)
|
||||
self.player.collectedItems.append(obj.soundName)
|
||||
elif obj.isHazard:
|
||||
# Only affect player if they're not jumping (for ground-based hazards)
|
||||
if not self.player.isJumping:
|
||||
if obj.soundName == "grave":
|
||||
self.sounds['grave'].play()
|
||||
speak("You fell into a pit!")
|
||||
elif obj.soundName == "goblin":
|
||||
self.sounds['goblin'].play()
|
||||
speak("A goblin got you!")
|
||||
else: # Other hazards
|
||||
self.sounds[obj.soundName].play()
|
||||
speak(f"A {obj.soundName} got you!")
|
||||
|
||||
# Apply knockback for any hazard hit
|
||||
knockback = 2
|
||||
self.player.xPos = self.player.xPos - knockback if self.player.facingRight else self.player.xPos + knockback
|
||||
elif obj.isHazard and not self.player.isJumping:
|
||||
self.sounds[obj.soundName].play()
|
||||
speak("You fell in an open grave!")
|
||||
self.player.set_health(0)
|
||||
|
Reference in New Issue
Block a user