다이얼로그 작업중
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The interface for an executor of a visual novel node.
|
||||
/// <br/><br/>
|
||||
/// An executor defines the runtime behaviour for the data stored in a <see cref="VisualNovelRuntimeNode"/>. Each
|
||||
/// <see cref="VisualNovelRuntimeNode"/> will have its own implementation of an executor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If we want to share runtime behaviour between nodes, a single class can implement multiple node executors and have
|
||||
/// functions for shared behaviour. This is useful for nodes that have similar behaviour but different data.
|
||||
/// We can see an example of this in the <see cref="SetDialogueExecutor"/> class, which implements
|
||||
/// <see cref="IVisualNovelNodeExecutor{TNode}"/> for both <see cref="SetDialogueRuntimeNode"/> and <see cref="SetDialogueRuntimeNodeWithPreviousActor"/>
|
||||
/// </remarks>
|
||||
/// <typeparam name="TNode">The type of <see cref="VisualNovelRuntimeNode"/> to execute</typeparam>
|
||||
public interface IVisualNovelNodeExecutor<in TNode> where TNode : VisualNovelRuntimeNode
|
||||
{
|
||||
Task ExecuteAsync(TNode node, VisualNovelDirector ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcf95c3fd8c7449eb6d6aa5368f3f575
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab22459b58eb45bfa0373ce6130bfcfb
|
||||
timeCreated: 1743647612
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// Executor for the <see cref="SetBackgroundRuntimeNode"/> node.
|
||||
/// </summary>
|
||||
public class SetBackgroundExecutor : IVisualNovelNodeExecutor<SetBackgroundRuntimeNode>
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the background image of the visual novel director context to the specified sprite.
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(SetBackgroundRuntimeNode runtimeNode, VisualNovelDirector ctx)
|
||||
{
|
||||
ctx.BackgroundImage.sprite = runtimeNode.BackgroundSprite;
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea05d640e7a44fb1a25b0543cc9f9e47
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The serializable data representing a runtime node in the visual novel graph that sets the background image.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SetBackgroundRuntimeNode : VisualNovelRuntimeNode
|
||||
{
|
||||
public Sprite BackgroundSprite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5611765a9ea43fb8f1348a7e1dd8f55
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b31022c513b476d8e79090f8556e1b6
|
||||
timeCreated: 1743647633
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// Executor for the <see cref="SetDialogueRuntimeNode"/> and <see cref="SetDialogueRuntimeNodeWithPreviousActor"/> nodes.
|
||||
/// </summary>
|
||||
public class SetDialogueExecutor :
|
||||
IVisualNovelNodeExecutor<SetDialogueRuntimeNode>,
|
||||
IVisualNovelNodeExecutor<SetDialogueRuntimeNodeWithPreviousActor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the <see cref="SetDialogueRuntimeNode"/> node, setting the dialogue text and actor sprite settings.
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(SetDialogueRuntimeNode runtimeNode, VisualNovelDirector ctx)
|
||||
{
|
||||
if (string.IsNullOrEmpty(runtimeNode.DialogueText))
|
||||
{
|
||||
ctx.DialoguePanel.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DialoguePanel.SetActive(true);
|
||||
ctx.ActorNameText.text = runtimeNode.ActorName;
|
||||
|
||||
foreach (var location in ctx.ActorLocationList)
|
||||
location.enabled = false;
|
||||
|
||||
if (runtimeNode.ActorSprite != null)
|
||||
{
|
||||
var img = ctx.ActorLocationList[runtimeNode.LocationIndex];
|
||||
img.enabled = true;
|
||||
img.sprite = runtimeNode.ActorSprite;
|
||||
}
|
||||
|
||||
await TypeTextWithSkipAsync(runtimeNode.DialogueText, ctx);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the <see cref="SetDialogueRuntimeNodeWithPreviousActor"/> node, and keeps all previous actor settings
|
||||
/// while changing the dialogue text.
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(SetDialogueRuntimeNodeWithPreviousActor runtimeNode, VisualNovelDirector ctx)
|
||||
{
|
||||
if (string.IsNullOrEmpty(runtimeNode.DialogueText))
|
||||
{
|
||||
ctx.DialoguePanel.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DialoguePanel.SetActive(true);
|
||||
|
||||
await TypeTextWithSkipAsync(runtimeNode.DialogueText, ctx);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a typewriter effect on the given <see cref="TextMeshProUGUI"/> label.
|
||||
/// </summary>
|
||||
/// <param name="dialogueText">The text to set</param>
|
||||
/// <param name="ctx">The <see cref="VisualNovelDirector"/> context to get settings and input from</param>
|
||||
/// <remarks>
|
||||
/// Input is used to skip the typewriter effect if it's in-progress.
|
||||
/// </remarks>
|
||||
static async Task TypeTextWithSkipAsync(string dialogueText, VisualNovelDirector ctx)
|
||||
{
|
||||
var label = ctx.DialogueText;
|
||||
var delayPerCharSeconds = ctx.GlobalTextDelayPerCharacter;
|
||||
var inputProvider = ctx.InputProvider;
|
||||
|
||||
label.text = "";
|
||||
var builder = new StringBuilder();
|
||||
|
||||
var insideRichTag = false;
|
||||
|
||||
// Start listening for skip input
|
||||
var skipInputDetected = inputProvider.InputDetected();
|
||||
|
||||
foreach (var c in dialogueText)
|
||||
{
|
||||
// Handle rich text tags (e.g., <b>, </i>)
|
||||
if (c == '<')
|
||||
insideRichTag = true;
|
||||
|
||||
builder.Append(c);
|
||||
|
||||
if (c == '>')
|
||||
insideRichTag = false;
|
||||
|
||||
// Skip delay if rich text
|
||||
if (insideRichTag || char.IsWhiteSpace(c)) continue;
|
||||
|
||||
label.text = builder.ToString();
|
||||
|
||||
var timer = 0f;
|
||||
while (timer < delayPerCharSeconds)
|
||||
{
|
||||
if (skipInputDetected.IsCompleted)
|
||||
{
|
||||
label.text = dialogueText;
|
||||
return;
|
||||
}
|
||||
timer += Time.deltaTime;
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
label.text = dialogueText;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5306b40600a4b1dba95ac4dbff24dc3
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The serializable data representing a runtime node in the visual novel graph that sets the dialogue text and actor information.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SetDialogueRuntimeNode : VisualNovelRuntimeNode
|
||||
{
|
||||
public string ActorName;
|
||||
public Sprite ActorSprite;
|
||||
public int LocationIndex;
|
||||
public string DialogueText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b73106ed058476487451106f4cd06cd
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The serializable data that represents a runtime node in the visual novel graph that sets the dialogue text only.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SetDialogueRuntimeNodeWithPreviousActor : VisualNovelRuntimeNode
|
||||
{
|
||||
public string DialogueText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f76932495d484264a27c87163f5ee1a6
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e04bdd30e6acbb244ac32c9196b537d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// Executor for the <see cref="TwoOptionRuntimeNode"/> node.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This executor displays a question and two dialogue options to the player,
|
||||
/// waits for their selection, and records which option was chosen.
|
||||
/// </remarks>
|
||||
public class TwoOptionExecutor : IVisualNovelNodeExecutor<TwoOptionRuntimeNode>
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the <see cref="TwoOptionRuntimeNode"/> node, displaying the dialogue options
|
||||
/// and waiting for the player to select one.
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(TwoOptionRuntimeNode runtimeNode, VisualNovelDirector ctx)
|
||||
{
|
||||
// Display the options
|
||||
ctx.OptionPanel.SetActive(true);
|
||||
ctx.Option1Text.text = runtimeNode.Option1Text;
|
||||
ctx.Option2Text.text = runtimeNode.Option2Text;
|
||||
|
||||
// Wait for player to select an option
|
||||
var optionSelectionDetected = ctx.InputProvider.OptionSelectionDetected();
|
||||
while (!optionSelectionDetected.IsCompleted)
|
||||
{
|
||||
await Task.Yield();
|
||||
}
|
||||
runtimeNode.SelectedOption = optionSelectionDetected.Result;
|
||||
ctx.OptionPanel.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67810d7679f665c4b869ceefa9f4736d
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The serializable data representing a runtime node in the visual novel graph
|
||||
/// that presents two dialogue options to the player.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class TwoOptionRuntimeNode : VisualNovelRuntimeNode
|
||||
{
|
||||
public string Option1Text;
|
||||
public string Option2Text;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the node to execute if Option 1 is selected.
|
||||
/// -1 indicates no continuation for this branch.
|
||||
/// </summary>
|
||||
public int Option1NextNodeIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the node to execute if Option 2 is selected.
|
||||
/// -1 indicates no continuation for this branch.
|
||||
/// </summary>
|
||||
public int Option2NextNodeIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Records which option the player selected (0 for option 1, 1 for option 2).
|
||||
/// Set during runtime execution.
|
||||
/// </summary>
|
||||
public int SelectedOption;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afce09435a9f2b049bc1fa2034268cca
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for the runtime data for all visual novel nodes.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class VisualNovelRuntimeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// The index of the next node to execute in the runtime graph.
|
||||
/// -1 indicates no next node (end of execution).
|
||||
/// For branching nodes, this represents the default path.
|
||||
/// </summary>
|
||||
public int NextNodeIndex = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0bf19e6af304282be4060c37ab3aec7
|
||||
timeCreated: 1743618864
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 162d7b6e660341b9b835e484ea6717c3
|
||||
timeCreated: 1743647811
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The executor for the <see cref="WaitForInputRuntimeNode"/> node.
|
||||
/// </summary>
|
||||
public class WaitForInputExecutor : IVisualNovelNodeExecutor<WaitForInputRuntimeNode>
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously waits for user input to be detected before proceeding with the execution of the visual novel graph.
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(WaitForInputRuntimeNode _, VisualNovelDirector ctx)
|
||||
{
|
||||
await ctx.InputProvider.InputDetected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cfe275f272e4272aad2ae65d590f4fc
|
||||
timeCreated: 1743647517
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.GraphToolkit.Samples.VisualNovelDirector
|
||||
{
|
||||
/// <summary>
|
||||
/// The serializable data that represents a runtime node in the visual novel graph that waits for player input.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class WaitForInputRuntimeNode : VisualNovelRuntimeNode
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16cc3826ec21426989b58379033c6688
|
||||
timeCreated: 1743647517
|
||||
Reference in New Issue
Block a user