polished
This commit is contained in:
@@ -4,6 +4,7 @@ var player_free: bool = true
|
||||
var player: Player
|
||||
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
@onready var explosion: Control = $Explosion
|
||||
|
||||
enum Events { NONE, PUMPKIN_CARVE, OUTSIDE_NORMAL }
|
||||
var current_event: Events = Events.NONE
|
||||
@@ -23,10 +24,13 @@ func run_event(event: Events, player_postion: Vector2 = Vector2.ZERO):
|
||||
player_free = false
|
||||
transition_scene_file("uid://ccfdsdgaon63m") # scenes/levels/home.tscn
|
||||
await get_tree().scene_changed
|
||||
explosion.explode()
|
||||
await get_tree().create_timer(2).timeout
|
||||
var pumpkin_carve: Control = preload("res://scenes/menus/pumpkin_carve.tscn").instantiate()
|
||||
add_child(pumpkin_carve)
|
||||
|
||||
Events.NONE:
|
||||
player_free = true
|
||||
|
||||
func transition_scene_file(scene: String) -> void:
|
||||
if !animation_player.is_playing():
|
||||
transition_start()
|
||||
|
||||
@@ -20,6 +20,9 @@ func _ready() -> void:
|
||||
navigation_agent_2d.avoidance_priority = randf_range(0.5, 1.0)
|
||||
attack_cooldown_offset = randf_range(0.0, 0.5)
|
||||
animated_sprite.speed_scale = randf_range(0.4, 1.2)
|
||||
|
||||
follow_update_timer.one_shot = false
|
||||
follow_update_timer.autostart = false
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if flicker_timer > 0.0:
|
||||
@@ -28,10 +31,24 @@ func _process(delta: float) -> void:
|
||||
if flicker_timer <= 0.0:
|
||||
animated_sprite.modulate = Color(1, 1, 1)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if !idle and target:
|
||||
if navigation_agent_2d.is_navigation_finished():
|
||||
velocity = Vector2.ZERO
|
||||
else:
|
||||
var next_pos: Vector2 = navigation_agent_2d.get_next_path_position()
|
||||
var direction: Vector2 = (next_pos - global_position).normalized()
|
||||
velocity = direction * speed * delta
|
||||
else:
|
||||
velocity = Vector2.ZERO
|
||||
|
||||
move_and_slide()
|
||||
|
||||
func _on_area_body_entered(body: Node2D) -> void:
|
||||
if body is Player:
|
||||
idle = false
|
||||
target = body
|
||||
navigation_agent_2d.target_position = target.global_position
|
||||
follow_update_timer.start()
|
||||
animated_sprite.play()
|
||||
|
||||
@@ -53,30 +70,12 @@ func _on_attack_area_body_exited(body: Node2D) -> void:
|
||||
in_attack_range = false
|
||||
attack_timer.stop()
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if !idle && target:
|
||||
if !navigation_agent_2d.is_navigation_finished():
|
||||
var next_path_pos: Vector2 = navigation_agent_2d.get_next_path_position()
|
||||
var direction: Vector2 = (next_path_pos - global_position).normalized()
|
||||
var desired_velocity: Vector2 = direction * speed * delta
|
||||
navigation_agent_2d.set_velocity(desired_velocity)
|
||||
else:
|
||||
velocity = Vector2.ZERO
|
||||
move_and_slide()
|
||||
else:
|
||||
velocity = Vector2.ZERO
|
||||
move_and_slide()
|
||||
|
||||
func _on_follow_update_timer_timeout() -> void:
|
||||
if target && !idle:
|
||||
if target and !idle:
|
||||
navigation_agent_2d.target_position = target.global_position
|
||||
|
||||
func _on_navigation_agent2d_velocity_computed(safe_velocity: Vector2) -> void:
|
||||
velocity = safe_velocity
|
||||
move_and_slide()
|
||||
|
||||
func _on_attack_timer_timeout() -> void:
|
||||
if target && in_attack_range:
|
||||
if target and in_attack_range:
|
||||
target.health -= DAMAGE
|
||||
|
||||
func _on_fightable_fought(player: Player) -> void:
|
||||
|
||||
@@ -89,3 +89,7 @@ func save_image() -> void:
|
||||
|
||||
func _on_undo_button_pressed() -> void:
|
||||
undo()
|
||||
|
||||
func _on_finish_pressed() -> void:
|
||||
EventManager.run_event(EventManager.Events.NONE)
|
||||
queue_free()
|
||||
|
||||
176
scripts/menus/util/dialog.gd
Normal file
176
scripts/menus/util/dialog.gd
Normal file
@@ -0,0 +1,176 @@
|
||||
extends Control
|
||||
## A basic dialogue balloon for use with Dialogue Manager.
|
||||
|
||||
## The action to use for advancing the dialogue
|
||||
@export var next_action: StringName = &"ui_accept"
|
||||
|
||||
## The action to use to skip typing the dialogue
|
||||
@export var skip_action: StringName = &"ui_cancel"
|
||||
|
||||
## The dialogue resource
|
||||
var resource: DialogueResource
|
||||
|
||||
## Temporary game states
|
||||
var temporary_game_states: Array = []
|
||||
|
||||
## See if we are waiting for the player
|
||||
var is_waiting_for_input: bool = false
|
||||
|
||||
## See if we are running a long mutation and should hide the balloon
|
||||
var will_hide_balloon: bool = false
|
||||
|
||||
## A dictionary to store any ephemeral variables
|
||||
var locals: Dictionary = {}
|
||||
|
||||
var _locale: String = TranslationServer.get_locale()
|
||||
|
||||
## The current line
|
||||
var dialogue_line: DialogueLine:
|
||||
set(value):
|
||||
if value:
|
||||
dialogue_line = value
|
||||
apply_dialogue_line()
|
||||
else:
|
||||
await get_tree().create_timer(.2).timeout # prevent dialogue trigger loop
|
||||
balloon.hide()
|
||||
get:
|
||||
return dialogue_line
|
||||
|
||||
## A cooldown timer for delaying the balloon hide when encountering a mutation.
|
||||
var mutation_cooldown: Timer = Timer.new()
|
||||
|
||||
## The base balloon anchor
|
||||
@onready var balloon: Control = %Balloon
|
||||
|
||||
## The label showing the name of the currently speaking character
|
||||
@onready var character_label: RichTextLabel = %CharacterLabel
|
||||
|
||||
## The label showing the currently spoken dialogue
|
||||
@onready var dialogue_label: DialogueLabel = %DialogueLabel
|
||||
|
||||
## The menu of responses
|
||||
@onready var responses_menu: DialogueResponsesMenu = %ResponsesMenu
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
balloon.hide()
|
||||
Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated)
|
||||
|
||||
# If the responses menu doesn't have a next action set, use this one
|
||||
if responses_menu.next_action.is_empty():
|
||||
responses_menu.next_action = next_action
|
||||
|
||||
mutation_cooldown.timeout.connect(_on_mutation_cooldown_timeout)
|
||||
add_child(mutation_cooldown)
|
||||
|
||||
|
||||
func _unhandled_input(_event: InputEvent) -> void:
|
||||
# Only the balloon is allowed to handle input while it's showing
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
## Detect a change of locale and update the current dialogue line to show the new language
|
||||
if what == NOTIFICATION_TRANSLATION_CHANGED and _locale != TranslationServer.get_locale() and is_instance_valid(dialogue_label):
|
||||
_locale = TranslationServer.get_locale()
|
||||
var visible_ratio = dialogue_label.visible_ratio
|
||||
self.dialogue_line = await resource.get_next_dialogue_line(dialogue_line.id)
|
||||
if visible_ratio < 1:
|
||||
dialogue_label.skip_typing()
|
||||
|
||||
|
||||
## Start some dialogue
|
||||
func start(dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []) -> void:
|
||||
temporary_game_states = [self] + extra_game_states
|
||||
is_waiting_for_input = false
|
||||
resource = dialogue_resource
|
||||
self.dialogue_line = await resource.get_next_dialogue_line(title, temporary_game_states)
|
||||
|
||||
|
||||
## Apply any changes to the balloon given a new [DialogueLine].
|
||||
func apply_dialogue_line() -> void:
|
||||
mutation_cooldown.stop()
|
||||
|
||||
is_waiting_for_input = false
|
||||
balloon.focus_mode = Control.FOCUS_ALL
|
||||
balloon.grab_focus()
|
||||
|
||||
character_label.visible = not dialogue_line.character.is_empty()
|
||||
character_label.text = tr(dialogue_line.character, "dialogue")
|
||||
|
||||
dialogue_label.hide()
|
||||
dialogue_label.dialogue_line = dialogue_line
|
||||
|
||||
responses_menu.hide()
|
||||
responses_menu.responses = dialogue_line.responses
|
||||
|
||||
# Show our balloon
|
||||
balloon.show()
|
||||
will_hide_balloon = false
|
||||
|
||||
dialogue_label.show()
|
||||
if not dialogue_line.text.is_empty():
|
||||
dialogue_label.type_out()
|
||||
await dialogue_label.finished_typing
|
||||
|
||||
# Wait for input
|
||||
if dialogue_line.responses.size() > 0:
|
||||
balloon.focus_mode = Control.FOCUS_NONE
|
||||
responses_menu.show()
|
||||
elif dialogue_line.time != "":
|
||||
var time = dialogue_line.text.length() * 0.02 if dialogue_line.time == "auto" else dialogue_line.time.to_float()
|
||||
await get_tree().create_timer(time).timeout
|
||||
next(dialogue_line.next_id)
|
||||
else:
|
||||
is_waiting_for_input = true
|
||||
balloon.focus_mode = Control.FOCUS_ALL
|
||||
balloon.grab_focus()
|
||||
|
||||
|
||||
## Go to the next line
|
||||
func next(next_id: String) -> void:
|
||||
self.dialogue_line = await resource.get_next_dialogue_line(next_id, temporary_game_states)
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
|
||||
func _on_mutation_cooldown_timeout() -> void:
|
||||
if will_hide_balloon:
|
||||
will_hide_balloon = false
|
||||
balloon.hide()
|
||||
|
||||
|
||||
func _on_mutated(_mutation: Dictionary) -> void:
|
||||
is_waiting_for_input = false
|
||||
will_hide_balloon = true
|
||||
mutation_cooldown.start(0.1)
|
||||
|
||||
|
||||
func _on_balloon_gui_input(event: InputEvent) -> void:
|
||||
# See if we need to skip typing of the dialogue
|
||||
if dialogue_label.is_typing:
|
||||
var mouse_was_clicked: bool = event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed()
|
||||
var skip_button_was_pressed: bool = event.is_action_pressed(skip_action)
|
||||
if mouse_was_clicked or skip_button_was_pressed:
|
||||
get_viewport().set_input_as_handled()
|
||||
dialogue_label.skip_typing()
|
||||
return
|
||||
|
||||
if not is_waiting_for_input: return
|
||||
if dialogue_line.responses.size() > 0: return
|
||||
|
||||
# When there are no response options the balloon itself is the clickable thing
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
if event is InputEventMouseButton and event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
next(dialogue_line.next_id)
|
||||
elif event.is_action_pressed(next_action) and get_viewport().gui_get_focus_owner() == balloon:
|
||||
next(dialogue_line.next_id)
|
||||
|
||||
|
||||
func _on_responses_menu_response_selected(response: DialogueResponse) -> void:
|
||||
next(response.next_id)
|
||||
|
||||
|
||||
#endregion
|
||||
1
scripts/menus/util/dialog.gd.uid
Normal file
1
scripts/menus/util/dialog.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cky2m61jgkbsi
|
||||
@@ -60,6 +60,7 @@ func interact() -> void:
|
||||
if interactable == null:
|
||||
fight_animation.rotation_degrees = 0
|
||||
fight_animation.play()
|
||||
$Hit.play()
|
||||
if !fight_animation.is_playing():
|
||||
fight_animation.play()
|
||||
await animated_sprite.animation_finished
|
||||
@@ -69,6 +70,7 @@ func interact() -> void:
|
||||
if interactable == null:
|
||||
fight_animation.rotation_degrees = 180
|
||||
fight_animation.play()
|
||||
$Hit.play()
|
||||
if !fight_animation.is_playing():
|
||||
fight_animation.play()
|
||||
await animated_sprite.animation_finished
|
||||
@@ -76,6 +78,7 @@ func interact() -> void:
|
||||
"side":
|
||||
animated_sprite.play("hand_side")
|
||||
if interactable == null:
|
||||
$Hit.play()
|
||||
if animated_sprite.flip_h:
|
||||
fight_animation.rotation_degrees = 90
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user