improved typewriter and cleaned dialogue code

This commit is contained in:
2023-02-12 10:44:23 +01:00
parent 953210b65f
commit 47c6d08f53
2 changed files with 138 additions and 130 deletions

View File

@@ -11,9 +11,7 @@ script = ExtResource("1_xtj1q")
metadata/_edit_use_anchors_ = true metadata/_edit_use_anchors_ = true
[node name="typewriter_timer" type="Timer" parent="."] [node name="typewriter_timer" type="Timer" parent="."]
wait_time = 0.04 wait_time = 0.05
one_shot = true
metadata/charsAtOnce = 60
[node name="box" type="ColorRect" parent="."] [node name="box" type="ColorRect" parent="."]
anchors_preset = -1 anchors_preset = -1
@@ -102,3 +100,5 @@ theme_override_constants/margin_top = 30
theme_override_constants/margin_right = 60 theme_override_constants/margin_right = 60
theme_override_constants/margin_bottom = 30 theme_override_constants/margin_bottom = 30
metadata/_edit_lock_ = true metadata/_edit_lock_ = true
[connection signal="timeout" from="typewriter_timer" to="." method="OnTypewriterTimerTimeout"]

View File

@@ -1,146 +1,154 @@
using Godot; using Godot;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
public partial class dialog_bubble : CanvasLayer public partial class dialog_bubble : CanvasLayer
{ {
public Variant parsedDlg; public Variant parsedDlg;
public Variant dlgLines; public Variant dlgLines;
public int dlgPointer = 0; public int dlgPointer = 0;
public RichTextLabel richText; public RichTextLabel richText;
public string name; public Timer typewriterTimer;
public Area2D triggerArea; public string name;
public Area2D triggerArea;
/*TODO: /*TODO:
- Dont repeat the same randomized dialogue after you get asked do you need something "else" - Dont repeat the same randomized dialogue after you get asked do you need something "else"
- add tree support (example: "story" key) - add tree support (example: "story" key)
- ability to add dialogue begin answers on the fly (special ones are colored) - ability to add dialogue begin answers on the fly (special ones are colored)
they will be in a dictionary with event IDs or Dictionary keys it also needs an array wich ones are active*/ they will be in a dictionary with event IDs or Dictionary keys it also needs an array wich ones are active*/
public override void _Ready() public override void _Ready()
{ {
richText = GetNode<RichTextLabel>("box/rich_text_label"); richText = GetNode<RichTextLabel>("box/rich_text_label");
} typewriterTimer = GetNode<Timer>("typewriter_timer");
public void GetDialog(string file, string title, Area2D actor, string playerName, bool introducedVillager) }
{ public void GetDialog(string file, string title, Area2D actor, string playerName, bool introducedVillager)
triggerArea = actor; {
name = title; triggerArea = actor;
name = title;
parsedDlg = Json.ParseString(FileAccess.Open(file, FileAccess.ModeFlags.Read).GetAsText() parsedDlg = Json.ParseString(FileAccess.Open(file, FileAccess.ModeFlags.Read).GetAsText()
.Replace("{player}", "[color=cyan]" + playerName + "[/color]").Replace("{title}", "[color=purple]" + title + "[/color]")); .Replace("{player}", "[color=cyan]" + playerName + "[/color]").Replace("{title}", "[color=purple]" + title + "[/color]"));
if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() != "villager" || introducedVillager) if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() != "villager" || introducedVillager)
GetNode<Label>("box/name_label").Text = title; GetNode<Label>("box/name_label").Text = title;
if (GetParent().Name == "player") GetParent<player>().allowMovement = false; if (GetParent().Name == "player") GetParent<player>().allowMovement = false;
//Get first key //Get first key
if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() == "villager") if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() == "villager")
if (introducedVillager) if (introducedVillager)
GatherDialog("welcome"); GatherDialog("welcome");
else else
GatherDialog("intro"); GatherDialog("intro");
else if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() == "message") else if (parsedDlg.AsGodotDictionary()["dialogType"].AsString() == "message")
GatherDialog("message"); GatherDialog("message");
Visible = true; Visible = true;
} }
public void GatherDialog(string key) public void GatherDialog(string key)
{ {
dlgPointer = 0; dlgPointer = 0;
dlgLines = parsedDlg.AsGodotDictionary()[key].AsGodotArray(); dlgLines = parsedDlg.AsGodotDictionary()[key].AsGodotArray();
dlgLines = dlgLines.AsGodotArray()[GD.RandRange(0, dlgLines.AsGodotArray().Count - 1)]; dlgLines = dlgLines.AsGodotArray()[GD.RandRange(0, dlgLines.AsGodotArray().Count - 1)];
//TODO:copy a clean default array and remove already used indexes and copy from clean array when its empty //TODO:copy a clean default array and remove already used indexes and copy from clean array when its empty
} }
public void CloseDialog() public override void _Process(double delta)
{ {
Visible = false; DialogControlls();
dlgPointer = 0; AnswerBoxControlls();
richText.VisibleCharacters = -1; }
GetNode<Label>("box/name_label").Text = "???"; public void DialogControlls()
richText.Text = ""; {
if (GetParent().Name == "player") GetParent<player>().allowMovement = true; if (Input.IsActionJustPressed("ui_cancel") && Visible) richText.VisibleCharacters = richText.Text.Length;
}
public override void _Process(double delta)
{
if (Input.IsActionJustPressed("ui_cancel") && Visible) richText.VisibleCharacters = richText.Text.Length;
if (Input.IsActionJustPressed("ui_accept") && Visible && GetNode<PanelContainer>("box/panel_container").Visible == false if (Input.IsActionJustPressed("ui_accept") && Visible && GetNode<PanelContainer>("box/panel_container").Visible == false
&& richText.VisibleCharacters == -1 | Regex.Replace(richText.Text, @"\[[^]]+\]", "").Length <= richText.VisibleCharacters) && richText.VisibleCharacters == -1 | Regex.Replace(richText.Text, @"\[[^]]+\]", "").Length <= richText.VisibleCharacters)
{ {
if (dlgPointer < dlgLines.AsGodotArray().Count) if (dlgPointer < dlgLines.AsGodotArray().Count)
{ {
//read and write the dialogue //read and write the dialogue
if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.Float) if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.Float)
InDialogEvents((int)dlgLines.AsGodotArray()[dlgPointer]); InDialogEvents((int)dlgLines.AsGodotArray()[dlgPointer]);
else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.String && !dlgLines.AsGodotArray()[dlgPointer].AsString().StartsWith("<goto:>")) else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.String && !dlgLines.AsGodotArray()[dlgPointer].AsString().StartsWith("<goto:>"))
UpdateDialog(); UpdateDialog();
else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.String && dlgLines.AsGodotArray()[dlgPointer].AsString().StartsWith("<goto:>")) else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.String && dlgLines.AsGodotArray()[dlgPointer].AsString().StartsWith("<goto:>"))
{ {
GatherDialog(dlgLines.AsGodotArray()[dlgPointer].AsString().Replace("<goto:>", "")); GatherDialog(dlgLines.AsGodotArray()[dlgPointer].AsString().Replace("<goto:>", ""));
UpdateDialog(); UpdateDialog();
} }
else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.Dictionary) else if (dlgLines.AsGodotArray()[dlgPointer].VariantType == Variant.Type.Dictionary)
MakeAnswerBox(Json.ParseString(dlgLines.AsGodotArray()[dlgPointer].AsGodotDictionary().Keys.ToString()).AsStringArray()); MakeAnswerBox(Json.ParseString(dlgLines.AsGodotArray()[dlgPointer].AsGodotDictionary().Keys.ToString()).AsStringArray());
} }
dlgPointer++; dlgPointer++;
} }
//Typewrite effect if (dlgPointer > dlgLines.AsGodotArray().Count)
if (richText.VisibleCharacters < Regex.Replace(richText.Text, @"\[[^]]+\]", "").Length && GetNode<Timer>("typewriter_timer").IsStopped()) CloseDialog();
{ }
richText.VisibleCharacters++; public void UpdateDialog()
GetNode<Timer>("typewriter_timer").Start(); {
} richText.Text = dlgLines.AsGodotArray()[dlgPointer].ToString();
richText.VisibleCharacters = 0;
if (dlgPointer > dlgLines.AsGodotArray().Count) typewriterTimer.Start();
CloseDialog(); }
public void OnTypewriterTimerTimeout()
//AnswerBox answer "logic" {
if (GetNode<PanelContainer>("box/panel_container").Visible == true if (richText.VisibleCharacters < Regex.Replace(richText.Text, @"\[[^]]+\]", "").Length)
&& GetNode("box/panel_container/margin_container").GetChild(0).GetChild<Button>(0).ButtonGroup.GetPressedButton() != null) richText.VisibleCharacters++;
{ else typewriterTimer.Stop();
var answer = dlgLines.AsGodotArray()[dlgPointer - 1].AsGodotDictionary()[GetNode<Button>(GetNode("box/panel_container/margin_container") }
.GetChild(0).GetChild<Button>(0).ButtonGroup.GetPressedButton().GetPath()).Text]; public void MakeAnswerBox(string[] dialogOptions)
GetNode<PanelContainer>("box/panel_container").Visible = false; {
if (answer.VariantType == Variant.Type.String && answer.AsString().StartsWith("<goto:>")) var parent = GetNode("box/panel_container/margin_container");
{ if (parent.GetChildCount() == 1) parent.GetChild(0).Free();
GatherDialog(answer.AsString().Replace("<goto:>", "")); parent.AddChild(new VBoxContainer());
UpdateDialog(); parent = parent.GetChild(0);
} for (int i = 0; parent.GetChildCount() < dialogOptions.Length; i++)
dlgPointer++; {
} parent.AddChild(GD.Load<PackedScene>("res://scenes/gui/dlg_answer_button.tscn").Instantiate());
} if (dialogOptions[i].StartsWith("<!>")) parent.GetChild<Button>(i).Disabled = true;
public void UpdateDialog() parent.GetChild<Button>(i).Text = dialogOptions[i].Replace("<!>", "");
{ }
richText.Text = dlgLines.AsGodotArray()[dlgPointer].ToString(); GetNode<PanelContainer>("box/panel_container").Visible = true;
richText.VisibleCharacters = 0; parent.GetChild<Button>(0).GrabFocus();
GetNode<Timer>("typewriter_timer").Start(); }
} public void AnswerBoxControlls()
public void MakeAnswerBox(string[] dialogOptions) {
{ if (GetNode<PanelContainer>("box/panel_container").Visible == true
var parent = GetNode("box/panel_container/margin_container"); && GetNode("box/panel_container/margin_container").GetChild(0).GetChild<Button>(0).ButtonGroup.GetPressedButton() != null)
if (parent.GetChildCount() == 1) parent.GetChild(0).Free(); {
parent.AddChild(new VBoxContainer()); var answer = dlgLines.AsGodotArray()[dlgPointer - 1].AsGodotDictionary()[GetNode<Button>(GetNode("box/panel_container/margin_container")
parent = parent.GetChild(0); .GetChild(0).GetChild<Button>(0).ButtonGroup.GetPressedButton().GetPath()).Text];
for (int i = 0; parent.GetChildCount() < dialogOptions.Length; i++) GetNode<PanelContainer>("box/panel_container").Visible = false;
{ if (answer.VariantType == Variant.Type.String && answer.AsString().StartsWith("<goto:>"))
parent.AddChild(GD.Load<PackedScene>("res://scenes/gui/dlg_answer_button.tscn").Instantiate()); {
if (dialogOptions[i].StartsWith("<!>")) parent.GetChild<Button>(i).Disabled = true; GatherDialog(answer.AsString().Replace("<goto:>", ""));
parent.GetChild<Button>(i).Text = dialogOptions[i].Replace("<!>", ""); UpdateDialog();
} }
GetNode<PanelContainer>("box/panel_container").Visible = true; dlgPointer++;
parent.GetChild<Button>(0).GrabFocus(); }
} }
public void InDialogEvents(int eventID) //maybe replaceable with jsonrpc? public void InDialogEvents(int eventID) //maybe replaceable with jsonrpc?
{ {
switch (eventID) switch (eventID)
{ {
case 0: case 0:
GetNode<Label>("box/name_label").Text = name; GetNode<Label>("box/name_label").Text = name;
triggerArea.Set("introducedVillager", true); triggerArea.Set("introducedVillager", true);
GatherDialog("begindialog"); GatherDialog("begindialog");
UpdateDialog(); UpdateDialog();
break; break;
} }
} }
public void CloseDialog()
{
Visible = false;
dlgPointer = 0;
richText.VisibleCharacters = -1;
GetNode<Label>("box/name_label").Text = "???";
richText.Text = "";
if (GetParent().Name == "player") GetParent<player>().allowMovement = true;
}
} }