Grasping hands obstacle added.
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								sounds/grasping_hands.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/grasping_hands.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/grasping_hands_end.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/grasping_hands_end.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/grasping_hands_start.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/grasping_hands_start.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										127
									
								
								src/grasping_hands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/grasping_hands.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import pygame | ||||
| from libstormgames import * | ||||
| from src.object import Object | ||||
|  | ||||
| class GraspingHands(Object): | ||||
|     """A hazard where the ground crumbles beneath the player as undead hands reach up.""" | ||||
|      | ||||
|     def __init__(self, xRange, y, sounds, delay=1000, crumble_speed=0.065): | ||||
|         super().__init__( | ||||
|             xRange, | ||||
|             y, | ||||
|             "",  # Empty string so no regular object sound plays | ||||
|             isStatic=True, | ||||
|             isCollectible=False, | ||||
|             isHazard=True | ||||
|         ) | ||||
|         self.sounds = sounds | ||||
|         self.delay = delay  # Delay in milliseconds before ground starts crumbling | ||||
|         self.crumble_speed = crumble_speed  # How fast the crumbling catches up (tiles per frame) | ||||
|          | ||||
|         # State tracking | ||||
|         self.isTriggered = False  # Has the player entered the zone? | ||||
|         self.triggerTime = 0  # When did the player enter the zone? | ||||
|         self.crumblePosition = 0  # The position of the crumbling ground | ||||
|         self.isActive = True  # Is this hazard active? | ||||
|         self.isReset = True  # Has this hazard been reset? | ||||
|         self.crumbleChannel = None  # Channel for the looping crumble sound | ||||
|         self.entryFromRight = False  # Which side did player enter from | ||||
|         self.crumbleDirection = 1  # Direction the crumbling moves (1=right, -1=left) | ||||
|          | ||||
|     def trigger(self, currentTime, playerX): | ||||
|         """Trigger the grasping hands when player enters range""" | ||||
|         if not self.isTriggered: | ||||
|             self.isTriggered = True | ||||
|             self.triggerTime = currentTime | ||||
|              | ||||
|             # Determine which side player entered from | ||||
|             if playerX > (self.xRange[0] + self.xRange[1]) / 2: | ||||
|                 # Player entered from right side | ||||
|                 self.entryFromRight = True | ||||
|                 self.crumblePosition = self.xRange[1]  # Start crumbling from right boundary | ||||
|                 self.crumbleDirection = -1  # Crumble moves left | ||||
|             else: | ||||
|                 # Player entered from left side (or middle) | ||||
|                 self.entryFromRight = False | ||||
|                 self.crumblePosition = self.xRange[0]  # Start crumbling from left boundary | ||||
|                 self.crumbleDirection = 1  # Crumble moves right | ||||
|                  | ||||
|             self.isReset = False | ||||
|              | ||||
|             # Play initial warning sound | ||||
|             play_sound(self.sounds['grasping_hands_start']) | ||||
|             speak("The ground crumbles as the dead reach for you.") | ||||
|      | ||||
|     def reset(self): | ||||
|         """Reset the trap when player leaves the range""" | ||||
|         if not self.isReset: | ||||
|             self.isTriggered = False | ||||
|             self.crumblePosition = 0 | ||||
|             self.isReset = True | ||||
|              | ||||
|             # Stop the looping crumble sound if it's playing | ||||
|             if self.crumbleChannel: | ||||
|                 obj_stop(self.crumbleChannel) | ||||
|                 self.crumbleChannel = None | ||||
|              | ||||
|             # Play the end sound | ||||
|             play_sound(self.sounds['grasping_hands_end']) | ||||
|      | ||||
|     def update(self, currentTime, player): | ||||
|         """Update the grasping hands trap state""" | ||||
|         if not self.isActive: | ||||
|             return False | ||||
|              | ||||
|         # Check if player is in range | ||||
|         isInRange = self.xRange[0] <= player.xPos <= self.xRange[1] | ||||
|          | ||||
|         # Handle player entering/exiting range | ||||
|         if isInRange and not self.isTriggered: | ||||
|             self.trigger(currentTime, player.xPos) | ||||
|         elif not isInRange and self.isTriggered: | ||||
|             self.reset() | ||||
|             return False | ||||
|              | ||||
|         # If triggered and delay has passed, start crumbling | ||||
|         if self.isTriggered and currentTime - self.triggerTime >= self.delay: | ||||
|             # Update crumble position based on direction | ||||
|             self.crumblePosition += self.crumble_speed * self.crumbleDirection | ||||
|              | ||||
|             # Manage the looping positional audio for the crumbling ground | ||||
|             if self.crumbleChannel is None or not self.crumbleChannel.get_busy(): | ||||
|                 # Start the sound if it's not playing | ||||
|                 self.crumbleChannel = obj_play(self.sounds, 'grasping_hands', player.xPos, self.crumblePosition) | ||||
|             else: | ||||
|                 # Update the sound position | ||||
|                 self.crumbleChannel = obj_update(self.crumbleChannel, player.xPos, self.crumblePosition) | ||||
|                  | ||||
|             # Check if player is caught by crumbling | ||||
|             playerCaught = False | ||||
|             if not player.isJumping: | ||||
|                 if (self.crumbleDirection > 0 and player.xPos <= self.crumblePosition) or \ | ||||
|                    (self.crumbleDirection < 0 and player.xPos >= self.crumblePosition): | ||||
|                     playerCaught = True | ||||
|              | ||||
|             if playerCaught: | ||||
|                 if not player.isInvincible: | ||||
|                     # Player is caught - instant death | ||||
|                     # Stop the crumbling sound before death | ||||
|                     if self.crumbleChannel: | ||||
|                         obj_stop(self.crumbleChannel) | ||||
|                         self.crumbleChannel = None | ||||
|                      | ||||
|                     speak("The hands of the dead drag you down!") | ||||
|                     player.set_health(0) | ||||
|                     return True | ||||
|                 # Player is invincible - no warning needed | ||||
|              | ||||
|         return False | ||||
|          | ||||
|     def __del__(self): | ||||
|         """Cleanup when object is destroyed""" | ||||
|         # Ensure sound is stopped when object is destroyed | ||||
|         if hasattr(self, 'crumbleChannel') and self.crumbleChannel: | ||||
|             obj_stop(self.crumbleChannel) | ||||
|             self.crumbleChannel = None | ||||
							
								
								
									
										20
									
								
								src/level.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/level.py
									
									
									
									
									
								
							| @@ -6,6 +6,7 @@ from libstormgames import * | ||||
| from src.catapult import Catapult | ||||
| from src.coffin import CoffinObject | ||||
| from src.enemy import Enemy | ||||
| from src.grasping_hands import GraspingHands | ||||
| from src.grave import GraveObject | ||||
| from src.object import Object | ||||
| from src.player import Player | ||||
| @@ -87,6 +88,16 @@ class Level: | ||||
|                     firingRange=obj.get("range", 20) | ||||
|                 ) | ||||
|                 self.objects.append(catapult) | ||||
|             # Check if this is grasping hands | ||||
|             elif obj.get("type") == "grasping_hands": | ||||
|                 graspingHands = GraspingHands( | ||||
|                     xPos, | ||||
|                     obj["y"], | ||||
|                     self.sounds, | ||||
|                     delay=obj.get("delay", 1000), | ||||
|                     crumble_speed=obj.get("crumble_speed", 0.03) | ||||
|                 ) | ||||
|                 self.objects.append(graspingHands) | ||||
|             # Check if this is a grave | ||||
|             elif obj.get("type") == "grave": | ||||
|                 grave = GraveObject( | ||||
| @@ -247,6 +258,13 @@ class Level: | ||||
|             if isinstance(obj, SkullStorm): | ||||
|                 obj.update(currentTime, self.player) | ||||
|  | ||||
|         # Update grasping hands | ||||
|         for obj in self.objects: | ||||
|             if isinstance(obj, GraspingHands): | ||||
|                 caught = obj.update(currentTime, self.player) | ||||
|                 if caught: | ||||
|                     return  # Stop if player is dead | ||||
|  | ||||
|         # Update bouncing items | ||||
|         for item in self.bouncing_items[:]:  # Copy list to allow removal | ||||
|             if not item.update(currentTime, self.player.xPos): | ||||
| @@ -318,7 +336,7 @@ class Level: | ||||
|                 continue | ||||
|  | ||||
|             # Handle grave edge warnings | ||||
|             if obj.isHazard and obj.soundName != "spiderweb":  # Explicitly exclude spiderwebs | ||||
|             if obj.isHazard and obj.soundName != "spiderweb" and not isinstance(obj, GraspingHands):  # Exclude spiderwebs and grasping hands | ||||
|                 distance = abs(self.player.xPos - obj.xPos) | ||||
|                 currentTime = pygame.time.get_ticks() | ||||
|                 if (distance <= 2 and not self.player.isJumping and not self.player.isInvincible  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user