Rat dialogue
@@ -64,8 +64,10 @@ namespace DialogueManagerRuntime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isWaitingForInput) return;
|
if (!isWaitingForInput)
|
||||||
if (dialogueLine.Responses.Count > 0) return;
|
return;
|
||||||
|
if (dialogueLine.Responses.Count > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
GetViewport().SetInputAsHandled();
|
GetViewport().SetInputAsHandled();
|
||||||
|
|
||||||
@@ -104,22 +106,6 @@ namespace DialogueManagerRuntime
|
|||||||
GetViewport().SetInputAsHandled();
|
GetViewport().SetInputAsHandled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override async void _Notification(int what)
|
|
||||||
{
|
|
||||||
// Detect a change of locale and update the current dialogue line to show the new language
|
|
||||||
if (what == NotificationTranslationChanged)
|
|
||||||
{
|
|
||||||
float visibleRatio = dialogueLabel.VisibleRatio;
|
|
||||||
DialogueLine = await DialogueManager.GetNextDialogueLine(resource, DialogueLine.Id, temporaryGameStates);
|
|
||||||
if (visibleRatio < 1.0f)
|
|
||||||
{
|
|
||||||
dialogueLabel.Call("skip_typing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async void Start(Resource dialogueResource, string title, Array<Variant> extraGameStates = null)
|
public async void Start(Resource dialogueResource, string title, Array<Variant> extraGameStates = null)
|
||||||
{
|
{
|
||||||
temporaryGameStates = extraGameStates ?? new Array<Variant>();
|
temporaryGameStates = extraGameStates ?? new Array<Variant>();
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://debwoww4x115m"]
|
|
||||||
|
|
||||||
[node name="IntroductionDemoMarginContainer" type="CenterContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="IntroductionDemoVBoxContainer" type="VBoxContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="IntroductionDemoExaplanationPanelContainer" type="PanelContainer" parent="IntroductionDemoVBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="IntroductionDemoExaplanationLabel" type="Label" parent="IntroductionDemoVBoxContainer/IntroductionDemoExaplanationPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Basic dialogue processing is composed of two parts:"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="IntroductionDemoPreparationLabel" type="Label" parent="IntroductionDemoVBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "1. Dialogue tree preparation:"
|
|
||||||
|
|
||||||
[node name="IntroductionDemoPreparationExampleCodeEdit" type="CodeEdit" parent="IntroductionDemoVBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_colors/font_readonly_color = Color(1, 1, 1, 1)
|
|
||||||
text = "extends DialogueEngine
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry(\"First dialogue message\")
|
|
||||||
add_text_entry(\"Second dialogue message\")
|
|
||||||
add_text_entry(\"Third dialogue message\")
|
|
||||||
# and so on"
|
|
||||||
editable = false
|
|
||||||
scroll_fit_content_height = true
|
|
||||||
symbol_lookup_on_click = true
|
|
||||||
auto_brace_completion_highlight_matching = true
|
|
||||||
|
|
||||||
[node name="IntroductionDemoTraversalLabel" type="Label" parent="IntroductionDemoVBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "2. And tree traversal:"
|
|
||||||
|
|
||||||
[node name="IntroductionDemoTraversalExamplePanelContainer" type="PanelContainer" parent="IntroductionDemoVBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="IntroductionDemoTraversalExampleLabel" type="Label" parent="IntroductionDemoVBoxContainer/IntroductionDemoTraversalExamplePanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "dialogue_engine.advance() # called when convenient"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("Hey...")
|
|
||||||
add_text_entry("[i]Have [i][b]you[/b][/i] seen the code for this sample?[/i]")
|
|
||||||
add_text_entry("[rainbow freq=1.0 sat=0.4 val=0.8]It's beautiful![/rainbow]")
|
|
||||||
add_text_entry("[i][shake rate=20.0 level=5 connected=1]You won't believe it![/shake][/i]")
|
|
||||||
add_text_entry("[code][i]Press <Enter> or <Space> to exit.[/i][/code]")
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://bl1ul621fkvxw"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/1. simple dialogue/simple_log.gd" id="1_km05v"]
|
|
||||||
[ext_resource type="Script" path="res://demos/1. simple dialogue/simple_dialogue.gd" id="2_clmvy"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_km05v")
|
|
||||||
dialogue_gdscript = ExtResource("2_clmvy")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
|
|
||||||
const SAVE_PATH : String = "user://save.dat"
|
|
||||||
var counter : int = 0
|
|
||||||
var start_counting_id : int = 0
|
|
||||||
var log_history : Array = []
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("This is an example of an infinite dynamically generated/saved/loaded dialogue.")
|
|
||||||
add_text_entry("You can save the dialogue progress at any time by clicking the save button above.")
|
|
||||||
add_text_entry("And when you restart this scene, the dialogue will continue from where it left off.")
|
|
||||||
add_text_entry("As the dialogue progresses, the graph in the debugger will update automatically as well.")
|
|
||||||
add_text_entry("Let's count to infinity!!")
|
|
||||||
dialogue_continued.connect(__log_history)
|
|
||||||
dialogue_about_to_finish.connect(__continue_counting)
|
|
||||||
|
|
||||||
# Load previous state if any
|
|
||||||
load_state()
|
|
||||||
|
|
||||||
|
|
||||||
func __log_history(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
# Always track the log history:
|
|
||||||
log_history.push_back(p_dialogue_entry.get_formatted_text())
|
|
||||||
|
|
||||||
func __continue_counting() -> void:
|
|
||||||
counter += 1
|
|
||||||
add_text_entry(str(counter))
|
|
||||||
|
|
||||||
|
|
||||||
func save_state() -> void:
|
|
||||||
var file_handle: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
|
||||||
file_handle.store_var(counter)
|
|
||||||
file_handle.store_var(get_current_entry().get_id())
|
|
||||||
file_handle.store_var(log_history)
|
|
||||||
print("State Saved")
|
|
||||||
|
|
||||||
|
|
||||||
func load_state() -> void:
|
|
||||||
if FileAccess.file_exists(SAVE_PATH):
|
|
||||||
var file_handle: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.READ)
|
|
||||||
counter = file_handle.get_var()
|
|
||||||
var entry_id : int = file_handle.get_var()
|
|
||||||
if has_entry_id(entry_id):
|
|
||||||
set_current_entry(entry_id)
|
|
||||||
else:
|
|
||||||
set_current_entry(add_text_entry("Let's continue counting!!").get_id())
|
|
||||||
log_history = file_handle.get_var()
|
|
||||||
print("State Loaded")
|
|
||||||
|
|
||||||
|
|
||||||
func clear_state() -> void:
|
|
||||||
if FileAccess.file_exists(SAVE_PATH):
|
|
||||||
DirAccess.remove_absolute(SAVE_PATH)
|
|
||||||
print("State Cleared")
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
extends Control
|
|
||||||
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
@onready var dialogue : VBoxContainer = $VBox/Dialogue
|
|
||||||
@onready var history : CenterContainer = $History
|
|
||||||
@onready var history_log : VBoxContainer = $History/Panel/Margin/HistoryLog
|
|
||||||
@onready var animator : AnimationPlayer = $Animator
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
if animator.is_playing():
|
|
||||||
# Player is inpatient -- auto-advance the text
|
|
||||||
var animation_name : StringName = animator.get_current_animation()
|
|
||||||
var animation : Animation = animator.get_animation(animation_name)
|
|
||||||
animator.advance(animation.get_length()) # this will fire the animation_finished signal automatically else:
|
|
||||||
else:
|
|
||||||
# Advance current entry
|
|
||||||
dialogue_engine.advance()
|
|
||||||
accept_event() # accepting input event here to stop it from traversing into into buttons possibly added through the interaction
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
# Add the text to the log:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
var author : String = p_dialogue_entry.get_metadata("author")
|
|
||||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_formatted_text())
|
|
||||||
else:
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_formatted_text())
|
|
||||||
dialogue.add_child(label, true)
|
|
||||||
|
|
||||||
# Setup the animation:
|
|
||||||
animator.stop(true) # internally some timers do not reset properly unless we do this
|
|
||||||
if not animator.has_animation_library(&"demo"):
|
|
||||||
var new_animation_library : AnimationLibrary = AnimationLibrary.new()
|
|
||||||
animator.add_animation_library(&"demo", new_animation_library)
|
|
||||||
var animation_library : AnimationLibrary = animator.get_animation_library(&"demo")
|
|
||||||
var animation : Animation = create_visible_characters_animation_per_character(label.get_text(), 0.045, true)
|
|
||||||
animator.set_root_node(label.get_path())
|
|
||||||
animation_library.add_animation(&"dialogue", animation)
|
|
||||||
animator.play(&"demo/dialogue")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_animation_started(p_animation_name : StringName) -> void:
|
|
||||||
print("Animation started:", p_animation_name)
|
|
||||||
|
|
||||||
|
|
||||||
func create_visible_characters_animation_per_character(p_text : String, p_time_per_character : float, p_instant_first_character : bool = false, p_time_whitespace : bool = false) -> Animation:
|
|
||||||
# Do initial calculations
|
|
||||||
var whitespace_regex : RegEx
|
|
||||||
if not p_time_whitespace or p_instant_first_character:
|
|
||||||
whitespace_regex = RegEx.new()
|
|
||||||
whitespace_regex.compile("\\s")
|
|
||||||
|
|
||||||
# Create animation and track
|
|
||||||
var animation : Animation = Animation.new()
|
|
||||||
var track_index : int = animation.add_track(Animation.TYPE_VALUE)
|
|
||||||
animation.track_set_path(track_index, ".:visible_characters")
|
|
||||||
animation.track_set_interpolation_type(track_index, Animation.INTERPOLATION_LINEAR)
|
|
||||||
|
|
||||||
# Configure keys
|
|
||||||
var total_time : float = 0.0
|
|
||||||
var total_visible_characters : int = 0
|
|
||||||
var whitespace_time_offset : float = 0.0
|
|
||||||
animation.track_insert_key(track_index, total_time, 0)
|
|
||||||
var total_animation_length : float = 0.0
|
|
||||||
for character : String in p_text:
|
|
||||||
total_time += p_time_per_character
|
|
||||||
total_visible_characters += 1
|
|
||||||
if not p_time_whitespace and whitespace_regex.sub(character, "", true).is_empty():
|
|
||||||
whitespace_time_offset += p_time_per_character
|
|
||||||
continue
|
|
||||||
total_animation_length = total_time - whitespace_time_offset
|
|
||||||
animation.track_insert_key(track_index, total_animation_length, total_visible_characters)
|
|
||||||
animation.set_length(total_animation_length)
|
|
||||||
|
|
||||||
if p_instant_first_character:
|
|
||||||
if animation.track_get_key_count(track_index) > 0:
|
|
||||||
# Shift all the keys back in time according to the time it took per character
|
|
||||||
for key_index : int in animation.track_get_key_count(track_index):
|
|
||||||
var key_time : float = animation.track_get_key_time(track_index, key_index)
|
|
||||||
animation.track_set_key_time(track_index, key_index, key_time - p_time_per_character)
|
|
||||||
animation.set_length(total_animation_length - p_time_per_character)
|
|
||||||
return animation
|
|
||||||
|
|
||||||
|
|
||||||
func _on_history_log_toggled(p_should_be_visible : bool) -> void:
|
|
||||||
# Free all previous history labels
|
|
||||||
for child: Node in history_log.get_children():
|
|
||||||
child.queue_free()
|
|
||||||
|
|
||||||
history.visible = p_should_be_visible
|
|
||||||
|
|
||||||
if p_should_be_visible:
|
|
||||||
@warning_ignore("unsafe_method_access")
|
|
||||||
var log_history : Array = dialogue_engine.get_log_history()
|
|
||||||
for text : String in log_history:
|
|
||||||
var label: Label = Label.new()
|
|
||||||
label.text = text
|
|
||||||
history_log.add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_save_pressed() -> void:
|
|
||||||
@warning_ignore("unsafe_method_access")
|
|
||||||
dialogue_engine.save_state()
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_clear_pressed() -> void:
|
|
||||||
@warning_ignore("unsafe_method_access")
|
|
||||||
dialogue_engine.clear_state()
|
|
||||||
get_tree().quit()
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://b0gsgxefiut4g"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/10. dynamic save and load/dynamic_save_load.gd" id="1_75aob"]
|
|
||||||
[ext_resource type="Script" path="res://demos/10. dynamic save and load/dynamic_save_dialogue.gd" id="2_lqhmn"]
|
|
||||||
|
|
||||||
[node name="DynamicSaveLoad" type="Control"]
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_75aob")
|
|
||||||
dialogue_gdscript = ExtResource("2_lqhmn")
|
|
||||||
|
|
||||||
[node name="VBox" type="VBoxContainer" parent="."]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="VBox/DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Buttons" type="HBoxContainer" parent="VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Save" type="Button" parent="VBox/Buttons"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Save and Quit"
|
|
||||||
|
|
||||||
[node name="Clear" type="Button" parent="VBox/Buttons"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Clear State and Quit"
|
|
||||||
|
|
||||||
[node name="HistoryLog" type="Button" parent="VBox/Buttons"]
|
|
||||||
layout_mode = 2
|
|
||||||
toggle_mode = true
|
|
||||||
text = "History Log"
|
|
||||||
|
|
||||||
[node name="Dialogue" type="VBoxContainer" parent="VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="VBox/Dialogue"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
|
|
||||||
[node name="History" type="CenterContainer" parent="."]
|
|
||||||
visible = false
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
|
|
||||||
[node name="Panel" type="PanelContainer" parent="History"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="History/Panel"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_top = 16
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_bottom = 16
|
|
||||||
|
|
||||||
[node name="HistoryLog" type="VBoxContainer" parent="History/Panel/Margin"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Animator" type="AnimationPlayer" parent="."]
|
|
||||||
root_node = NodePath("../VBox")
|
|
||||||
|
|
||||||
[connection signal="pressed" from="VBox/Buttons/Save" to="." method="_on_save_pressed"]
|
|
||||||
[connection signal="pressed" from="VBox/Buttons/Clear" to="." method="_on_clear_pressed"]
|
|
||||||
[connection signal="toggled" from="VBox/Buttons/HistoryLog" to="." method="_on_history_log_toggled"]
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
@onready var progress_bar : ProgressBar = $ProgressBar
|
|
||||||
@onready var vbox : VBoxContainer = $VBox
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
accept_event() # to avoid hidding an button due to the input event travelling through the children
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
var enabled_buttons : Array[Button] = []
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
vbox.add_child(label)
|
|
||||||
|
|
||||||
if p_dialogue_entry.has_options():
|
|
||||||
var dont_show_options : Array = p_dialogue_entry.get_metadata("dont_show_options", [])
|
|
||||||
for option_id : int in range(0, p_dialogue_entry.get_option_count()):
|
|
||||||
if option_id in dont_show_options:
|
|
||||||
continue
|
|
||||||
var option_text : String = p_dialogue_entry.get_option_text(option_id)
|
|
||||||
var button : Button = Button.new()
|
|
||||||
button.set_text(option_text)
|
|
||||||
vbox.add_child(button)
|
|
||||||
var tween: Tween = create_tween()
|
|
||||||
if option_id == 0:
|
|
||||||
button.grab_focus()
|
|
||||||
tween.tween_property(button, "modulate", Color.TRANSPARENT, 3.0)
|
|
||||||
tween.tween_callback(button.hide)
|
|
||||||
else:
|
|
||||||
# Only show other buttons after the tween finishes
|
|
||||||
button.hide()
|
|
||||||
tween.tween_callback(button.show).set_delay(5.0)
|
|
||||||
|
|
||||||
if option_id == 1:
|
|
||||||
tween.tween_callback(button.grab_focus)
|
|
||||||
tween.tween_callback(progress_bar.show)
|
|
||||||
tween.tween_method(progress_bar.set_value, 1.0, 0.0, 2.0)
|
|
||||||
|
|
||||||
# The timer has just finished
|
|
||||||
tween.tween_callback(progress_bar.hide)
|
|
||||||
tween.tween_callback(advance_dialogue_no_answer)
|
|
||||||
button.pressed.connect(__advance_dialogue_with_chosen_option.bind(option_id))
|
|
||||||
enabled_buttons.push_back(button)
|
|
||||||
set_process_input(false)
|
|
||||||
|
|
||||||
|
|
||||||
func advance_dialogue_no_answer() -> void:
|
|
||||||
for button : Button in enabled_buttons:
|
|
||||||
button.set_disabled(true)
|
|
||||||
|
|
||||||
var entry : DialogueEntry = dialogue_engine.get_current_entry()
|
|
||||||
var option_id : int = entry.get_metadata("auto_choose")
|
|
||||||
entry.choose_option(option_id)
|
|
||||||
dialogue_engine.advance()
|
|
||||||
set_process_input(true)
|
|
||||||
|
|
||||||
|
|
||||||
func __advance_dialogue_with_chosen_option(p_option_id : int) -> void:
|
|
||||||
# Kill all tweens from processing further
|
|
||||||
for tween: Tween in get_tree().get_processed_tweens():
|
|
||||||
tween.kill()
|
|
||||||
for button : Button in enabled_buttons:
|
|
||||||
button.set_disabled(true)
|
|
||||||
# Reset modulate of vanishing button
|
|
||||||
button.modulate = Color.WHITE
|
|
||||||
enabled_buttons.clear()
|
|
||||||
progress_bar.hide()
|
|
||||||
|
|
||||||
var current_entry : DialogueEntry = dialogue_engine.get_current_entry()
|
|
||||||
current_entry.choose_option(p_option_id)
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
set_process_input(true)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://ctlvurl3kobjf"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/11. timed options/timed_options.gd" id="1_g0ote"]
|
|
||||||
[ext_resource type="Script" path="res://demos/11. timed options/timed_options_dialogue.gd" id="2_gqlp8"]
|
|
||||||
|
|
||||||
[node name="TimedOptions" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_g0ote")
|
|
||||||
dialogue_gdscript = ExtResource("2_gqlp8")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="VBox" type="VBoxContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
|
|
||||||
[node name="ProgressBar" type="ProgressBar" parent="."]
|
|
||||||
visible = false
|
|
||||||
custom_minimum_size = Vector2(0, 16)
|
|
||||||
layout_mode = 2
|
|
||||||
max_value = 1.0
|
|
||||||
show_percentage = false
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DEFAULT_TOPIC = 0, # this is the branch used by default unless set_branch_id() is used
|
|
||||||
WATCH_THE_STORM,
|
|
||||||
GO_BACK_TO_SLEEP,
|
|
||||||
KEEP_WORKING,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
var entry : DialogueEntry = add_text_entry("The storm rages right outside the window. I should...")
|
|
||||||
var option_id_1 : int = entry.add_option("Wait for storm to finish.")
|
|
||||||
var option_id_2 : int = entry.add_option("Go back to sleep.")
|
|
||||||
var option_id_3 : int = entry.add_option("Get back to work.")
|
|
||||||
var option_id_4 : int = entry.add_option("Hidden option -- this should not be shown on the UI")
|
|
||||||
entry.set_metadata("dont_show_options", [option_id_4])
|
|
||||||
entry.set_metadata("auto_choose", option_id_4)
|
|
||||||
|
|
||||||
var option_id_2_entry : DialogueEntry = add_text_entry("That's right, sleep is for the strong 💪.", GO_BACK_TO_SLEEP)
|
|
||||||
entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id())
|
|
||||||
|
|
||||||
var option_id_3_entry : DialogueEntry = add_text_entry("That's right, let's get back to work 🫡", KEEP_WORKING)
|
|
||||||
entry.set_option_goto_id(option_id_3, option_id_3_entry.get_id())
|
|
||||||
|
|
||||||
var option_id_4_entry : DialogueEntry = add_text_entry("I think I'll enjoy watching the storm for a bit...", WATCH_THE_STORM)
|
|
||||||
entry.set_option_goto_id(option_id_4, option_id_4_entry.get_id())
|
|
||||||
|
|
||||||
# Join branches into the default topic (i.e. branch id 0)
|
|
||||||
var default_topic : DialogueEntry = add_text_entry("Some time passes...")
|
|
||||||
entry.set_option_goto_id(option_id_1, default_topic.get_id())
|
|
||||||
option_id_2_entry.set_goto_id(default_topic.get_id())
|
|
||||||
option_id_3_entry.set_goto_id(default_topic.get_id())
|
|
||||||
option_id_4_entry.set_goto_id(default_topic.get_id())
|
|
||||||
|
|
||||||
add_text_entry("<Press 'Space' or 'Enter' to quit>")
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
var first_entry : DialogueEntry = add_text_entry("This is an example of...")
|
|
||||||
add_text_entry("This text will be shown on the debugger connected to branch ID 0")
|
|
||||||
add_text_entry("This text will be shown on the debugger as a separate graph node not connected to branch id 0", 1)
|
|
||||||
var first_entry_goto : DialogueEntry = add_text_entry("a skipped dialogue! Check the debugger out!")
|
|
||||||
first_entry.set_goto_id(first_entry_goto.get_id())
|
|
||||||
add_text_entry("Press <Enter> or <Space> to exit.")
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
var enabled_buttons : Array[Button] = []
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
get_tree().quit()
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://dkfjywgk5gykn"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/2. same branch goto/same_branch_goto_log.gd" id="1_biw57"]
|
|
||||||
[ext_resource type="Script" path="res://demos/2. same branch goto/same_branch_goto_dialogue.gd" id="2_bn40h"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_biw57")
|
|
||||||
dialogue_gdscript = ExtResource("2_bn40h")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
enum { DEFAULT_BRANCH = 0, DIFFERENT_BRANCH_ONE, DIFFERENT_BRANCH_TWO, DIFFERENT_BRANCH_THREE }
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
var first_entry : DialogueEntry = add_text_entry("This is an example of...", DEFAULT_BRANCH)
|
|
||||||
first_entry.set_goto_id(add_text_entry("how gotos work against different branch IDs", DIFFERENT_BRANCH_TWO).get_id())
|
|
||||||
add_text_entry("Once you jump to a different branch ID, the DialogueEngine will only consider entries in that branch ID unless you jump to a different one.", DIFFERENT_BRANCH_TWO)
|
|
||||||
add_text_entry("If, for example, you add another text entry to a branch ID that is empty, it will show up in Debugger/DialogueEngine as such.", DIFFERENT_BRANCH_TWO)
|
|
||||||
add_text_entry("For example, this text will be shown on branch ID %d in the debugger and not connected to anything. It won't show up in the interaction either." % DIFFERENT_BRANCH_ONE, DIFFERENT_BRANCH_ONE)
|
|
||||||
add_text_entry("You can also create full branches in a different branch ID", DIFFERENT_BRANCH_THREE)
|
|
||||||
add_text_entry("But since there's no jump to this branch (i.e. no goto set to this branch ID)", DIFFERENT_BRANCH_THREE)
|
|
||||||
add_text_entry("It won't show up in the interaction", DIFFERENT_BRANCH_THREE)
|
|
||||||
add_text_entry("See the auto-generated graph in Debugger/DialogueEngine.", DIFFERENT_BRANCH_TWO)
|
|
||||||
add_text_entry("Press <Enter> or <Space> to exit.", DIFFERENT_BRANCH_TWO)
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
var enabled_buttons : Array[Button] = []
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
get_tree().quit()
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://clxd85by8v506"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/3. different branch goto/different_branch_goto_log.gd" id="1_et54s"]
|
|
||||||
[ext_resource type="Script" path="res://demos/3. different branch goto/different_branch_goto_dialogue.gd" id="2_x1mbj"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_et54s")
|
|
||||||
dialogue_gdscript = ExtResource("2_x1mbj")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
var have_we_talked_before : bool = false
|
|
||||||
|
|
||||||
enum branch {
|
|
||||||
STRANGERS,
|
|
||||||
ACQUAINTANCES,
|
|
||||||
}
|
|
||||||
|
|
||||||
func __have_we_talked_before() -> bool:
|
|
||||||
return have_we_talked_before
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("Hello!")
|
|
||||||
var condition_entry : DialogueEntry = add_conditional_entry(__have_we_talked_before)
|
|
||||||
var if_true : DialogueEntry = add_text_entry("Hey! We meet again!", branch.STRANGERS)
|
|
||||||
var if_false : DialogueEntry = add_text_entry("It's nice to meet you!", branch.ACQUAINTANCES)
|
|
||||||
condition_entry.set_condition_goto_ids(if_true.get_id(), if_false.get_id())
|
|
||||||
add_text_entry("<Press 'Enter' or 'Space' to exit>")
|
|
||||||
|
|
||||||
dialogue_finished.connect(func() -> void: have_we_talked_before = true)
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
var dialogue_finished_count : int = 0
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
var enabled_buttons : Array[Button] = []
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
if dialogue_finished_count > 0:
|
|
||||||
get_tree().quit()
|
|
||||||
return
|
|
||||||
dialogue_finished_count += 1
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text("<Some time passes>")
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://bl1d3ktmm0s7f"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/4. branching condition/branching_condition_log.gd" id="1_7x7u2"]
|
|
||||||
[ext_resource type="Script" path="res://demos/4. branching condition/branching_condition_dialogue.gd" id="2_yhcl2"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_7x7u2")
|
|
||||||
dialogue_gdscript = ExtResource("2_yhcl2")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DEFAULT_TOPIC = 0, # this is the branch used by default unless set_branch_id() is used
|
|
||||||
GO_BACK_TO_SLEEP = 1,
|
|
||||||
KEEP_WORKING = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
var entry : DialogueEntry = add_text_entry("The storm rages right outside the window. I should...")
|
|
||||||
var option_id_1 : int = entry.add_option("Go back to sleep.")
|
|
||||||
var option_id_2 : int = entry.add_option("Get back to work.")
|
|
||||||
|
|
||||||
var option_id_1_entry : DialogueEntry = add_text_entry("That's right, sleep is for the strong 💪.", GO_BACK_TO_SLEEP)
|
|
||||||
entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id())
|
|
||||||
|
|
||||||
var option_id_2_entry : DialogueEntry = add_text_entry("That's right, let's get back to work 🫡", KEEP_WORKING)
|
|
||||||
entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id())
|
|
||||||
|
|
||||||
# Join branches into the default topic (i.e. branch id 0)
|
|
||||||
var default_topic : DialogueEntry = add_text_entry("Some time passes...")
|
|
||||||
option_id_1_entry.set_goto_id(default_topic.get_id())
|
|
||||||
option_id_2_entry.set_goto_id(default_topic.get_id())
|
|
||||||
|
|
||||||
# None of the following entries will be connected on the graph and won't be shown when advancing the dialogue
|
|
||||||
add_text_entry("A sleep entry skipped due to missing goto against this entry.", GO_BACK_TO_SLEEP)
|
|
||||||
add_text_entry("A working entry due to missing goto against this entry.", KEEP_WORKING)
|
|
||||||
|
|
||||||
add_text_entry("<Press 'Space' or 'Enter' to quit>")
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
accept_event() # to avoid hidding an button due to the input event travelling through the children
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
var enabled_buttons : Array[Button] = []
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
if p_dialogue_entry.has_options():
|
|
||||||
for option_id : int in range(0, p_dialogue_entry.get_option_count()):
|
|
||||||
var option_text : String = p_dialogue_entry.get_option_text(option_id)
|
|
||||||
var button : Button = Button.new()
|
|
||||||
button.set_text(option_text)
|
|
||||||
add_child(button)
|
|
||||||
if option_id == 0:
|
|
||||||
button.grab_focus()
|
|
||||||
button.pressed.connect(__advance_dialogue_with_chosen_option.bind(option_id))
|
|
||||||
enabled_buttons.push_back(button)
|
|
||||||
set_process_input(false)
|
|
||||||
|
|
||||||
|
|
||||||
func __advance_dialogue_with_chosen_option(p_option_id : int) -> void:
|
|
||||||
for button : Button in enabled_buttons:
|
|
||||||
button.set_disabled(true)
|
|
||||||
enabled_buttons.clear()
|
|
||||||
|
|
||||||
var current_entry : DialogueEntry = dialogue_engine.get_current_entry()
|
|
||||||
current_entry.choose_option(p_option_id)
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
set_process_input(true)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://c1803quu2vtn"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/5. branching options dialogue/branching_options_dialogue_log.gd" id="1_0yldt"]
|
|
||||||
[ext_resource type="Script" path="res://demos/5. branching options dialogue/branching_options_dialogue.gd" id="2_h7u25"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_0yldt")
|
|
||||||
dialogue_gdscript = ExtResource("2_h7u25")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
# Use DialogueEntry.set_metadata for data that must be available through DialogueEngine.dialogue_continued signal.
|
|
||||||
# The metadata handling per DialogueEntry must be implemented by the user.
|
|
||||||
add_text_entry("[i]We won! Let's goooo!![/i]").set_metadata("author", "Gary")
|
|
||||||
add_text_entry("Press <Enter> or <Space> to exit.")
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
var author : String = p_dialogue_entry.get_metadata("author")
|
|
||||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_text())
|
|
||||||
else:
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://jeupskd3oea8"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/6. handling metadata/handling_metadata_log.gd" id="1_0ot0q"]
|
|
||||||
[ext_resource type="Script" path="res://demos/6. handling metadata/handling_metadata_dialogue.gd" id="2_tq44t"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_0ot0q")
|
|
||||||
dialogue_gdscript = ExtResource("2_tq44t")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
var player_name : String # will be set by the UI code
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("Welcome adventurer. May I know you name?").set_metadata(&"get_player_name", "The UI code will act accordingly and inject player_name into DialogueEngine.")
|
|
||||||
add_text_entry("The legendary {player_name}!? Please, follow me this way. I will personally show you our guild.").set_format({"player_name" : get.bind("player_name")}, DialogueEntry.FORMAT_FUNCTION)
|
|
||||||
add_text_entry("Press <Enter> or <Space> to exit.")
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
dialogue_engine.advance()
|
|
||||||
accept_event()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
var author : String = p_dialogue_entry.get_metadata("author")
|
|
||||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_formatted_text())
|
|
||||||
else:
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_formatted_text())
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
if p_dialogue_entry.has_metadata(&"get_player_name"):
|
|
||||||
__get_player_name()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
# Must return player name to update the variable within DialogueEngine
|
|
||||||
func __get_player_name() -> void:
|
|
||||||
var line_edit : LineEdit = LineEdit.new()
|
|
||||||
add_child(line_edit)
|
|
||||||
var p_data : Array = []
|
|
||||||
line_edit.text_submitted.connect(func(text : String) -> void:
|
|
||||||
p_data.push_back(text)
|
|
||||||
)
|
|
||||||
line_edit.grab_focus()
|
|
||||||
line_edit.set_placeholder("Enter your name.")
|
|
||||||
set_process_input(false)
|
|
||||||
await line_edit.text_submitted
|
|
||||||
line_edit.set_editable(false)
|
|
||||||
@warning_ignore("unsafe_property_access")
|
|
||||||
dialogue_engine.player_name = p_data[0]
|
|
||||||
set_process_input(true)
|
|
||||||
dialogue_engine.advance()
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://cc22y2sa14se6"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/7. handling input/handling_input_log.gd" id="1_4r4r1"]
|
|
||||||
[ext_resource type="Script" path="res://demos/7. handling input/handling_input_dialogue.gd" id="2_ti25x"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_4r4r1")
|
|
||||||
dialogue_gdscript = ExtResource("2_ti25x")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
var player_name : String # will be set by the UI code
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("Welcome adventurer. May I know you name?").set_metadata(&"get_player_name", "The UI code will act accordingly and inject player_name into DialogueEngine.")
|
|
||||||
add_text_entry("The legendary %s!? Please, follow me this way. I will personally show you our guild.").set_format([get.bind("player_name")], DialogueEntry.FORMAT_OPERATOR)
|
|
||||||
add_text_entry("Press <Enter> or <Space> to exit.").set_name("Exit")
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
@onready var animation_player : AnimationPlayer = find_child("LogAnimationPlayer")
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
if not animation_player.is_playing():
|
|
||||||
dialogue_engine.advance()
|
|
||||||
else:
|
|
||||||
# Player is inpatient -- auto-advance the text
|
|
||||||
var animation_name : StringName = animation_player.get_current_animation()
|
|
||||||
var animation : Animation = animation_player.get_animation(animation_name)
|
|
||||||
animation_player.advance(animation.get_length()) # this will fire the animation_finished signal automatically
|
|
||||||
accept_event() # accepting input event here to stop it from traversing into into buttons possibly added through the interaction
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
# Add the text to the log:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
var author : String = p_dialogue_entry.get_metadata("author")
|
|
||||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_formatted_text())
|
|
||||||
else:
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_formatted_text())
|
|
||||||
add_child(label, true)
|
|
||||||
|
|
||||||
# Setup the animation:
|
|
||||||
animation_player.stop(true) # internally some timers do not reset properly unless we do this
|
|
||||||
if not animation_player.has_animation_library(&"demo"):
|
|
||||||
var new_animation_library : AnimationLibrary = AnimationLibrary.new()
|
|
||||||
animation_player.add_animation_library(&"demo", new_animation_library)
|
|
||||||
var animation_library : AnimationLibrary = animation_player.get_animation_library(&"demo")
|
|
||||||
var animation : Animation = create_visible_characters_animation_per_character(label.get_text(), 0.045, true)
|
|
||||||
animation_player.set_root_node(label.get_path())
|
|
||||||
animation_library.add_animation(&"dialogue", animation)
|
|
||||||
animation_player.play(&"demo/dialogue")
|
|
||||||
|
|
||||||
# Setup the post dialogue callback
|
|
||||||
if p_dialogue_entry.has_metadata(&"get_player_name"):
|
|
||||||
animation_player.animation_finished.connect(__on_animation_finished.bind(__get_player_name), CONNECT_ONE_SHOT)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
# Must return player name to update the variable within DialogueEngine
|
|
||||||
func __get_player_name() -> void:
|
|
||||||
# Get player name into the current stack:
|
|
||||||
var line_edit : LineEdit = LineEdit.new()
|
|
||||||
add_child(line_edit)
|
|
||||||
var p_data : Array = []
|
|
||||||
line_edit.text_submitted.connect(func(text : String) -> void:
|
|
||||||
p_data.push_back(text)
|
|
||||||
)
|
|
||||||
line_edit.grab_focus()
|
|
||||||
line_edit.set_placeholder("Enter your name.")
|
|
||||||
|
|
||||||
# Disable input processing by this node to avoid calling DialogueEngine.advance if the user presses space or enter
|
|
||||||
set_process_input(false)
|
|
||||||
|
|
||||||
await line_edit.text_submitted
|
|
||||||
line_edit.set_editable(false)
|
|
||||||
|
|
||||||
# Allow the user to progress the dialogue
|
|
||||||
set_process_input(true)
|
|
||||||
|
|
||||||
# Auto-advance the dialogue so the user does not have to press space or enter again
|
|
||||||
@warning_ignore("unsafe_property_access")
|
|
||||||
dialogue_engine.player_name = p_data[0]
|
|
||||||
dialogue_engine.advance()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_animation_started(p_animation_name : StringName) -> void:
|
|
||||||
print("Animation started:", p_animation_name)
|
|
||||||
|
|
||||||
|
|
||||||
func __on_animation_finished(p_animation_name : StringName, p_post_dialogue_callback : Callable) -> void:
|
|
||||||
if p_animation_name == &"demo/dialogue":
|
|
||||||
p_post_dialogue_callback.call()
|
|
||||||
|
|
||||||
|
|
||||||
# Utility function to animate the text at a constant speed
|
|
||||||
func create_visible_characters_animation_per_character(p_text : String, p_time_per_character : float, p_instant_first_character : bool = false, p_time_whitespace : bool = false) -> Animation:
|
|
||||||
# Do initial calculations
|
|
||||||
var whitespace_regex : RegEx
|
|
||||||
if not p_time_whitespace or p_instant_first_character:
|
|
||||||
whitespace_regex = RegEx.new()
|
|
||||||
whitespace_regex.compile("\\s")
|
|
||||||
|
|
||||||
# Create animation and track
|
|
||||||
var animation : Animation = Animation.new()
|
|
||||||
var track_index : int = animation.add_track(Animation.TYPE_VALUE)
|
|
||||||
animation.track_set_path(track_index, ".:visible_characters")
|
|
||||||
animation.track_set_interpolation_type(track_index, Animation.INTERPOLATION_LINEAR)
|
|
||||||
|
|
||||||
# Configure keys
|
|
||||||
var total_time : float = 0.0
|
|
||||||
var total_visible_characters : int = 0
|
|
||||||
var whitespace_time_offset : float = 0.0
|
|
||||||
animation.track_insert_key(track_index, total_time, 0)
|
|
||||||
var total_animation_length : float = 0.0
|
|
||||||
for character : String in p_text:
|
|
||||||
total_time += p_time_per_character
|
|
||||||
total_visible_characters += 1
|
|
||||||
if not p_time_whitespace and whitespace_regex.sub(character, "", true).is_empty():
|
|
||||||
whitespace_time_offset += p_time_per_character
|
|
||||||
continue
|
|
||||||
total_animation_length = total_time - whitespace_time_offset
|
|
||||||
animation.track_insert_key(track_index, total_animation_length, total_visible_characters)
|
|
||||||
animation.set_length(total_animation_length)
|
|
||||||
|
|
||||||
if p_instant_first_character:
|
|
||||||
if animation.track_get_key_count(track_index) > 0:
|
|
||||||
# Shift all the keys back in time according to the time it took per character
|
|
||||||
for key_index : int in animation.track_get_key_count(track_index):
|
|
||||||
var key_time : float = animation.track_get_key_time(track_index, key_index)
|
|
||||||
animation.track_set_key_time(track_index, key_index, key_time - p_time_per_character)
|
|
||||||
animation.set_length(total_animation_length - p_time_per_character)
|
|
||||||
return animation
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://djujyea67gj55"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://demos/8. handling animations/handling_animations_log.gd" id="1_0567n"]
|
|
||||||
[ext_resource type="Script" path="res://demos/8. handling animations/handling_animations_dialogue.gd" id="2_4ky6k"]
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoVBoxContainer" type="VBoxContainer"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_0567n")
|
|
||||||
dialogue_gdscript = ExtResource("2_4ky6k")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="LogRichTextLabel" type="RichTextLabel" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
|
|
||||||
[node name="LogAnimationPlayer" type="AnimationPlayer" parent="."]
|
|
||||||
root_node = NodePath("../LogRichTextLabel")
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
extends Control
|
|
||||||
|
|
||||||
|
|
||||||
@export var dialogue_gdscript : GDScript = null
|
|
||||||
var dialogue_engine : DialogueEngine = null
|
|
||||||
|
|
||||||
@onready var animator : AnimationPlayer = $Animator
|
|
||||||
@onready var vbox : VBoxContainer = $Center/Box/Margin/VBox/VBox
|
|
||||||
@onready var peter : TextureRect = $Center/Box/Margin/VBox/Peter
|
|
||||||
@onready var john : TextureRect = $Center/Box/Margin/VBox/John
|
|
||||||
@onready var audio_player : AudioStreamPlayer = $AudioStreamPlayer
|
|
||||||
|
|
||||||
var beep : PackedVector2Array = []
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
dialogue_engine = dialogue_gdscript.new()
|
|
||||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
|
||||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
|
||||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
|
||||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
|
||||||
|
|
||||||
# Generate a beep to use when displaying the characters
|
|
||||||
var audio_frame_being_filled : int = 2730
|
|
||||||
var total_audio_frames_to_fill : int = audio_frame_being_filled
|
|
||||||
var beep_softener_ratio : float = 0.05
|
|
||||||
var sample_hz : float = 22050.0 # Keep the number of samples to mix low, GDScript is not super fast.
|
|
||||||
var pulse_hz : float = 440.0
|
|
||||||
var phase : float = 0.0
|
|
||||||
var increment : float = pulse_hz / sample_hz
|
|
||||||
while audio_frame_being_filled > 0:
|
|
||||||
var _ignore : bool = beep.push_back(Vector2.ONE * beep_softener_ratio * sin(phase * TAU) * audio_frame_being_filled/total_audio_frames_to_fill)
|
|
||||||
phase = fmod(phase + increment, 1.0)
|
|
||||||
audio_frame_being_filled -= 1
|
|
||||||
|
|
||||||
|
|
||||||
func _input(p_input_event : InputEvent) -> void:
|
|
||||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
|
||||||
if not animator.is_playing():
|
|
||||||
dialogue_engine.advance()
|
|
||||||
else:
|
|
||||||
# Player is inpatient -- auto-advance the text
|
|
||||||
var animation_name : StringName = animator.get_current_animation()
|
|
||||||
var animation : Animation = animator.get_animation(animation_name)
|
|
||||||
animator.advance(animation.get_length()) # this will fire the animation_finished signal automatically
|
|
||||||
accept_event() # accepting input event here to stop it from traversing into into buttons possibly added through the interaction
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_started() -> void:
|
|
||||||
print("Dialogue Started!")
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
|
||||||
# Add the text to the log:
|
|
||||||
var label : RichTextLabel = RichTextLabel.new()
|
|
||||||
label.set_use_bbcode(true)
|
|
||||||
label.set_fit_content(true)
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
var author : String = p_dialogue_entry.get_metadata("author")
|
|
||||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_formatted_text())
|
|
||||||
else:
|
|
||||||
label.set_text(" > " + p_dialogue_entry.get_formatted_text())
|
|
||||||
vbox.add_child(label, true)
|
|
||||||
|
|
||||||
# Setup the animation:
|
|
||||||
animator.stop(true) # internally some timers do not reset properly unless we do this
|
|
||||||
if not animator.has_animation_library(&"demo"):
|
|
||||||
var new_animation_library : AnimationLibrary = AnimationLibrary.new()
|
|
||||||
animator.add_animation_library(&"demo", new_animation_library)
|
|
||||||
var animation_library : AnimationLibrary = animator.get_animation_library(&"demo")
|
|
||||||
var animation : Animation = create_visible_characters_animation_per_character(label.get_text(), 0.045, true)
|
|
||||||
animator.set_root_node(label.get_path())
|
|
||||||
animation_library.add_animation(&"dialogue", animation)
|
|
||||||
animator.play(&"demo/dialogue")
|
|
||||||
|
|
||||||
# Hide all portraits
|
|
||||||
peter.hide()
|
|
||||||
john.hide()
|
|
||||||
|
|
||||||
# Show author portrait
|
|
||||||
if p_dialogue_entry.has_metadata("author"):
|
|
||||||
if p_dialogue_entry.get_metadata("author") == "Peter":
|
|
||||||
peter.show()
|
|
||||||
else:
|
|
||||||
john.show()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_finished() -> void:
|
|
||||||
print("Dialogue Finished! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_dialogue_cancelled() -> void:
|
|
||||||
print("Dialogue Cancelled! Exiting...")
|
|
||||||
get_tree().quit()
|
|
||||||
|
|
||||||
|
|
||||||
func __on_animation_started(p_animation_name : StringName) -> void:
|
|
||||||
print("Animation started:", p_animation_name)
|
|
||||||
|
|
||||||
|
|
||||||
# Utility function to animate the text at a constant speed
|
|
||||||
func create_visible_characters_animation_per_character(p_text : String, p_time_per_character : float, p_instant_first_character : bool = false, p_time_whitespace : bool = false) -> Animation:
|
|
||||||
# Do initial calculations
|
|
||||||
var whitespace_regex : RegEx
|
|
||||||
if not p_time_whitespace or p_instant_first_character:
|
|
||||||
whitespace_regex = RegEx.new()
|
|
||||||
whitespace_regex.compile("\\s")
|
|
||||||
|
|
||||||
# Create animation and track
|
|
||||||
var animation : Animation = Animation.new()
|
|
||||||
var track_index : int = animation.add_track(Animation.TYPE_VALUE)
|
|
||||||
animation.track_set_path(track_index, ".:visible_characters")
|
|
||||||
animation.track_set_interpolation_type(track_index, Animation.INTERPOLATION_LINEAR)
|
|
||||||
var sound_track_index : int = animation.add_track(Animation.TYPE_METHOD)
|
|
||||||
# The path provided here points to the root node (i.e. ComplexDialogue node)
|
|
||||||
animation.track_set_path(sound_track_index, "../../../../../..")
|
|
||||||
|
|
||||||
# Configure keys
|
|
||||||
var total_time : float = 0.0
|
|
||||||
var total_visible_characters : int = 0
|
|
||||||
var whitespace_time_offset : float = 0.0
|
|
||||||
animation.track_insert_key(track_index, total_time, 0)
|
|
||||||
var total_animation_length : float = 0.0
|
|
||||||
for character : String in p_text:
|
|
||||||
total_time += p_time_per_character
|
|
||||||
total_visible_characters += 1
|
|
||||||
if not p_time_whitespace and whitespace_regex.sub(character, "", true).is_empty():
|
|
||||||
whitespace_time_offset += p_time_per_character
|
|
||||||
continue
|
|
||||||
total_animation_length = total_time - whitespace_time_offset
|
|
||||||
animation.track_insert_key(track_index, total_animation_length, total_visible_characters)
|
|
||||||
# Simple sound animation:
|
|
||||||
var should_play : bool = total_visible_characters % 3 == 0 and total_visible_characters < p_text.length() - 1
|
|
||||||
if should_play:
|
|
||||||
animation.track_insert_key(sound_track_index, total_animation_length, {"method": "__play_sound", "args": []})
|
|
||||||
animation.set_length(total_animation_length)
|
|
||||||
|
|
||||||
if p_instant_first_character:
|
|
||||||
if animation.track_get_key_count(track_index) > 0:
|
|
||||||
# Shift all the keys back in time according to the time it took per character
|
|
||||||
for key_index : int in animation.track_get_key_count(track_index):
|
|
||||||
var key_time : float = animation.track_get_key_time(track_index, key_index)
|
|
||||||
animation.track_set_key_time(track_index, key_index, key_time - p_time_per_character)
|
|
||||||
animation.set_length(total_animation_length - p_time_per_character)
|
|
||||||
return animation
|
|
||||||
|
|
||||||
|
|
||||||
func __play_sound() -> void:
|
|
||||||
# Create the audio stream dynamically
|
|
||||||
var audio_stream : AudioStreamGenerator = AudioStreamGenerator.new()
|
|
||||||
const mix_rate : float = 22050.0
|
|
||||||
audio_stream.set_mix_rate(mix_rate)
|
|
||||||
audio_player.set_stream(audio_stream)
|
|
||||||
|
|
||||||
|
|
||||||
# Fill in the playback audio frames:
|
|
||||||
audio_player.play()
|
|
||||||
var playback : AudioStreamGeneratorPlayback = audio_player.get_stream_playback()
|
|
||||||
var total_available_frames : int = playback.get_frames_available()
|
|
||||||
var _success : bool = playback.push_buffer(beep)
|
|
||||||
var _frames_filled : int = total_available_frames - playback.get_frames_available()
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://djkxscwuw617h"]
|
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://cr0rdb3ab8xwg" path="res://icon.svg" id="1_5ptqw"]
|
|
||||||
[ext_resource type="Script" path="res://demos/9. complex dialogue/complex_dialogue.gd" id="1_qenq2"]
|
|
||||||
[ext_resource type="Script" path="res://demos/9. complex dialogue/dialogue.gd" id="2_buq0b"]
|
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hqwn4"]
|
|
||||||
bg_color = Color(0, 0, 0, 1)
|
|
||||||
|
|
||||||
[node name="ComplexDialogue" type="Control"]
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_qenq2")
|
|
||||||
dialogue_gdscript = ExtResource("2_buq0b")
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartPanelContainer" type="PanelContainer" parent="."]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 10
|
|
||||||
anchor_right = 1.0
|
|
||||||
offset_bottom = 23.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
|
|
||||||
[node name="DialogueEngineDemoQuickStartLabel" type="Label" parent="DialogueEngineDemoQuickStartPanelContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Press <Enter> or <Space> to progress the dialogue."
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Center" type="CenterContainer" parent="."]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="Box" type="PanelContainer" parent="Center"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_styles/panel = SubResource("StyleBoxFlat_hqwn4")
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="Center/Box"]
|
|
||||||
custom_minimum_size = Vector2(384, 384)
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_top = 16
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_bottom = 16
|
|
||||||
|
|
||||||
[node name="VBox" type="VBoxContainer" parent="Center/Box/Margin"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 32
|
|
||||||
|
|
||||||
[node name="VBox" type="VBoxContainer" parent="Center/Box/Margin/VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
|
|
||||||
[node name="Text" type="RichTextLabel" parent="Center/Box/Margin/VBox/VBox"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Log:"
|
|
||||||
fit_content = true
|
|
||||||
|
|
||||||
[node name="Peter" type="TextureRect" parent="Center/Box/Margin/VBox"]
|
|
||||||
visible = false
|
|
||||||
custom_minimum_size = Vector2(96, 96)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 0
|
|
||||||
texture = ExtResource("1_5ptqw")
|
|
||||||
expand_mode = 1
|
|
||||||
|
|
||||||
[node name="John" type="TextureRect" parent="Center/Box/Margin/VBox"]
|
|
||||||
visible = false
|
|
||||||
modulate = Color(0.980392, 0.631373, 1, 1)
|
|
||||||
custom_minimum_size = Vector2(96, 96)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 8
|
|
||||||
texture = ExtResource("1_5ptqw")
|
|
||||||
expand_mode = 1
|
|
||||||
|
|
||||||
[node name="Animator" type="AnimationPlayer" parent="."]
|
|
||||||
|
|
||||||
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
extends DialogueEngine
|
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
|
||||||
add_text_entry("Hello, how are you?").set_metadata("author", "Peter")
|
|
||||||
add_text_entry("I'm fine, thank you! And you?").set_metadata("author", "John")
|
|
||||||
add_text_entry("I'm fine too! Thank you!").set_metadata("author", "Peter")
|
|
||||||
add_text_entry("What's your name?").set_metadata("author", "John")
|
|
||||||
add_text_entry("I'm Peter, and you?").set_metadata("author", "Peter")
|
|
||||||
add_text_entry("Nice to meet you Peter! I'm John!").set_metadata("author", "John")
|
|
||||||
var entry: DialogueEntry = add_text_entry("Nice to meet you John!")
|
|
||||||
entry.set_metadata("author", "Peter")
|
|
||||||
entry.set_name("Exit")
|
|
||||||
@@ -18,6 +18,7 @@ boot_splash/show_image=false
|
|||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
||||||
|
DialogueController="*res://src/game/DialogueController.cs"
|
||||||
|
|
||||||
[dialogue_manager]
|
[dialogue_manager]
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ Throw={
|
|||||||
|
|
||||||
[internationalization]
|
[internationalization]
|
||||||
|
|
||||||
locale/translations_pot_files=PackedStringArray("res://src/dialog/Dialogue.dialogue", "res://src/ui/dialogue/FloorExit.dialogue")
|
locale/translations_pot_files=PackedStringArray("res://src/dialog/Dialogue.dialogue", "res://src/ui/dialogue/FloorExit.dialogue", "res://src/npc/rat/ratdialogue.dialogue")
|
||||||
|
|
||||||
[layer_names]
|
[layer_names]
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using Chickensoft.AutoInject;
|
|
||||||
using DialogueManagerRuntime;
|
using DialogueManagerRuntime;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class DialogueController : Node
|
public partial class DialogueController : Node
|
||||||
{
|
{
|
||||||
private DialogueManager DialogueManager;
|
public static PackedScene DialogueBalloon { get; set; }
|
||||||
|
|
||||||
[Export] public PackedScene DialogueBalloon { get; set; } = default!;
|
public DialogueController()
|
||||||
|
{
|
||||||
[Export] public Resource DialogueResource { get; set; } = default!;
|
DialogueBalloon = GD.Load<PackedScene>("res://src/ui/dialogue/DialogueBalloon.tscn");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ public partial class Game : Node3D, IGame
|
|||||||
{
|
{
|
||||||
GameRepo.Pause();
|
GameRepo.Pause();
|
||||||
DialogueManager.GetCurrentScene = (() => this);
|
DialogueManager.GetCurrentScene = (() => this);
|
||||||
DialogueManager.ShowDialogueBalloonScene(DialogueController.DialogueBalloon, DialogueController.DialogueResource, "floor_exit");
|
var dialogueResource = GD.Load<Resource>("res://src/ui/dialogue/FloorExit.dialogue");
|
||||||
|
DialogueManager.ShowDialogueBalloonScene(DialogueController.DialogueBalloon, dialogueResource, "floor_exit");
|
||||||
DialogueManager.DialogueEnded += (Resource resource) => { GameRepo.Resume(); };
|
DialogueManager.DialogueEnded += (Resource resource) => { GameRepo.Resume(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=18 format=3 uid="uid://33ek675mfb5n"]
|
[gd_scene load_steps=16 format=3 uid="uid://33ek675mfb5n"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/game/Game.cs" id="1_ytcii"]
|
[ext_resource type="Script" path="res://src/game/Game.cs" id="1_ytcii"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cfecvvav8kkp6" path="res://src/player/Player.tscn" id="3_kk6ly"]
|
[ext_resource type="PackedScene" uid="uid://cfecvvav8kkp6" path="res://src/player/Player.tscn" id="3_kk6ly"]
|
||||||
@@ -10,8 +10,6 @@
|
|||||||
[ext_resource type="PackedScene" path="res://src/map/dungeon/floors/Floor3.tscn" id="8_87yk1"]
|
[ext_resource type="PackedScene" path="res://src/map/dungeon/floors/Floor3.tscn" id="8_87yk1"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bjqgl5u05ia04" path="res://src/map/Teleport.tscn" id="9_nwu7r"]
|
[ext_resource type="PackedScene" uid="uid://bjqgl5u05ia04" path="res://src/map/Teleport.tscn" id="9_nwu7r"]
|
||||||
[ext_resource type="Script" path="res://src/game/DialogueController.cs" id="10_58pbt"]
|
[ext_resource type="Script" path="res://src/game/DialogueController.cs" id="10_58pbt"]
|
||||||
[ext_resource type="Resource" uid="uid://6bhfbvi6jbms" path="res://src/ui/dialogue/FloorExit.dialogue" id="11_4ysvf"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://73jm5qjy52vq" path="res://src/ui/dialogue/Balloon.tscn" id="11_ofwv2"]
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_fke5g"]
|
[sub_resource type="Environment" id="Environment_fke5g"]
|
||||||
|
|
||||||
@@ -131,5 +129,3 @@ disable_mode = 2
|
|||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
process_mode = 3
|
process_mode = 3
|
||||||
script = ExtResource("10_58pbt")
|
script = ExtResource("10_58pbt")
|
||||||
DialogueBalloon = ExtResource("11_ofwv2")
|
|
||||||
DialogueResource = ExtResource("11_4ysvf")
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[gd_scene load_steps=49 format=3 uid="uid://dvnc26rebk6o0"]
|
[gd_scene load_steps=49 format=3 uid="uid://dvnc26rebk6o0"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/map/dungeon/floors/Overworld.cs" id="1_5hmt3"]
|
[ext_resource type="Script" path="res://src/map/dungeon/floors/Overworld.cs" id="1_5hmt3"]
|
||||||
[ext_resource type="PackedScene" uid="uid://d4l4qutp8x40c" path="res://src/npc/goddess/Goddess.tscn" id="3_4sm8u"]
|
[ext_resource type="PackedScene" uid="uid://d4l4qutp8x40c" path="res://src/npc/rat/NPC.tscn" id="3_4sm8u"]
|
||||||
[ext_resource type="Material" uid="uid://cv70me80rxpem" path="res://src/map/overworld/Textures/water.tres" id="4_qojho"]
|
[ext_resource type="Material" uid="uid://cv70me80rxpem" path="res://src/map/overworld/Textures/water.tres" id="4_qojho"]
|
||||||
[ext_resource type="PackedScene" path="res://src/dialog/Dialog.tscn" id="4_thkm7"]
|
[ext_resource type="PackedScene" path="res://src/dialog/Dialog.tscn" id="4_thkm7"]
|
||||||
[ext_resource type="Material" uid="uid://c3wrhqfpx8th1" path="res://src/map/overworld/Textures/ruins.tres" id="5_6uoht"]
|
[ext_resource type="Material" uid="uid://c3wrhqfpx8th1" path="res://src/map/overworld/Textures/ruins.tres" id="5_6uoht"]
|
||||||
|
|||||||
41
src/npc/Npc.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using Chickensoft.AutoInject;
|
||||||
|
using Chickensoft.Introspection;
|
||||||
|
using DialogueManagerRuntime;
|
||||||
|
using GameJamDungeon;
|
||||||
|
using Godot;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
[Meta(typeof(IAutoNode))]
|
||||||
|
public partial class Npc : Node3D
|
||||||
|
{
|
||||||
|
public override void _Notification(int what) => this.Notify(what);
|
||||||
|
|
||||||
|
[Node] public Area3D DialogueZone { get; set; } = default!;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Godot.Collections.Array<Resource> DialogueOptions { get; set; } = default!;
|
||||||
|
|
||||||
|
private bool _isInDialogueZone = false;
|
||||||
|
|
||||||
|
public void OnReady()
|
||||||
|
{
|
||||||
|
DialogueZone.BodyEntered += DialogueZone_BodyEntered;
|
||||||
|
DialogueZone.BodyExited += DialogueZone_BodyExited;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DialogueZone_BodyExited(Node3D body)
|
||||||
|
{
|
||||||
|
_isInDialogueZone = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DialogueZone_BodyEntered(Node3D body)
|
||||||
|
{
|
||||||
|
_isInDialogueZone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _UnhandledInput(InputEvent @event)
|
||||||
|
{
|
||||||
|
if (Input.IsActionJustPressed(GameInputs.Throw) && _isInDialogueZone)
|
||||||
|
DialogueManager.ShowDialogueBalloonScene(DialogueController.DialogueBalloon, DialogueOptions.First(), "introduction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -1,35 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://cnbdf5rnmss0c"
|
|
||||||
path.s3tc="res://.godot/imported/GameJam_DevilCapricorn_WalkBehind.png-d474259823f7e07d28e67fbeafea4ee9.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://src/npc/goddess/GameJam_DevilCapricorn_WalkBehind.png"
|
|
||||||
dest_files=["res://.godot/imported/GameJam_DevilCapricorn_WalkBehind.png-d474259823f7e07d28e67fbeafea4ee9.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
compress/high_quality=false
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_compression=1
|
|
||||||
compress/normal_map=0
|
|
||||||
compress/channel_pack=0
|
|
||||||
mipmaps/generate=true
|
|
||||||
mipmaps/limit=-1
|
|
||||||
roughness/mode=0
|
|
||||||
roughness/src_normal=""
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/normal_map_invert_y=false
|
|
||||||
process/hdr_as_srgb=false
|
|
||||||
process/hdr_clamp_exposure=false
|
|
||||||
process/size_limit=0
|
|
||||||
detect_3d/compress_to=0
|
|
||||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -1,35 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://dg22b8xckfhfx"
|
|
||||||
path.s3tc="res://.godot/imported/GameJam_DevilCapricorn_WalkForward.png-234fa02af8dbdd9edff550fcb77a7464.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://src/npc/goddess/GameJam_DevilCapricorn_WalkForward.png"
|
|
||||||
dest_files=["res://.godot/imported/GameJam_DevilCapricorn_WalkForward.png-234fa02af8dbdd9edff550fcb77a7464.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
compress/high_quality=false
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_compression=1
|
|
||||||
compress/normal_map=0
|
|
||||||
compress/channel_pack=0
|
|
||||||
mipmaps/generate=true
|
|
||||||
mipmaps/limit=-1
|
|
||||||
roughness/mode=0
|
|
||||||
roughness/src_normal=""
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/normal_map_invert_y=false
|
|
||||||
process/hdr_as_srgb=false
|
|
||||||
process/hdr_clamp_exposure=false
|
|
||||||
process/size_limit=0
|
|
||||||
detect_3d/compress_to=0
|
|
||||||
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -1,35 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://b7aj0ii438hho"
|
|
||||||
path.s3tc="res://.godot/imported/GameJam_DevilCapricorn_WalkSide.png-771c2b0d0af534bbb03d6b7aadea21c5.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://src/npc/goddess/GameJam_DevilCapricorn_WalkSide.png"
|
|
||||||
dest_files=["res://.godot/imported/GameJam_DevilCapricorn_WalkSide.png-771c2b0d0af534bbb03d6b7aadea21c5.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
compress/high_quality=false
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_compression=1
|
|
||||||
compress/normal_map=0
|
|
||||||
compress/channel_pack=0
|
|
||||||
mipmaps/generate=true
|
|
||||||
mipmaps/limit=-1
|
|
||||||
roughness/mode=0
|
|
||||||
roughness/src_normal=""
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/normal_map_invert_y=false
|
|
||||||
process/hdr_as_srgb=false
|
|
||||||
process/hdr_clamp_exposure=false
|
|
||||||
process/size_limit=0
|
|
||||||
detect_3d/compress_to=0
|
|
||||||
|
Before Width: | Height: | Size: 7.3 KiB |
@@ -1,35 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://xu8t0sly6ju7"
|
|
||||||
path.s3tc="res://.godot/imported/GameJam_DevilCapricorn_WalkSideLeft.png-01b9979d4d466cf12540b33bef3b5d16.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://src/npc/goddess/GameJam_DevilCapricorn_WalkSideLeft.png"
|
|
||||||
dest_files=["res://.godot/imported/GameJam_DevilCapricorn_WalkSideLeft.png-01b9979d4d466cf12540b33bef3b5d16.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
compress/high_quality=false
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_compression=1
|
|
||||||
compress/normal_map=0
|
|
||||||
compress/channel_pack=0
|
|
||||||
mipmaps/generate=true
|
|
||||||
mipmaps/limit=-1
|
|
||||||
roughness/mode=0
|
|
||||||
roughness/src_normal=""
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/normal_map_invert_y=false
|
|
||||||
process/hdr_as_srgb=false
|
|
||||||
process/hdr_clamp_exposure=false
|
|
||||||
process/size_limit=0
|
|
||||||
detect_3d/compress_to=0
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using Chickensoft.AutoInject;
|
|
||||||
using Chickensoft.Introspection;
|
|
||||||
using GameJamDungeon;
|
|
||||||
using Godot;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
[Meta(typeof(IAutoNode))]
|
|
||||||
public partial class Goddess : Node3D
|
|
||||||
{
|
|
||||||
public override void _Notification(int what) => this.Notify(what);
|
|
||||||
|
|
||||||
[Dependency]
|
|
||||||
public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
|
||||||
|
|
||||||
[Export]
|
|
||||||
public Godot.Collections.Array<Texture2D> Sprites { get; set; } = default!;
|
|
||||||
|
|
||||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
|
||||||
|
|
||||||
public void OnReady()
|
|
||||||
{
|
|
||||||
SetPhysicsProcess(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
|
||||||
{
|
|
||||||
var cameraPosition = new Vector2(GameRepo.PlayerGlobalPosition.Value.X, GameRepo.PlayerGlobalPosition.Value.Z).Normalized();
|
|
||||||
var facing = Vector2.Up;
|
|
||||||
var angle = facing.AngleTo(cameraPosition);
|
|
||||||
|
|
||||||
var cameraAngle = (int)Mathf.Floor((angle + Mathf.Pi / 8) / (Mathf.Pi / 4));
|
|
||||||
cameraAngle = (cameraAngle + 4) % 4;
|
|
||||||
|
|
||||||
Sprite.Texture = Sprites[cameraAngle];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://wqh1m4j0n64m"]
|
|
||||||
|
|
||||||
[ext_resource type="Shader" path="res://src/npc/goddess/SpriteMelt.gdshader" id="1_k3mvs"]
|
|
||||||
|
|
||||||
[resource]
|
|
||||||
shader = ExtResource("1_k3mvs")
|
|
||||||
shader_parameter/progress = 0.0
|
|
||||||
shader_parameter/meltiness = 1.0
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
[gd_scene load_steps=7 format=3 uid="uid://d4l4qutp8x40c"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/npc/goddess/Goddess.cs" id="1_4cyto"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://bhiyrdo2jk1qg" path="res://src/npc/goddess/goddess.png" id="1_uay1m"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://cnbdf5rnmss0c" path="res://src/npc/goddess/GameJam_DevilCapricorn_WalkBehind.png" id="2_d6er1"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://dg22b8xckfhfx" path="res://src/npc/goddess/GameJam_DevilCapricorn_WalkForward.png" id="2_twumu"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://xu8t0sly6ju7" path="res://src/npc/goddess/GameJam_DevilCapricorn_WalkSideLeft.png" id="3_tds5k"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://b7aj0ii438hho" path="res://src/npc/goddess/GameJam_DevilCapricorn_WalkSide.png" id="4_6kg8t"]
|
|
||||||
|
|
||||||
[node name="Goddess" type="Node3D"]
|
|
||||||
script = ExtResource("1_4cyto")
|
|
||||||
Sprites = Array[Texture2D]([ExtResource("2_d6er1"), ExtResource("3_tds5k"), ExtResource("2_twumu"), ExtResource("4_6kg8t")])
|
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite3D" parent="."]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
transform = Transform3D(1.25, 0, 0, 0, 1.25, 0, 0, 0, 1.25, 0, 0, 0)
|
|
||||||
gi_mode = 0
|
|
||||||
billboard = 2
|
|
||||||
texture_filter = 0
|
|
||||||
texture = ExtResource("1_uay1m")
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
shader_type spatial;
|
|
||||||
|
|
||||||
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,unshaded;
|
|
||||||
|
|
||||||
uniform vec4 albedo : source_color = vec4(1.0,1.0,1.0,1.0);
|
|
||||||
|
|
||||||
uniform sampler2D sprite_sheet : source_color;
|
|
||||||
|
|
||||||
/// the count of v_frames, used for the directions
|
|
||||||
uniform int directions_count = 1;
|
|
||||||
/// the count of h_frames, used for the animations
|
|
||||||
uniform int frames_count = 1;
|
|
||||||
/// the current h_frame
|
|
||||||
uniform int frame = 1;
|
|
||||||
/// the angle around vertical axis; the resulting direction looks to (cos y_angle, 0, -sin y_angle)
|
|
||||||
uniform float y_angle = 0.0;
|
|
||||||
|
|
||||||
/// this parameter below specifies which angle is the first frame pointed to.
|
|
||||||
/// example: if your character has the first frame turned toward north, the starting angle should be pi/2, if it looks to east it can be let to 0.0
|
|
||||||
uniform float starting_angle = 0.0;
|
|
||||||
|
|
||||||
/// this option specify if the direction changes along the vertical axis (default, false) or use the horizontal one instead (true)
|
|
||||||
uniform bool directions_on_horizontal_axis = false;
|
|
||||||
/// if you have drawn the sprite sheet so as to make the object rotate clockwise instead of counter-clockwise, set this parameter below true
|
|
||||||
uniform bool clockwise = false;
|
|
||||||
|
|
||||||
void vertex() {
|
|
||||||
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0],INV_VIEW_MATRIX[1],INV_VIEW_MATRIX[2],MODEL_MATRIX[3]);
|
|
||||||
}
|
|
||||||
void fragment() {
|
|
||||||
//euler angle around the vertical axis
|
|
||||||
float vert_axis_angle = atan(-VIEW_MATRIX[0][2]/VIEW_MATRIX[2][2]) + (VIEW_MATRIX[0][0] < 0.0?PI:0.0);
|
|
||||||
//difference
|
|
||||||
vert_axis_angle += y_angle - starting_angle;
|
|
||||||
//pinning
|
|
||||||
vert_axis_angle += PI / float(directions_count);
|
|
||||||
float direction = floor(vert_axis_angle * float(directions_count) / TAU);
|
|
||||||
if (clockwise) direction = 1.0 - direction;
|
|
||||||
float uv_y = direction / float(directions_count);
|
|
||||||
//texture UV
|
|
||||||
vec2 texture_uv = directions_on_horizontal_axis?
|
|
||||||
vec2(
|
|
||||||
(UV.x / float(directions_count)) + uv_y,
|
|
||||||
(UV.y + float(frame))/float(frames_count)
|
|
||||||
):
|
|
||||||
vec2(
|
|
||||||
(UV.x + float(frame))/float(frames_count),
|
|
||||||
(UV.y / float(directions_count)) + uv_y
|
|
||||||
);
|
|
||||||
vec4 albedo_tex = texture(sprite_sheet,texture_uv);
|
|
||||||
//albedo
|
|
||||||
ALBEDO = albedo.rgb * albedo_tex.rgb;
|
|
||||||
ALPHA = albedo.a * albedo_tex.a;
|
|
||||||
}
|
|
||||||
/************************ FOR GODOT 3 ***************************
|
|
||||||
|
|
||||||
shader_type spatial;
|
|
||||||
|
|
||||||
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,unshaded;
|
|
||||||
|
|
||||||
uniform vec4 albedo: hint_color = vec4(1.0,1.0,1.0,1.0);
|
|
||||||
|
|
||||||
uniform sampler2D sprite_sheet : hint_albedo;
|
|
||||||
|
|
||||||
/// the count of v_frames, used for the directions
|
|
||||||
uniform int directions_count = 1;
|
|
||||||
/// the count of h_frames, used for the animations
|
|
||||||
uniform int frames_count = 1;
|
|
||||||
/// the current h_frame
|
|
||||||
uniform int frame = 1;
|
|
||||||
/// the angle around vertical axis; the resulting direction looks to (cos y_angle, 0, -sin y_angle)
|
|
||||||
uniform float y_angle = 0.0;
|
|
||||||
|
|
||||||
/// this parameter below specifies which angle is the first frame pointed to.
|
|
||||||
/// example: if your character has the first frame turned toward north, the starting angle should be pi/2,
|
|
||||||
///if it looks to east it can be let to 0.0
|
|
||||||
uniform float starting_angle = 0.0;
|
|
||||||
|
|
||||||
/// this option specify if the direction changes along the vertical axis (default, false) or use the horizontal one instead (true)
|
|
||||||
uniform bool directions_on_horizontal_axis = false;
|
|
||||||
/// if you have drawn the sprite sheet so as to make the object rotate clockwise instead of counter-clockwise, set this parameter below true
|
|
||||||
uniform bool clockwise = false;
|
|
||||||
|
|
||||||
void vertex() {
|
|
||||||
MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fragment() {
|
|
||||||
//euler angle around the vertical axis
|
|
||||||
float vert_axis_angle = atan(CAMERA_MATRIX[0][2]/CAMERA_MATRIX[0][0]) + (CAMERA_MATRIX[0][0] < 0.0?3.141593:0.0);
|
|
||||||
//difference
|
|
||||||
vert_axis_angle += y_angle - starting_angle;
|
|
||||||
//pinning
|
|
||||||
vert_axis_angle += 3.141593 / float(directions_count);
|
|
||||||
float direction = floor(vert_axis_angle * float(directions_count) / 6.283185);
|
|
||||||
if (clockwise) direction = 1.0 - direction;
|
|
||||||
float uv_y = direction / float(directions_count);
|
|
||||||
//texture UV
|
|
||||||
vec2 texture_uv = directions_on_horizontal_axis?
|
|
||||||
vec2(
|
|
||||||
(UV.x / float(directions_count)) + uv_y,
|
|
||||||
(UV.y + float(frame))/float(frames_count)
|
|
||||||
):
|
|
||||||
vec2(
|
|
||||||
(UV.x + float(frame))/float(frames_count),
|
|
||||||
(UV.y / float(directions_count)) + uv_y
|
|
||||||
);
|
|
||||||
vec4 albedo_tex = texture(sprite_sheet,texture_uv);
|
|
||||||
//albedo
|
|
||||||
ALBEDO = albedo.rgb * albedo_tex.rgb;
|
|
||||||
ALPHA = albedo.a * albedo_tex.a;
|
|
||||||
}
|
|
||||||
|
|
||||||
****************************************************************/
|
|
||||||
|
Before Width: | Height: | Size: 4.8 KiB |
BIN
src/npc/maiden/PUELLA.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bhiyrdo2jk1qg"
|
uid="uid://c414kvmj6wav6"
|
||||||
path.s3tc="res://.godot/imported/goddess.png-acb5c411edb71ef5e959e417175ba39f.s3tc.ctex"
|
path.s3tc="res://.godot/imported/PUELLA.png-b84e4cf70035cd95eb206a5a08c4ab61.s3tc.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc"],
|
"imported_formats": ["s3tc_bptc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
@@ -11,8 +11,8 @@ metadata={
|
|||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://src/npc/goddess/goddess.png"
|
source_file="res://src/npc/maiden/PUELLA.png"
|
||||||
dest_files=["res://.godot/imported/goddess.png-acb5c411edb71ef5e959e417175ba39f.s3tc.ctex"]
|
dest_files=["res://.godot/imported/PUELLA.png-b84e4cf70035cd95eb206a5a08c4ab61.s3tc.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
14
src/npc/maiden/maiden.tscn
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://d26qwequeef2i"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://c414kvmj6wav6" path="res://src/npc/maiden/PUELLA.png" id="1_mlyk6"]
|
||||||
|
|
||||||
|
[node name="NPC" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
|
||||||
|
gi_mode = 0
|
||||||
|
pixel_size = 0.005
|
||||||
|
billboard = 2
|
||||||
|
texture_filter = 0
|
||||||
|
texture = ExtResource("1_mlyk6")
|
||||||
30
src/npc/rat/NPC.tscn
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://d4l4qutp8x40c"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://t7fbfplu2js7" path="res://src/npc/rat/ROYAL_RAT_PRINCEP.png" id="1_0r0wh"]
|
||||||
|
[ext_resource type="Script" path="res://src/npc/Npc.cs" id="1_cpdf2"]
|
||||||
|
[ext_resource type="Resource" uid="uid://cf7ycgdiihyh" path="res://src/npc/rat/ratdialogue.dialogue" id="2_uo38w"]
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_wfhgc"]
|
||||||
|
radius = 1.5
|
||||||
|
|
||||||
|
[node name="NPC" type="Node3D"]
|
||||||
|
script = ExtResource("1_cpdf2")
|
||||||
|
DialogueOptions = Array[Resource]([ExtResource("2_uo38w")])
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
|
||||||
|
gi_mode = 0
|
||||||
|
pixel_size = 0.005
|
||||||
|
billboard = 2
|
||||||
|
texture_filter = 0
|
||||||
|
texture = ExtResource("1_0r0wh")
|
||||||
|
|
||||||
|
[node name="DialogueZone" type="Area3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
collision_layer = 2
|
||||||
|
collision_mask = 2
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="DialogueZone"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.00131226, 0, -0.00723076)
|
||||||
|
shape = SubResource("CylinderShape3D_wfhgc")
|
||||||
BIN
src/npc/rat/ROYAL_RAT_PRINCEP.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://dmh2hm1iy6i1x"
|
uid="uid://t7fbfplu2js7"
|
||||||
path.s3tc="res://.godot/imported/testsprite.png-70f2b03f832bdb736932806bcf06b54e.s3tc.ctex"
|
path.s3tc="res://.godot/imported/ROYAL_RAT_PRINCEP.png-e4eeb4a5bba938a6dc238bcabe55375f.s3tc.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc"],
|
"imported_formats": ["s3tc_bptc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
@@ -11,8 +11,8 @@ metadata={
|
|||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://src/npc/testsprite.png"
|
source_file="res://src/npc/rat/ROYAL_RAT_PRINCEP.png"
|
||||||
dest_files=["res://.godot/imported/testsprite.png-70f2b03f832bdb736932806bcf06b54e.s3tc.ctex"]
|
dest_files=["res://.godot/imported/ROYAL_RAT_PRINCEP.png-e4eeb4a5bba938a6dc238bcabe55375f.s3tc.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
10
src/npc/rat/ratdialogue.dialogue
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
~ introduction
|
||||||
|
|
||||||
|
Royal Rat Princep, Tekohcyo: I do not know thee but I perceive thine sorrows vividly,
|
||||||
|
for I am embraced by their brethren.
|
||||||
|
Royal Rat Princep, Tekohcyo: Though it be in mind only, I am traitor to mine country and family.
|
||||||
|
But a plague on the mind is a plague on one's world is it not?
|
||||||
|
Royal Rat Princep, Tekohcyo: Alas, the tower has rejected me, so here I reside.
|
||||||
|
Unable to return home, but unable to climb it.
|
||||||
|
|
||||||
|
=> END
|
||||||
15
src/npc/rat/ratdialogue.dialogue.import
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="dialogue_manager_compiler_12"
|
||||||
|
type="Resource"
|
||||||
|
uid="uid://cf7ycgdiihyh"
|
||||||
|
path="res://.godot/imported/ratdialogue.dialogue-44b9fe9da69f8da8a6bfdeb5429ef4a3.tres"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://src/npc/rat/ratdialogue.dialogue"
|
||||||
|
dest_files=["res://.godot/imported/ratdialogue.dialogue-44b9fe9da69f8da8a6bfdeb5429ef4a3.tres"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
defaults=true
|
||||||
|
Before Width: | Height: | Size: 33 KiB |
@@ -92,6 +92,8 @@ Panel/styles/panel = SubResource("StyleBoxFlat_uy0d5")
|
|||||||
[node name="DialogueBalloon" type="CanvasLayer"]
|
[node name="DialogueBalloon" type="CanvasLayer"]
|
||||||
layer = 100
|
layer = 100
|
||||||
script = ExtResource("1_okfmu")
|
script = ExtResource("1_okfmu")
|
||||||
|
NextAction = "Throw"
|
||||||
|
SkipAction = "Throw"
|
||||||
|
|
||||||
[node name="Balloon" type="Control" parent="."]
|
[node name="Balloon" type="Control" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|||||||