Fix bomb explosions not killing rats and remove tracked pycache
- Move Timer explosion from move() to collisions() so all units are registered in the collision system before the kill query runs. - Explosion units now set a bbox and kill rats that touch them. - Guard Rat.draw() so dead rats are not drawn. - Remove units/__pycache__ files from tracking.
This commit is contained in:
Binary file not shown.
Binary file not shown.
+39
-24
@@ -55,32 +55,31 @@ class Timer(Bomb):
|
|||||||
|
|
||||||
def move(self):
|
def move(self):
|
||||||
self.age += self.speed
|
self.age += self.speed
|
||||||
if self.age == AGE_THRESHOLD:
|
if self.age >= AGE_THRESHOLD and not getattr(self, "exploded", False):
|
||||||
self.die()
|
self.exploding = True
|
||||||
|
|
||||||
def die(self, unit=None, score=None):
|
def collisions(self):
|
||||||
"""Handle bomb explosion and chain reactions using vectorized collision system."""
|
"""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
|
score = 10
|
||||||
print("BOOM")
|
print("BOOM")
|
||||||
target_unit = unit if unit else self
|
|
||||||
self.game.render_engine.play_sound("BOMB.WAV")
|
self.game.render_engine.play_sound("BOMB.WAV")
|
||||||
|
self.exploded = True
|
||||||
|
|
||||||
# Use base class cleanup with error handling
|
# Remove bomb
|
||||||
try:
|
if self.id in self.game.units:
|
||||||
if target_unit.id in self.game.units:
|
self.game.units.pop(self.id)
|
||||||
self.game.units.pop(target_unit.id)
|
|
||||||
except:
|
|
||||||
print(f"Unit {target_unit.id} already dead")
|
|
||||||
|
|
||||||
# Bomb-specific behavior: create explosion
|
# Collect all explosion positions
|
||||||
self.game.unit_manager.spawn_unit(Explosion, target_unit.position)
|
|
||||||
|
|
||||||
# Collect all explosion positions using vectorized approach
|
|
||||||
explosion_positions = []
|
explosion_positions = []
|
||||||
|
|
||||||
# Check for chain reactions in all four directions
|
# Check for chain reactions in all four directions
|
||||||
for direction in ["N", "S", "E", "W"]:
|
for direction in ["N", "S", "E", "W"]:
|
||||||
x, y = target_unit.position
|
x, y = self.position
|
||||||
while True:
|
while True:
|
||||||
if not self.game.map.is_wall(x, y):
|
if not self.game.map.is_wall(x, y):
|
||||||
explosion_positions.append((x, y))
|
explosion_positions.append((x, y))
|
||||||
@@ -95,28 +94,30 @@ class Timer(Bomb):
|
|||||||
elif direction == "W":
|
elif direction == "W":
|
||||||
x -= 1
|
x -= 1
|
||||||
|
|
||||||
# Create all explosions at once
|
# Create visual explosions
|
||||||
for pos in explosion_positions:
|
for pos in explosion_positions:
|
||||||
self.game.unit_manager.spawn_unit(Explosion, pos)
|
self.game.unit_manager.spawn_unit(Explosion, pos)
|
||||||
|
|
||||||
# Use optimized collision system to get all rats in explosion area
|
# Kill all rats in explosion area (Pass 2: all units registered)
|
||||||
# This replaces the nested loop with a single vectorized operation
|
|
||||||
victim_ids = self.game.collision_system.get_units_in_area(
|
victim_ids = self.game.collision_system.get_units_in_area(
|
||||||
explosion_positions,
|
explosion_positions,
|
||||||
layer_filter=CollisionLayer.RAT
|
layer_filter=CollisionLayer.RAT
|
||||||
)
|
)
|
||||||
|
|
||||||
# Kill all victims with score multiplier
|
|
||||||
for victim_id in victim_ids:
|
for victim_id in victim_ids:
|
||||||
victim = self.game.unit_manager.get_unit_by_id(victim_id)
|
victim = self.game.unit_manager.get_unit_by_id(victim_id)
|
||||||
if victim and victim.id in self.game.units:
|
if victim and victim.id in self.game.units:
|
||||||
# Determine position based on partial_move
|
if victim.position in explosion_positions or victim.position_before in explosion_positions:
|
||||||
victim_pos = victim.position if victim.partial_move >= 0.5 else victim.position_before
|
|
||||||
if victim_pos in explosion_positions:
|
|
||||||
victim.die(score=score)
|
victim.die(score=score)
|
||||||
if score < 160:
|
if score < 160:
|
||||||
score *= 2
|
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):
|
class Explosion(Bomb):
|
||||||
def __init__(self, game, position=(0,0), id=None):
|
def __init__(self, game, position=(0,0), id=None):
|
||||||
@@ -129,6 +130,20 @@ class Explosion(Bomb):
|
|||||||
self.age += self.speed
|
self.age += self.speed
|
||||||
if self.age >= AGE_THRESHOLD:
|
if self.age >= AGE_THRESHOLD:
|
||||||
self.die()
|
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):
|
def draw(self):
|
||||||
image = self.game.graphics.assets["BMP_EXPLOSION"]
|
image = self.game.graphics.assets["BMP_EXPLOSION"]
|
||||||
|
|||||||
@@ -171,6 +171,8 @@ class Rat(Unit):
|
|||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
"""Optimized draw using pre-calculated positions from move()"""
|
"""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"
|
sex = self.sex if self.age > AGE_THRESHOLD else "BABY"
|
||||||
image = self.game.graphics.rat_assets_textures[sex][self.direction]
|
image = self.game.graphics.rat_assets_textures[sex][self.direction]
|
||||||
image_size = self.game.graphics.rat_image_sizes[sex][self.direction]
|
image_size = self.game.graphics.rat_image_sizes[sex][self.direction]
|
||||||
|
|||||||
Reference in New Issue
Block a user