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)