extends Node2D @export var speed = 100 # How fast the virus will move (pixels/sec). @export var attack_range = 1000 # virus vision radius (pixels) @export var max_health = 10 var health = max_health # a virus is instantiated as Spawning and transitions (matures) into Spawned # after a timer timeout, after which it is activated and ready to do its thing. enum SpawningState {Spawning, Spawned} # when idle, a virus Waits. if it has already performed some action, it may # become Blocked for a while. otherwise it might be Running. like a process. enum ActionState {Blocked, Waiting, Running} var spawning_state var action_state var knockback_timer: Timer = Timer.new() var knockback = Vector2.ZERO # temp 0 because of if len == 0 in process var targets = [0] # who the virus will attack func _ready(): self.spawning_state = SpawningState.Spawning self.action_state = ActionState.Waiting self.add_to_group("Virus") $AnimationTree.set("parameters/transition/transition_request", "processing") knockback_timer.one_shot = true add_child(knockback_timer); func _process(delta): if self.spawning_state != SpawningState.Spawned: return # do nothing if not yet spawned if self.targets.size() == 0: return # do nothing if no set targets # --- determine nearest target var nearest_target = get_node("../../Player").position var shortest_distance = nearest_target.distance_to(self.position) # --- attack the nearest target, if within range if self.action_state != ActionState.Blocked: if shortest_distance < self.attack_range: self.attack(nearest_target) if knockback_timer.time_left > 0: print_debug("knockback timer left: %f %s" % [knockback_timer.time_left, knockback]) self.position += knockback * delta else: # --- move towards nearest target self.position += \ self.position.direction_to(nearest_target) * self.speed * delta func attack(target): # do attack, block until timer self.action_state = ActionState.Blocked func set_spawning(): self.spawning_state = SpawningState.Spawning func set_spawned(): self.spawning_state = SpawningState.Spawned func take_hit(damage, knockback_vector, knockback_strength = 1): $HitSFX.play(); if self.spawning_state == SpawningState.Spawning: health -= damage * 2 else: health -= damage if health <= 0: get_node("../../Player").add_to_score(1); queue_free() elif knockback_strength > 0: knockback = -knockback_vector; knockback_timer.start(0.2 * knockback_strength); # Flash white? func _on_body_entered(body: Node2D) -> void: if self.spawning_state == SpawningState.Spawning: return body.take_hit(1, self.position.direction_to(body.position) * 500, 2)