2025-10-23 15:46:17 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Core;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
using Script.Gameplay.Interface;
|
|
|
|
|
using Script.Gameplay.Input;
|
|
|
|
|
using UI;
|
2025-10-27 10:31:01 +08:00
|
|
|
using UnityEngine.InputSystem;
|
2025-10-23 15:46:17 +08:00
|
|
|
|
|
|
|
|
namespace Script.Gameplay.Player
|
|
|
|
|
{
|
|
|
|
|
public class PlayerDialogueController : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
[SerializeField] private bool isEnablePlayerDialogue = true; // 是否启用玩家对话功能
|
|
|
|
|
[SerializeField] private FirstPersonRaycaster firstPersonRaycaster; // 第一人称射线检测器
|
|
|
|
|
private bool isReadingDialogue = false;
|
|
|
|
|
public event Action OnPlayerBeginDialogue;
|
|
|
|
|
public event Action OnPlayerEndDialogue;
|
|
|
|
|
public event Action<GameObject> OnGazeEnterDialogue;
|
|
|
|
|
public event Action<GameObject> OnGazeExitDialogue;
|
2025-10-27 21:41:25 +08:00
|
|
|
|
2025-10-25 10:46:17 +08:00
|
|
|
private InputManager inputManager;
|
2025-10-27 21:41:25 +08:00
|
|
|
|
2025-10-23 15:46:17 +08:00
|
|
|
private Queue<string> dialogueQueue = new Queue<string>();
|
|
|
|
|
private PlayerDialogueViewer playerDialogueViewer;
|
|
|
|
|
|
|
|
|
|
private IDialogue previousDialogue;
|
|
|
|
|
private IDialogue currentDialogueTarget;
|
2025-10-27 21:41:25 +08:00
|
|
|
|
2025-10-23 15:46:17 +08:00
|
|
|
public IDialogue CurrentDialogueTarget
|
|
|
|
|
{
|
|
|
|
|
get => currentDialogueTarget;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
previousDialogue = currentDialogueTarget;
|
|
|
|
|
currentDialogueTarget = value;
|
|
|
|
|
if (previousDialogue != currentDialogueTarget)
|
|
|
|
|
{
|
|
|
|
|
if (currentDialogueTarget != null)
|
|
|
|
|
{
|
|
|
|
|
OnGazeEnterDialogue?.Invoke((currentDialogueTarget as MonoBehaviour)?.gameObject);
|
|
|
|
|
}
|
2025-10-27 21:41:25 +08:00
|
|
|
|
2025-10-23 15:46:17 +08:00
|
|
|
if (previousDialogue != null)
|
|
|
|
|
{
|
|
|
|
|
OnGazeExitDialogue?.Invoke((previousDialogue as MonoBehaviour)?.gameObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
|
|
|
|
if (firstPersonRaycaster == null)
|
|
|
|
|
firstPersonRaycaster = GetComponent<FirstPersonRaycaster>() ??
|
|
|
|
|
GetComponentInChildren<FirstPersonRaycaster>();
|
|
|
|
|
if (firstPersonRaycaster == null)
|
|
|
|
|
firstPersonRaycaster = FindObjectOfType<FirstPersonRaycaster>();
|
|
|
|
|
if (firstPersonRaycaster == null)
|
|
|
|
|
Debug.LogWarning("FirstPersonRaycaster not found! Please assign or add it to the player.");
|
|
|
|
|
|
2025-10-25 10:46:17 +08:00
|
|
|
inputManager = InputManager.Instance;
|
|
|
|
|
var input = inputManager.Input;
|
2025-10-27 10:31:01 +08:00
|
|
|
input.Player.Read.performed += OnReadOnperformed;
|
|
|
|
|
input.Player.ShowNextDialogue.performed += OnShowNextDialogueOnperformed;
|
2025-10-27 21:41:25 +08:00
|
|
|
input.Player.Escape.performed += OnEscapeOnperformed;
|
2025-10-23 15:46:17 +08:00
|
|
|
|
|
|
|
|
ControllerLocator.Instance.Register(this);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
private void OnEscapeOnperformed(InputAction.CallbackContext ctx)
|
|
|
|
|
{
|
|
|
|
|
EndDialogue();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-27 10:31:01 +08:00
|
|
|
private void OnShowNextDialogueOnperformed(InputAction.CallbackContext ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!isEnablePlayerDialogue) return;
|
|
|
|
|
if (CurrentDialogueTarget == null) return;
|
|
|
|
|
if (!isReadingDialogue) return;
|
|
|
|
|
PassNextDialogue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnReadOnperformed(InputAction.CallbackContext ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!isEnablePlayerDialogue) return;
|
|
|
|
|
if (CurrentDialogueTarget == null) return;
|
|
|
|
|
if (isReadingDialogue) return;
|
|
|
|
|
BeginDialogue();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 15:46:17 +08:00
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
DetectDialogue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DetectDialogue()
|
|
|
|
|
{
|
|
|
|
|
if (!isEnablePlayerDialogue || firstPersonRaycaster == null) return;
|
|
|
|
|
GameObject lookAtObj = firstPersonRaycaster.CurrentLookAtObject;
|
|
|
|
|
IDialogue hitDialogue = lookAtObj != null ? lookAtObj.GetComponent<IDialogue>() : null;
|
|
|
|
|
CurrentDialogueTarget = hitDialogue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BeginDialogue()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentDialogueTarget != null)
|
|
|
|
|
{
|
|
|
|
|
isReadingDialogue = true;
|
|
|
|
|
OnPlayerBeginDialogue?.Invoke();
|
|
|
|
|
CurrentDialogueTarget.OnBeginDialogue?.Invoke(true);
|
|
|
|
|
dialogueQueue = SplitDialogue(CurrentDialogueTarget.DialogueContent);
|
|
|
|
|
PassNextDialogue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PassNextDialogue()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentDialogueTarget != null)
|
|
|
|
|
{
|
|
|
|
|
if (dialogueQueue.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
EndDialogue();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string nextDialogue = dialogueQueue.Dequeue();
|
|
|
|
|
if (playerDialogueViewer != null)
|
|
|
|
|
{
|
|
|
|
|
playerDialogueViewer.ReceiveDialogue(nextDialogue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EndDialogue()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentDialogueTarget != null)
|
|
|
|
|
{
|
|
|
|
|
isReadingDialogue = false;
|
|
|
|
|
OnPlayerEndDialogue?.Invoke();
|
|
|
|
|
CurrentDialogueTarget.OnEndDialogue?.Invoke(true);
|
2025-10-27 21:41:25 +08:00
|
|
|
UIManager.Instance.CloseUI<PlayerDialogueViewer>();
|
2025-10-23 15:46:17 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Queue<string> SplitDialogue(string content)
|
|
|
|
|
{
|
|
|
|
|
// 按换行分段
|
|
|
|
|
return new(content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RegisterDialogueViewer(PlayerDialogueViewer viewer)
|
|
|
|
|
{
|
|
|
|
|
playerDialogueViewer = viewer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetPlayerDialogueEnabled(bool isEnabled)
|
|
|
|
|
{
|
|
|
|
|
isEnablePlayerDialogue = isEnabled;
|
|
|
|
|
if (!isEnabled)
|
|
|
|
|
{
|
|
|
|
|
CurrentDialogueTarget = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-27 10:31:01 +08:00
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
ControllerLocator.Instance.Unregister<PlayerDialogueController>(this);
|
|
|
|
|
|
|
|
|
|
if (inputManager != null)
|
|
|
|
|
{
|
|
|
|
|
var input = inputManager.Input;
|
|
|
|
|
input.Player.Read.performed -= OnReadOnperformed;
|
|
|
|
|
input.Player.ShowNextDialogue.performed -= OnShowNextDialogueOnperformed;
|
2025-10-27 21:41:25 +08:00
|
|
|
input.Player.Escape.performed -= OnEscapeOnperformed;
|
2025-10-27 10:31:01 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-23 15:46:17 +08:00
|
|
|
}
|
|
|
|
|
}
|