Files
Kalulu/sources/minigames/caterpillar/caterpillar.gd
T
Adrien Ufferte db4e1da25f Caterpillar
2026-01-14 14:47:32 +01:00

163 lines
5.1 KiB
GDScript

class_name Caterpillar
extends Node2D
signal berry_eaten(berry: Berry)
const BODY_PART_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/caterpillar_body.tscn")
const BODY_SIDE_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/caterpillar_body_side.tscn")
const BODY_PART_MOVE_TIME: float = 0.25
const BODY_PART_WAIT_TIME: float = 0.02
const SIDE_WIDTH: int = 11 # Side is 11 pixels wide
const BODY_PART_POSITION_X_MARGIN: int = 20 # Equals to the width of the graphics "left" + "right" of the body part, which are 10 pixels each
var is_switching_branch: bool = false
var is_eating: bool = false
@onready var head: CaterpillarHead = $Head
@onready var body_parts: Node2D = $BodyParts
@onready var tail: Node2D = $Tail
@onready var animated_tail: AnimatedSprite2D = $Tail/AnimatedSprite2D
func idle() -> void:
for body_part: Node in body_parts.get_children():
if body_part is CaterpillarBody:
(body_part as CaterpillarBody).idle()
head.pause_animation()
animated_tail.pause()
func walk() -> void:
for body_part: Node in body_parts.get_children():
if body_part is CaterpillarBody:
(body_part as CaterpillarBody).walk()
head.resume_animation()
animated_tail.play()
func move(distance: float) -> void:
if is_switching_branch or is_eating or head.is_paused:
return
idle()
is_switching_branch = true
var coroutine: Coroutine = Coroutine.new()
# Move head
coroutine.add_future(_tween_body_part(head, distance).finished)
# Move body
for index: int in range(body_parts.get_child_count(false)):
await get_tree().create_timer(BODY_PART_WAIT_TIME).timeout
var body_part: Node = body_parts.get_child(index)
if body_part is Node2D:
coroutine.add_future(_tween_body_part(body_part as Node2D, distance).finished)
# Move tail
var scene_tree: SceneTree = get_tree()
if scene_tree != null: # Is not in editor mode
await get_tree().create_timer(BODY_PART_WAIT_TIME).timeout
coroutine.add_future(_tween_body_part(tail, distance).finished)
await coroutine.join_all()
is_switching_branch = false
walk()
func _tween_body_part(part: Node2D, y_position: float) -> Tween:
var tween: Tween = create_tween()
tween.tween_property(part, "global_position:y", y_position, BODY_PART_MOVE_TIME)
return tween
func eat_berry(berry: Berry) -> void:
is_eating = true
var body_part: CaterpillarBody
var tween: Tween = create_tween()
body_part = BODY_PART_SCENE.instantiate()
body_parts.add_child(body_part)
body_parts.move_child(body_part, 0)
body_part.gp = berry.gp
var new_body_pos: Vector2 = Vector2(head.position.x, head.position.y)
var new_body_part_size: float = body_part.get_width()
var new_head_pos: Vector2 = Vector2(head.position.x + new_body_part_size + BODY_PART_POSITION_X_MARGIN, head.position.y)
if body_parts.get_child_count() > 1:
var body_side: Node2D = BODY_SIDE_SCENE.instantiate()
body_parts.add_child(body_side)
body_parts.move_child(body_side, 0)
body_side.position = Vector2(head.position.x, head.position.y)
new_body_pos = new_body_pos + Vector2(SIDE_WIDTH, 0)
new_head_pos = new_head_pos + Vector2(SIDE_WIDTH, 0)
body_part.position = new_body_pos
tween.tween_property(head, "position", new_head_pos, .3)
tween.parallel().tween_property(berry, "scale:x", 0.1, .25)
tween.parallel().tween_property(berry, "scale:y", 0.1, .25)
tween.parallel().tween_property(berry, "position:y", -100, .25)
tween.parallel().tween_property(berry, "global_position:x", body_part.global_position.x, .6)
head.eat()
await tween.finished
body_part.right()
berry.queue_free()
is_eating = false
func spit_berry(berry: Berry) -> void:
is_eating = true
var pos_x: float = berry.global_position.x
# Eat the berry
var tween: Tween = create_tween()
tween.parallel().tween_property(berry, "scale:x", 0.1, .2)
tween.parallel().tween_property(berry, "scale:y", 0.1, .2)
tween.parallel().tween_property(berry, "position:y", -100, .25)
tween.tween_property(berry, "global_position:x",head.global_position.x, .2)
await head.eat()
# Spit the berry
head.spit()
tween = create_tween()
tween.tween_property(berry, "global_position:x", pos_x, 0.2)
tween.parallel().tween_property(berry, "scale:x", 1, .2)
tween.parallel().tween_property(berry, "scale:y", 1, .2)
tween.parallel().tween_property(berry, "position:y", 0, .25)
await tween.finished
await berry.wrong()
# Make the berry disappear
tween = create_tween()
tween.tween_property(berry, "modulate:a", 0, 1)
await tween.finished
is_eating = false
func reset() -> void:
# Move the head and the body parts back
var tween: Tween = create_tween()
tween.tween_property(head, "position:x", 165, 0.5)
for index: int in range(0, body_parts.get_child_count()):
tween.parallel().tween_property(body_parts.get_child(index), "modulate:a", 0, 0.5)
await tween.finished
# Remove the old parts
for index: int in range(0, body_parts.get_child_count()):
body_parts.get_child(index).queue_free()
func _on_eat_area_2d_area_entered(area: Area2D) -> void:
if area is Berry and !is_switching_branch:
var berry: Berry = area as Berry
berry.is_eaten = true
berry_eaten.emit(berry)