diff --git a/units/__pycache__/rat.cpython-313.pyc b/units/__pycache__/rat.cpython-313.pyc deleted file mode 100644 index 94bcdea..0000000 Binary files a/units/__pycache__/rat.cpython-313.pyc and /dev/null differ diff --git a/units/__pycache__/unit.cpython-313.pyc b/units/__pycache__/unit.cpython-313.pyc deleted file mode 100644 index 684bce6..0000000 Binary files a/units/__pycache__/unit.cpython-313.pyc and /dev/null differ diff --git a/units/bomb.py b/units/bomb.py index 66f8e15..3fae2d4 100644 --- a/units/bomb.py +++ b/units/bomb.py @@ -55,32 +55,31 @@ class Timer(Bomb): def move(self): self.age += self.speed - if self.age == AGE_THRESHOLD: - self.die() + if self.age >= AGE_THRESHOLD and not getattr(self, "exploded", False): + self.exploding = True - def die(self, unit=None, score=None): - """Handle bomb explosion and chain reactions using vectorized collision system.""" + def collisions(self): + """Explode in Pass 2 when every unit is registered in the collision system.""" + if getattr(self, "exploding", False) and not getattr(self, "exploded", False): + self.explode() + + def explode(self): + """Handle bomb explosion and chain reactions.""" score = 10 print("BOOM") - target_unit = unit if unit else self self.game.render_engine.play_sound("BOMB.WAV") + self.exploded = True - # Use base class cleanup with error handling - try: - if target_unit.id in self.game.units: - self.game.units.pop(target_unit.id) - except: - print(f"Unit {target_unit.id} already dead") + # Remove bomb + if self.id in self.game.units: + self.game.units.pop(self.id) - # Bomb-specific behavior: create explosion - self.game.unit_manager.spawn_unit(Explosion, target_unit.position) - - # Collect all explosion positions using vectorized approach + # Collect all explosion positions explosion_positions = [] # Check for chain reactions in all four directions for direction in ["N", "S", "E", "W"]: - x, y = target_unit.position + x, y = self.position while True: if not self.game.map.is_wall(x, y): explosion_positions.append((x, y)) @@ -95,28 +94,30 @@ class Timer(Bomb): elif direction == "W": x -= 1 - # Create all explosions at once + # Create visual explosions for pos in explosion_positions: self.game.unit_manager.spawn_unit(Explosion, pos) - # Use optimized collision system to get all rats in explosion area - # This replaces the nested loop with a single vectorized operation + # Kill all rats in explosion area (Pass 2: all units registered) victim_ids = self.game.collision_system.get_units_in_area( - explosion_positions, + explosion_positions, layer_filter=CollisionLayer.RAT ) - # Kill all victims with score multiplier for victim_id in victim_ids: victim = self.game.unit_manager.get_unit_by_id(victim_id) if victim and victim.id in self.game.units: - # Determine position based on partial_move - victim_pos = victim.position if victim.partial_move >= 0.5 else victim.position_before - if victim_pos in explosion_positions: + if victim.position in explosion_positions or victim.position_before in explosion_positions: victim.die(score=score) if score < 160: score *= 2 + def draw(self): + """Don't draw a bomb that has already exploded.""" + if getattr(self, "exploded", False): + return + super().draw() + class Explosion(Bomb): def __init__(self, game, position=(0,0), id=None): @@ -129,6 +130,20 @@ class Explosion(Bomb): self.age += self.speed if self.age >= AGE_THRESHOLD: self.die() + # Set bbox so lingering explosions can kill rats via collision system + x = self.position[0] * self.game.cell_size + y = self.position[1] * self.game.cell_size + self.bbox = (float(x), float(y), float(x + self.game.cell_size), float(y + self.game.cell_size)) + + def collisions(self): + """Lingering explosion kills any rat that touches it.""" + victim_ids = self.game.collision_system.get_collisions_for_unit( + self.id, CollisionLayer.EXPLOSION, tolerance=0 + ) + for _, victim_id in victim_ids: + victim = self.game.unit_manager.get_unit_by_id(victim_id) + if victim and victim.type in [UnitType.RAT_MALE, UnitType.RAT_FEMALE] and victim.id in self.game.units: + victim.die(score=10) def draw(self): image = self.game.graphics.assets["BMP_EXPLOSION"] diff --git a/units/rat.py b/units/rat.py index b47578b..1b7d947 100644 --- a/units/rat.py +++ b/units/rat.py @@ -171,6 +171,8 @@ class Rat(Unit): def draw(self): """Optimized draw using pre-calculated positions from move()""" + if self.id not in self.game.units: + return sex = self.sex if self.age > AGE_THRESHOLD else "BABY" image = self.game.graphics.rat_assets_textures[sex][self.direction] image_size = self.game.graphics.rat_image_sizes[sex][self.direction]