extends Area2D # #101 (#97c): the part of a structure a wave can actually hit. # # A Building is a plain Node2D, so nothing could collide with it - enemies # flew through the mothership without noticing. This gives it a body in the # same shape the rest of the game already understands: an Area2D in a group, # exactly like a Ship or an asteroid, so EnemyProjectile needed one extra # branch rather than a new concept. # # Damage is applied on a TICK rather than on area_entered. Entry fires once, # which is right for a rammer - it dies on the first strike - but would let # a sniper that drifted inside sit there scratch-free for ever. On a tick, # an enemy parked on a structure is besieging it, which is what #97 asks # for. const STRIKE_INTERVAL: float = 0.7 var _strike_timer: float = 0.0 func _ready() -> void: add_to_group("player_buildings") func building_id() -> int: var building: Node = get_parent() return 0 if building == null else int(building.building_id) # Called by EnemyProjectile, which knows nothing about buildings beyond this # name - the same call it makes on a Ship. func take_damage(amount: int) -> void: GameState.damage_building(building_id(), amount) func _physics_process(delta: float) -> void: _strike_timer -= delta if _strike_timer > 0.0: return _strike_timer = STRIKE_INTERVAL var id: int = building_id() if id == 0: return for area in get_overlapping_areas(): if not is_instance_valid(area) or not area.is_in_group("enemies"): continue var damage: int = area.contact_damage() if area.has_method("contact_damage") else 6 # The structure is told first, for the same reason Ship tells the # enemy first: resolving the enemy's own death can free it, and a # rammer must still land its hit on the way out. GameState.damage_building(id, damage) if area.has_method("collide_with_player_building"): area.collide_with_player_building()