139 lines
3.6 KiB
C#
139 lines
3.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using BITKit.Entities.Player;
|
|
using Cysharp.Threading.Tasks;
|
|
using JetBrains.Annotations;
|
|
using NodeCanvas.DialogueTrees;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
namespace BITFALL.UX
|
|
{
|
|
/// <summary>
|
|
/// 对话组件,基于NodeCanvas.DialogueTrees
|
|
/// </summary>
|
|
public class UXDialogue : MonoBehaviour
|
|
{
|
|
[SerializeReference,SubclassSelector] private IPlayerService playerService;
|
|
[SerializeField] private UXBuilder dialogueBuilder;
|
|
[SerializeField] private InputActionReference[] choosesActions;
|
|
|
|
private readonly ValidHandle allowBackground = new();
|
|
private readonly List<int> _dialogueIds = new();
|
|
|
|
[Inject] private InputActionGroup _inputActionGroup;
|
|
|
|
[CanBeNull] private MultipleChoiceRequestInfo _multipleChoiceRequestInfo;
|
|
|
|
private void Start()
|
|
{
|
|
allowBackground.AddListener(dialogueBuilder.VisualElement.SetActive);
|
|
allowBackground.Invoke();
|
|
|
|
playerService.OnPlayerInitialized += OnPlayerInitialized;
|
|
playerService.OnPlayerDisposed += OnPlayerDisposed;
|
|
|
|
DialogueTree.OnSubtitlesRequest += OnSubtitlesRequest;
|
|
DialogueTree.OnMultipleChoiceRequest += OnMultipleChoiceRequest;
|
|
|
|
destroyCancellationToken.Register(() =>
|
|
{
|
|
playerService.OnPlayerInitialized -= OnPlayerInitialized;
|
|
DialogueTree.OnSubtitlesRequest -= OnSubtitlesRequest;
|
|
DialogueTree.OnMultipleChoiceRequest -= OnMultipleChoiceRequest;
|
|
playerService.OnPlayerDisposed -= OnPlayerDisposed;
|
|
});
|
|
|
|
|
|
|
|
}
|
|
private void OnPlayerDisposed(Entity obj)
|
|
{
|
|
foreach (var action in choosesActions)
|
|
{
|
|
UXOnScreenPrompts.Release(action.GetKeyMap());
|
|
}
|
|
}
|
|
|
|
private void OnPlayerInitialized(Entity obj)
|
|
{
|
|
obj.Inject(this);
|
|
|
|
for (var i = 0; i < choosesActions.Length; i++)
|
|
{
|
|
var action = choosesActions[i];
|
|
var index = i;
|
|
|
|
_inputActionGroup.RegisterCallback(action, OnAction);
|
|
|
|
continue;
|
|
|
|
void OnAction(InputAction.CallbackContext context)
|
|
{
|
|
if (_multipleChoiceRequestInfo is null) return;
|
|
_multipleChoiceRequestInfo.SelectOption?.Invoke(index);
|
|
_multipleChoiceRequestInfo = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnMultipleChoiceRequest(MultipleChoiceRequestInfo obj)
|
|
{
|
|
_multipleChoiceRequestInfo = obj;
|
|
foreach (var (statement,index) in obj.options)
|
|
{
|
|
UXOnScreenPrompts.Get(choosesActions[index].GetKeyMap(),statement.text);
|
|
obj.SelectOption+=i =>
|
|
{
|
|
UXOnScreenPrompts.Release(choosesActions[index].GetKeyMap());
|
|
};
|
|
}
|
|
}
|
|
|
|
private async void OnSubtitlesRequest(SubtitlesRequestInfo obj)
|
|
{
|
|
|
|
var id = obj.GetHashCode();
|
|
|
|
_dialogueIds.Add(id);
|
|
|
|
dialogueBuilder.VisualElement.SetActive(true);
|
|
var container = dialogueBuilder.BuildAsContainer();
|
|
container.contextLabel.text = $"{obj.actor.name}:{obj.statement}";
|
|
try
|
|
{
|
|
if (double.TryParse( obj.statement.meta,out var duration))
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(duration), destroyCancellationToken);
|
|
}
|
|
else
|
|
{
|
|
await Task.Delay(5000, destroyCancellationToken);
|
|
}
|
|
obj.Continue.Invoke();
|
|
await Task.Delay(5000, destroyCancellationToken);
|
|
container.visualElement.AddToClassList("dispose");
|
|
await Task.Delay(1000, destroyCancellationToken);
|
|
container.visualElement.RemoveFromHierarchy();
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
obj.Continue.Invoke();
|
|
}
|
|
|
|
_dialogueIds.Remove(id);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
allowBackground.SetElements(this, _dialogueIds.Count is not 0);
|
|
}
|
|
}
|
|
|
|
}
|