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