feat: add timer-based tower spawning mechanic triggered by player desk interaction
This commit is contained in:
+36
-8
@@ -28,6 +28,7 @@ from src.settings import (
|
||||
DOOR_HP,
|
||||
FPS,
|
||||
PLAYER_SPEED,
|
||||
TOWER_TABLE_ACTIVATION_TIME,
|
||||
)
|
||||
from src.shop import Shop
|
||||
from src.startscreen import Startscreen
|
||||
@@ -65,6 +66,7 @@ class Game:
|
||||
self.game_start_time = 0
|
||||
self.endscreen: Optional[Endscreen] = None
|
||||
self.current_room_key: Optional[tuple[int, int, int, int]] = None
|
||||
self.table_touch_start_time: Optional[int] = None
|
||||
|
||||
self.map = Map()
|
||||
self.active_door: Optional[Door] = None
|
||||
@@ -147,10 +149,11 @@ class Game:
|
||||
self.player.hit_wall()
|
||||
|
||||
self.player.update_animation(dt)
|
||||
self.ects.update(self.is_player_at_desk())
|
||||
self.handle_room_table_collision()
|
||||
player_rect = self.get_actor_rect(self.player)
|
||||
room_rect = self.map.get_current_room(player_rect)
|
||||
is_at_desk = self.is_player_at_desk(player_rect, room_rect)
|
||||
self.ects.update(is_at_desk)
|
||||
self.handle_room_table_collision()
|
||||
self.handle_room_change(room_rect)
|
||||
self.update_items(player_rect, room_rect)
|
||||
self.monsters.update(
|
||||
@@ -159,7 +162,7 @@ class Game:
|
||||
self.is_position_walkable,
|
||||
self.get_monster_spawn_blockers(),
|
||||
)
|
||||
self.update_tower()
|
||||
self.update_tower(room_rect, is_at_desk)
|
||||
self.check_end_conditions()
|
||||
|
||||
def get_player_movement(self, dt: float) -> pygame.Vector2:
|
||||
@@ -186,35 +189,58 @@ class Game:
|
||||
row = int(position.y // tile_size)
|
||||
return self.map.is_accessible(column, row)
|
||||
|
||||
def is_player_at_desk(self) -> bool:
|
||||
def is_player_at_desk(
|
||||
self,
|
||||
player_rect: Optional[pygame.Rect] = None,
|
||||
room_rect: Optional[pygame.Rect] = None,
|
||||
) -> bool:
|
||||
"""Return True while the player's hitbox touches a desk in the current room."""
|
||||
|
||||
if player_rect is None:
|
||||
player_rect = self.get_actor_rect(self.player)
|
||||
if room_rect is None:
|
||||
room_rect = self.map.get_current_room(player_rect)
|
||||
if room_rect is None:
|
||||
return False
|
||||
|
||||
return any(desk.check_collision(player_rect) for desk in self.map.get_desks_for_room(room_rect))
|
||||
|
||||
def update_tower(self) -> None:
|
||||
"""Spawn a tower when enough ECTS are available and let it attack the zombie."""
|
||||
def update_tower(
|
||||
self,
|
||||
room_rect: Optional[pygame.Rect],
|
||||
is_at_desk: bool,
|
||||
) -> None:
|
||||
"""Spawn a tower after the player studies at a table, then let it attack."""
|
||||
|
||||
player_rect = self.get_actor_rect(self.player)
|
||||
room_rect = self.map.get_current_room(player_rect)
|
||||
monster = self.monsters.monsters[0] if self.monsters.monsters else None
|
||||
if monster is None or not monster.is_alive:
|
||||
self.tower.expire_if_needed()
|
||||
self.update_table_touch_timer(is_at_desk)
|
||||
return
|
||||
|
||||
can_spawn_tower = self.update_table_touch_timer(is_at_desk)
|
||||
damage = self.tower.update(
|
||||
room_rect,
|
||||
self.get_tower_spawn_blockers(),
|
||||
self.ects,
|
||||
monster.rect,
|
||||
can_spawn=can_spawn_tower,
|
||||
)
|
||||
if monster is not None and damage > 0:
|
||||
monster.take_damage(damage)
|
||||
|
||||
def update_table_touch_timer(self, is_at_desk: bool) -> bool:
|
||||
now = pygame.time.get_ticks()
|
||||
if not is_at_desk:
|
||||
self.table_touch_start_time = None
|
||||
return False
|
||||
|
||||
if self.table_touch_start_time is None:
|
||||
self.table_touch_start_time = now
|
||||
return False
|
||||
|
||||
return now - self.table_touch_start_time >= TOWER_TABLE_ACTIVATION_TIME
|
||||
|
||||
def handle_room_change(self, room_rect: Optional[pygame.Rect]) -> None:
|
||||
room_key = self.get_room_key(room_rect) if room_rect is not None else None
|
||||
if room_key == self.current_room_key:
|
||||
@@ -225,6 +251,7 @@ class Game:
|
||||
|
||||
self.item_manager.clear()
|
||||
self.tower.clear(reset_spawned=True)
|
||||
self.table_touch_start_time = None
|
||||
self.current_room_key = room_key
|
||||
|
||||
def reset_active_encounter(self) -> None:
|
||||
@@ -281,6 +308,7 @@ class Game:
|
||||
self.shop = Shop(self.ects, self.item_manager.items, self.sound_manager)
|
||||
self.item_manager.clear()
|
||||
self.current_room_key = None
|
||||
self.table_touch_start_time = None
|
||||
self.tower.clear(reset_spawned=True)
|
||||
self.active_door = None
|
||||
self.doors_by_room = {}
|
||||
|
||||
+2
-1
@@ -67,6 +67,7 @@ TOWER_COST = 10
|
||||
PROJECTILE_DMG = 2
|
||||
PROJECTILE_SPEED = 7
|
||||
COLOR_PROJECTILE = (200, 200, 0)
|
||||
TOWER_TABLE_ACTIVATION_TIME = 5000 # ms the player must stay at a table before tower spawn
|
||||
TOWER_TIMER = 30000 # how long the tower stays and attack before it disappears
|
||||
|
||||
# --- ITEM SPAWN TIMER ---
|
||||
@@ -149,7 +150,7 @@ SFX_BUY_FAIL = f"{SOUND_DIR}/buy_fail.wav"
|
||||
SFX_MONSTER_HEALED = f"{SOUND_DIR}/monster_healed.wav"
|
||||
SFX_MONSTER_TRANSFORM = f"{SOUND_DIR}/monster_transform.wav"
|
||||
|
||||
BGM_NORMAL = f"{SOUND_DIR}/bgm_normal.wav"
|
||||
BGM_NORMAL = f"{SOUND_DIR}/bgm_creepy.wav"
|
||||
BGM_CREEPY = f"{SOUND_DIR}/bgm_creepy.wav"
|
||||
|
||||
VOLUME_SFX = 0.6
|
||||
|
||||
@@ -71,12 +71,14 @@ class Tower:
|
||||
blocked_rects: list[pygame.Rect],
|
||||
ects,
|
||||
monster_rect: Optional[pygame.Rect],
|
||||
can_spawn: bool = True,
|
||||
) -> int:
|
||||
"""Update tower spawning/shooting and return damage dealt to the monster."""
|
||||
|
||||
now = pygame.time.get_ticks()
|
||||
total_damage = 0
|
||||
|
||||
if can_spawn:
|
||||
self.try_spawn(room_rect, blocked_rects, ects)
|
||||
|
||||
if self.tower_rect is not None and monster_rect is not None:
|
||||
|
||||
Reference in New Issue
Block a user