Net.Like.Xue.Tokyo/Assets/Plugins/ParadoxNotion/NodeCanvas/Modules/DialogueTrees/DialogueGUI/DialogueUGUI.cs

295 lines
11 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.EventSystems;
namespace NodeCanvas.DialogueTrees.UI.Examples
{
public class DialogueUGUI : MonoBehaviour, IPointerClickHandler
{
[System.Serializable]
public class SubtitleDelays
{
public float characterDelay = 0.05f;
public float sentenceDelay = 0.5f;
public float commaDelay = 0.1f;
public float finalDelay = 1.2f;
}
//Options...
[Header("Input Options")]
public bool skipOnInput;
public bool waitForInput;
//Group...
[Header("Subtitles")]
public RectTransform subtitlesGroup;
public Text actorSpeech;
public Text actorName;
public Image actorPortrait;
public RectTransform waitInputIndicator;
public SubtitleDelays subtitleDelays = new SubtitleDelays();
public List<AudioClip> typingSounds;
private AudioSource playSource;
//Group...
[Header("Multiple Choice")]
public RectTransform optionsGroup;
public Button optionButton;
private Dictionary<Button, int> cachedButtons;
private Vector2 originalSubsPosition;
private bool isWaitingChoice;
private AudioSource _localSource;
private AudioSource localSource {
get { return _localSource != null ? _localSource : _localSource = gameObject.AddComponent<AudioSource>(); }
}
private bool anyKeyDown;
public void OnPointerClick(PointerEventData eventData) => anyKeyDown = true;
void LateUpdate() => anyKeyDown = false;
void Awake() { Subscribe(); Hide(); }
void OnEnable() { UnSubscribe(); Subscribe(); }
void OnDisable() { UnSubscribe(); }
void Subscribe() {
DialogueTree.OnDialogueStarted += OnDialogueStarted;
DialogueTree.OnDialoguePaused += OnDialoguePaused;
DialogueTree.OnDialogueFinished += OnDialogueFinished;
DialogueTree.OnSubtitlesRequest += OnSubtitlesRequest;
DialogueTree.OnMultipleChoiceRequest += OnMultipleChoiceRequest;
}
void UnSubscribe() {
DialogueTree.OnDialogueStarted -= OnDialogueStarted;
DialogueTree.OnDialoguePaused -= OnDialoguePaused;
DialogueTree.OnDialogueFinished -= OnDialogueFinished;
DialogueTree.OnSubtitlesRequest -= OnSubtitlesRequest;
DialogueTree.OnMultipleChoiceRequest -= OnMultipleChoiceRequest;
}
void Hide() {
subtitlesGroup.gameObject.SetActive(false);
optionsGroup.gameObject.SetActive(false);
optionButton.gameObject.SetActive(false);
waitInputIndicator.gameObject.SetActive(false);
originalSubsPosition = subtitlesGroup.transform.position;
}
void OnDialogueStarted(DialogueTree dlg) {
//nothing special...
}
void OnDialoguePaused(DialogueTree dlg) {
subtitlesGroup.gameObject.SetActive(false);
optionsGroup.gameObject.SetActive(false);
StopAllCoroutines();
if ( playSource != null ) playSource.Stop();
}
void OnDialogueFinished(DialogueTree dlg) {
subtitlesGroup.gameObject.SetActive(false);
optionsGroup.gameObject.SetActive(false);
if ( cachedButtons != null ) {
foreach ( var tempBtn in cachedButtons.Keys ) {
if ( tempBtn != null ) {
Destroy(tempBtn.gameObject);
}
}
cachedButtons = null;
}
StopAllCoroutines();
if ( playSource != null ) playSource.Stop();
}
///----------------------------------------------------------------------------------------------
void OnSubtitlesRequest(SubtitlesRequestInfo info) {
StartCoroutine(Internal_OnSubtitlesRequestInfo(info));
}
IEnumerator Internal_OnSubtitlesRequestInfo(SubtitlesRequestInfo info) {
var text = info.statement.text;
var audio = info.statement.audio;
var actor = info.actor;
subtitlesGroup.gameObject.SetActive(true);
subtitlesGroup.position = originalSubsPosition;
actorSpeech.text = "";
actorName.text = actor.name;
actorSpeech.color = actor.dialogueColor;
actorPortrait.gameObject.SetActive(actor.portraitSprite != null);
actorPortrait.sprite = actor.portraitSprite;
if ( audio != null ) {
var actorSource = actor.transform != null ? actor.transform.GetComponent<AudioSource>() : null;
playSource = actorSource != null ? actorSource : localSource;
playSource.clip = audio;
playSource.Play();
actorSpeech.text = text;
var timer = 0f;
while ( timer < audio.length ) {
if ( skipOnInput && anyKeyDown ) {
playSource.Stop();
break;
}
timer += Time.deltaTime;
yield return null;
}
}
if ( audio == null ) {
var tempText = "";
var inputDown = false;
if ( skipOnInput ) {
StartCoroutine(CheckInput(() => { inputDown = true; }));
}
for ( int i = 0; i < text.Length; i++ ) {
if ( skipOnInput && inputDown ) {
actorSpeech.text = text;
yield return null;
break;
}
if ( subtitlesGroup.gameObject.activeSelf == false ) {
yield break;
}
char c = text[i];
tempText += c;
yield return StartCoroutine(DelayPrint(subtitleDelays.characterDelay));
PlayTypeSound();
if ( c == '.' || c == '!' || c == '?' ) {
yield return StartCoroutine(DelayPrint(subtitleDelays.sentenceDelay));
PlayTypeSound();
}
if ( c == ',' ) {
yield return StartCoroutine(DelayPrint(subtitleDelays.commaDelay));
PlayTypeSound();
}
actorSpeech.text = tempText;
}
if ( !waitForInput ) {
yield return StartCoroutine(DelayPrint(subtitleDelays.finalDelay));
}
}
if ( waitForInput ) {
waitInputIndicator.gameObject.SetActive(true);
while ( !anyKeyDown ) {
yield return null;
}
waitInputIndicator.gameObject.SetActive(false);
}
yield return null;
subtitlesGroup.gameObject.SetActive(false);
info.Continue();
}
void PlayTypeSound() {
if ( typingSounds.Count > 0 ) {
var sound = typingSounds[Random.Range(0, typingSounds.Count)];
if ( sound != null ) {
localSource.PlayOneShot(sound, Random.Range(0.6f, 1f));
}
}
}
IEnumerator CheckInput(System.Action Do) {
while ( !anyKeyDown ) {
yield return null;
}
Do();
}
IEnumerator DelayPrint(float time) {
var timer = 0f;
while ( timer < time ) {
timer += Time.deltaTime;
yield return null;
}
}
///----------------------------------------------------------------------------------------------
void OnMultipleChoiceRequest(MultipleChoiceRequestInfo info) {
optionsGroup.gameObject.SetActive(true);
var buttonHeight = optionButton.GetComponent<RectTransform>().rect.height;
optionsGroup.sizeDelta = new Vector2(optionsGroup.sizeDelta.x, ( info.options.Values.Count * buttonHeight ) + 20);
cachedButtons = new Dictionary<Button, int>();
int i = 0;
foreach ( KeyValuePair<IStatement, int> pair in info.options ) {
var btn = (Button)Instantiate(optionButton);
btn.gameObject.SetActive(true);
btn.transform.SetParent(optionsGroup.transform, false);
btn.transform.localPosition = (Vector3)optionButton.transform.localPosition - new Vector3(0, buttonHeight * i, 0);
btn.GetComponentInChildren<Text>().text = pair.Key.text;
cachedButtons.Add(btn, pair.Value);
btn.onClick.AddListener(() => { Finalize(info, cachedButtons[btn]); });
i++;
}
if ( info.showLastStatement ) {
subtitlesGroup.gameObject.SetActive(true);
var newY = optionsGroup.position.y + optionsGroup.sizeDelta.y + 1;
subtitlesGroup.position = new Vector3(subtitlesGroup.position.x, newY, subtitlesGroup.position.z);
}
if ( info.availableTime > 0 ) {
StartCoroutine(CountDown(info));
}
}
IEnumerator CountDown(MultipleChoiceRequestInfo info) {
isWaitingChoice = true;
var timer = 0f;
while ( timer < info.availableTime ) {
if ( isWaitingChoice == false ) {
yield break;
}
timer += Time.deltaTime;
SetMassAlpha(optionsGroup, Mathf.Lerp(1, 0, timer / info.availableTime));
yield return null;
}
if ( isWaitingChoice ) {
Finalize(info, info.options.Values.Last());
}
}
void Finalize(MultipleChoiceRequestInfo info, int index) {
isWaitingChoice = false;
SetMassAlpha(optionsGroup, 1f);
optionsGroup.gameObject.SetActive(false);
subtitlesGroup.gameObject.SetActive(false);
foreach ( var tempBtn in cachedButtons.Keys ) {
Destroy(tempBtn.gameObject);
}
info.SelectOption(index);
}
void SetMassAlpha(RectTransform root, float alpha) {
foreach ( var graphic in root.GetComponentsInChildren<CanvasRenderer>() ) {
graphic.SetAlpha(alpha);
}
}
}
}