ld52_olive_harvest/characters/pests/Slug.gd

166 lines
4.2 KiB
GDScript

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()