extends KinematicBody2D const SPEED := 50 const HEAL_RATE_PER_OLIVE := 1.0 var _velocity := Vector2.ZERO onready var _agent: NavigationAgent2D = $NavigationAgent2D var target: Node2D = null var eaten_olives: float = 0 var hp: float = 0 # Called when the node enters the scene tree for the first time. func _ready(): call_deferred("_find_target") func _find_target() -> void: if eaten_olives >= 5: # go in for the kill target = find_parent("YSort").get_node("Player") else: var trees := get_tree().get_nodes_in_group("olive_trees") var best_tree = null var best_tree_juiciness = -1 for tree in trees: var tree_distsq := self.global_position.distance_squared_to(tree.global_position) var tree_dist := sqrt(tree_distsq) var tree_food = tree.calculate_food(tree_dist / SPEED) #print("est food ", tree_food) if tree_food < 0.1: continue var tree_juiciness = tree_food / tree_dist if tree_juiciness > best_tree_juiciness: best_tree = tree best_tree_juiciness = tree_juiciness target = best_tree if target != null: _agent.set_target_location(target.global_position) func _at_target() -> void: if target.is_in_group("olive_trees"): _eating() if target.name == "Player": _explode() var busy_eating = false func _eating() -> void: if busy_eating: return busy_eating = true var tree = target while true: var just_eaten = tree.eat_food() #print("ate ", just_eaten) eaten_olives += just_eaten hp += just_eaten _on_eaten_olives_updated() # TODO sfx # TODO vfx $EatingTimer.start(2.0); yield($EatingTimer, "timeout") if just_eaten <= 0.1: _find_target() busy_eating = false return busy_eating = false func _explode() -> void: var tree = get_tree() target = null $RenavigateTimer.stop() var tween = tree.create_tween() $ExplodeSfx.pitch_scale = rand_range(0.7, 1.2) $ExplodeSfx.play() tween.tween_property($AnimatedSprite, "scale", Vector2(2.5, 2.5), 0.5).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK) tween.tween_property(self, "modulate:a", 0.5, 0.5).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BOUNCE) tween.tween_callback(self, "queue_free") var hud = find_parent("Level*").get_node("Hud") # TODO sfx tween.tween_callback(hud, "remove_hp") func _physics_process(delta: float) -> void: if target == null: if $AnimatedSprite.animation != "still": $AnimatedSprite.play("still") return var target_velocity = Vector2.ZERO if not _agent.is_navigation_finished(): var direction_towards_travel := global_position.direction_to(_agent.get_next_location()) target_velocity = direction_towards_travel * SPEED _velocity += (target_velocity - _velocity) * delta * 2.0 if _velocity.length_squared() > 16: if $AnimatedSprite.animation != "crawl": $AnimatedSprite.play("crawl") if not $SlimyWalkSfx.playing: $SlimyWalkSfx.play() $AnimatedSprite.flip_h = _velocity.x < 0 else: if $AnimatedSprite.animation != "still": $AnimatedSprite.play("still") $SlimyWalkSfx.playing = false #print(_velocity) var _vel := move_and_slide(_velocity) func _process(delta: float) -> void: hp = min(eaten_olives, hp + eaten_olives * HEAL_RATE_PER_OLIVE * delta) _on_hp_updated() if target != null and target.name == "Player": if target.global_position.distance_squared_to(self.global_position) < 1024: self._explode() func _on_hp_updated() -> void: if hp == eaten_olives: self.modulate.a = 1.0 else: self.modulate.a = clamp(sqrt(hp / max(eaten_olives, 0.1)), 0.0, 1.0) func _on_eaten_olives_updated() -> void: self.scale = Vector2(1, 1) * (1.0 + eaten_olives * 0.1) var non_red := 1.0 - (0.1 * eaten_olives) self.modulate.g = non_red self.modulate.b = non_red func interact(_player: Node2D) -> bool: self.hp -= 1.0 if self.hp < 0: # the slug is dead! $SlimyWalkSfx.stop() target = null # TODO sfx $RenavigateTimer.stop() self.queue_free() else: self._on_hp_updated() return true func _on_NavigationAgent2D_target_reached() -> void: var dsq := self.global_position.distance_squared_to(target.global_position) print("reached distsq = ", dsq) if dsq < 256: self._at_target() func _on_RenavigateTimer_timeout() -> void: if target != null: _agent.set_target_location(target.global_position) else: _find_target()