163 lines
5.6 KiB
C#
163 lines
5.6 KiB
C#
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;
|
||
|
||
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;
|
||
|
||
private InputManager inputManager;
|
||
|
||
private Queue<string> dialogueQueue = new Queue<string>();
|
||
private PlayerDialogueViewer playerDialogueViewer;
|
||
|
||
private IDialogue previousDialogue;
|
||
private IDialogue currentDialogueTarget;
|
||
public IDialogue CurrentDialogueTarget
|
||
{
|
||
get => currentDialogueTarget;
|
||
set
|
||
{
|
||
previousDialogue = currentDialogueTarget;
|
||
currentDialogueTarget = value;
|
||
if (previousDialogue != currentDialogueTarget)
|
||
{
|
||
if (currentDialogueTarget != null)
|
||
{
|
||
OnGazeEnterDialogue?.Invoke((currentDialogueTarget as MonoBehaviour)?.gameObject);
|
||
}
|
||
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.");
|
||
|
||
inputManager = InputManager.Instance;
|
||
var input = inputManager.Input;
|
||
input.Player.Read.performed += ctx =>
|
||
{
|
||
if (!isEnablePlayerDialogue) return;
|
||
if (CurrentDialogueTarget == null) return;
|
||
if (isReadingDialogue) return;
|
||
BeginDialogue();
|
||
};
|
||
input.Player.ShowNextDialogue.performed += ctx =>
|
||
{
|
||
if (!isEnablePlayerDialogue) return;
|
||
if (CurrentDialogueTarget == null) return;
|
||
if (!isReadingDialogue) return;
|
||
PassNextDialogue();
|
||
};
|
||
|
||
ControllerLocator.Instance.Register(this);
|
||
}
|
||
|
||
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);
|
||
inputManager.SetInputForLook(false);
|
||
inputManager.SetInputForMove(false);
|
||
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);
|
||
inputManager.SetInputForLook(true);
|
||
inputManager.SetInputForMove(true);
|
||
if (playerDialogueViewer != null)
|
||
{
|
||
playerDialogueViewer.ClosePanel();
|
||
}
|
||
// 可扩展:隐藏UI、恢复输入等
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
} |