refactor: improve room handling and tower expiration logic

This commit is contained in:
Niklas Haiden
2026-05-08 19:30:18 +02:00
parent e7a4115721
commit d6bdf22a10
2 changed files with 32 additions and 20 deletions
+17 -15
View File
@@ -66,7 +66,7 @@ class Game:
self.player_name: str = "" self.player_name: str = ""
self.game_start_time = 0 self.game_start_time = 0
self.endscreen: Optional[Endscreen] = None self.endscreen: Optional[Endscreen] = None
self.current_item_room_key: Optional[tuple[int, int, int, int]] = None self.current_room_key: Optional[tuple[int, int, int, int]] = None
self.map = Map() self.map = Map()
self.active_door: Optional[Door] = None self.active_door: Optional[Door] = None
@@ -151,7 +151,10 @@ class Game:
self.player.update_animation(dt) self.player.update_animation(dt)
self.ects.update(self.is_player_at_desk()) self.ects.update(self.is_player_at_desk())
self.handle_room_table_collision() self.handle_room_table_collision()
self.update_items() player_rect = self.get_actor_rect(self.player)
room_rect = self.map.get_current_room(player_rect)
self.handle_room_change(room_rect)
self.update_items(player_rect, room_rect)
self.monsters.update( self.monsters.update(
dt, dt,
self.player.position, self.player.position,
@@ -202,7 +205,7 @@ class Game:
room_rect = self.map.get_current_room(player_rect) room_rect = self.map.get_current_room(player_rect)
monster = self.monsters.monsters[0] if self.monsters.monsters else None monster = self.monsters.monsters[0] if self.monsters.monsters else None
if monster is None or not monster.is_alive: if monster is None or not monster.is_alive:
self.tower.clear() self.tower.expire_if_needed()
return return
damage = self.tower.update( damage = self.tower.update(
@@ -213,19 +216,18 @@ class Game:
) )
if monster is not None and damage > 0: if monster is not None and damage > 0:
monster.take_damage(damage) monster.take_damage(damage)
if not monster.is_alive:
self.tower.clear()
def update_items(self) -> None: def handle_room_change(self, room_rect: Optional[pygame.Rect]) -> None:
"""Spawn room items and process one player purchase request."""
player_rect = self.get_actor_rect(self.player)
room_rect = self.map.get_current_room(player_rect)
room_key = self.get_room_key(room_rect) if room_rect is not None else None room_key = self.get_room_key(room_rect) if room_rect is not None else None
if room_key == self.current_room_key:
return
if room_key != self.current_item_room_key: self.item_manager.clear()
self.item_manager.clear() self.tower.clear(reset_spawned=True)
self.current_item_room_key = room_key self.current_room_key = room_key
def update_items(self, player_rect: pygame.Rect, room_rect: Optional[pygame.Rect]) -> None:
"""Spawn room items and process one player purchase request."""
self.item_manager.update(room_rect, self.get_item_spawn_blockers()) self.item_manager.update(room_rect, self.get_item_spawn_blockers())
@@ -269,8 +271,8 @@ class Game:
self.ects = ECTS() self.ects = ECTS()
self.shop = Shop(self.ects, self.item_manager.items, self.sound_manager) self.shop = Shop(self.ects, self.item_manager.items, self.sound_manager)
self.item_manager.clear() self.item_manager.clear()
self.current_item_room_key = None self.current_room_key = None
self.tower.clear() self.tower.clear(reset_spawned=True)
self.active_door = None self.active_door = None
self.doors_by_room = {} self.doors_by_room = {}
self.player.set_position(self.find_start_position()) self.player.set_position(self.find_start_position())
+15 -5
View File
@@ -25,6 +25,7 @@ class Tower:
self.projectiles: list[dict[str, float]] = [] self.projectiles: list[dict[str, float]] = []
self.tower_start: Optional[int] = None self.tower_start: Optional[int] = None
self.last_shot: int = 0 self.last_shot: int = 0
self.has_spawned = False
try: try:
self.tower_image = pygame.image.load("assets/items/tower.png").convert_alpha() self.tower_image = pygame.image.load("assets/items/tower.png").convert_alpha()
@@ -46,7 +47,7 @@ class Tower:
def try_spawn(self, room_rect: Optional[pygame.Rect], blocked_rects: list[pygame.Rect], ects) -> bool: def try_spawn(self, room_rect: Optional[pygame.Rect], blocked_rects: list[pygame.Rect], ects) -> bool:
"""Spawn and pay for one tower when the player has enough ECTS.""" """Spawn and pay for one tower when the player has enough ECTS."""
if room_rect is None or self.tower_rect is not None: if room_rect is None or self.tower_rect is not None or self.has_spawned:
return False return False
if ects.ects_balance < TOWER_COST: if ects.ects_balance < TOWER_COST:
return False return False
@@ -59,6 +60,7 @@ class Tower:
ects.decrease_balance(TOWER_COST) ects.decrease_balance(TOWER_COST)
self.tower_rect = rect self.tower_rect = rect
self.tower_start = pygame.time.get_ticks() self.tower_start = pygame.time.get_ticks()
self.has_spawned = True
self.projectiles = [] self.projectiles = []
self._play_sfx("buy_success") self._play_sfx("buy_success")
return True return True
@@ -97,12 +99,18 @@ class Tower:
self.projectiles.remove(projectile) self.projectiles.remove(projectile)
self._play_sfx("monster_hit") self._play_sfx("monster_hit")
if self.tower_rect is not None and self.tower_start is not None: self.expire_if_needed(now)
if now - self.tower_start >= TOWER_TIMER:
self.clear()
return total_damage return total_damage
def expire_if_needed(self, now: Optional[int] = None) -> None:
if self.tower_rect is None or self.tower_start is None:
return
current_time = pygame.time.get_ticks() if now is None else now
if current_time - self.tower_start >= TOWER_TIMER:
self.clear()
def draw(self, surface: pygame.Surface, font: pygame.font.Font, cam_x: int = 0, cam_y: int = 0) -> None: def draw(self, surface: pygame.Surface, font: pygame.font.Font, cam_x: int = 0, cam_y: int = 0) -> None:
if self.tower_rect is not None and self.tower_start is not None: if self.tower_rect is not None and self.tower_start is not None:
draw_rect = pygame.Rect( draw_rect = pygame.Rect(
@@ -134,11 +142,13 @@ class Tower:
else: else:
pygame.draw.rect(surface, COLOR_PROJECTILE, projectile_rect) pygame.draw.rect(surface, COLOR_PROJECTILE, projectile_rect)
def clear(self) -> None: def clear(self, reset_spawned: bool = False) -> None:
self.tower_rect = None self.tower_rect = None
self.projectiles = [] self.projectiles = []
self.tower_start = None self.tower_start = None
self.last_shot = 0 self.last_shot = 0
if reset_spawned:
self.has_spawned = False
def _shoot_at(self, monster_rect: pygame.Rect) -> None: def _shoot_at(self, monster_rect: pygame.Rect) -> None:
if self.tower_rect is None: if self.tower_rect is None: