class_name GunkNode extends StaticBody3D ## A static body which can be destroyed and collected by the player. ## Emitted immediately after this node has been destroyed by the player, ## but before it's removed from the scene tree signal destroyed const JITTER_FADE_RATE := 0.8 ## Time in seconds the player must hit this node with a sustained beam before it's destroyed. @export var durability := 1.0 ## Value added to the player's grunk total on destruction. @export var value := 1000.0 ## Scale factor applied to the size and volume of the splatter effect on destruction. @export var splatter_scale := 1.0 var _sustained_damage := 0.0 var _hit_this_frame := false ## Called each frame this node takes a hit. ## ## Derived types should override `_hit()` as a lifecycle method. func hit(damage: float = 0.05) -> void: _sustained_damage += damage _hit_this_frame = true _hit() ## Return this node's current damage as a proportion of it's total durability. func pct_damage() -> float: return _sustained_damage / durability func _hit() -> void: pass # Implemented in derived type func _process(_delta: float) -> void: if not _hit_this_frame: _sustained_damage *= JITTER_FADE_RATE _hit_this_frame = false if _sustained_damage >= durability: collect() ## Destroy this node, with the player collecting the grunk value. func collect() -> void: Game.manager.collect_grunk(value) destroy() ## Destroy this node. Called automatically when this node sustains damage beyond its durability. ## ## Derived types should override `_destroy` as a lifecycle method. func destroy() -> void: Game.manager.collect_grunk(value) var splatter := GrunkSplatter.build(splatter_scale * scale.x) add_sibling(splatter) splatter.global_position = global_position _destroy() destroyed.emit() queue_free() func _destroy() -> void: pass # Implemented in derived type