Complete reorga

This commit is contained in:
2026-03-09 17:55:23 +01:00
parent d9326e48cc
commit 10faf74405
703 changed files with 13040 additions and 1533 deletions
@@ -0,0 +1,255 @@
using UnityEngine;
using System;
using Unheimlich.Features.Player;
using Unheimlich.Features.Dialogue;
using Unheimlich.Features.Dialogue.UI;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Core.Utils;
namespace Unheimlich.Features.Dialogue
{
/// <summary>
/// Manages gaze-based focus detection for dialogue choices using raycasts.
/// </summary>
public class DialogueFocusSystem
{
private readonly DialogueManager _manager;
private readonly Camera _mainCamera;
private readonly CameraEffects _cameraEffects;
private ChoiceFocusHandler _currentFocusedHandler;
private float _focusTimer = 0f;
private float _retentionTimer = 0f;
private float _raycastTimer = 0f;
private bool _isFocusLocked = false;
private readonly LayerMask _choiceLayer;
private readonly float _focusRange;
private readonly float _focusTime;
private readonly float _raycastInterval;
private readonly float _recoveryDuration;
private readonly float _focusRetentionTime;
private readonly float _fallbackShakeIntensity;
public event Action<DialogueChoiceData> OnChoiceMade;
public DialogueFocusSystem(
DialogueManager manager,
Camera mainCamera,
CameraEffects cameraEffects,
LayerMask choiceLayer,
float focusRange,
float focusTime,
float raycastInterval,
float recoveryDuration,
float focusRetentionTime,
float fallbackShakeIntensity)
{
_manager = manager;
_mainCamera = mainCamera;
_cameraEffects = cameraEffects;
_choiceLayer = choiceLayer;
_focusRange = focusRange;
_focusTime = focusTime;
_raycastInterval = raycastInterval;
_recoveryDuration = recoveryDuration;
_focusRetentionTime = focusRetentionTime;
_fallbackShakeIntensity = fallbackShakeIntensity;
}
/// <summary>
/// Updates the focus detection system. Should be called every frame during active dialogue.
/// Performs raycasts at configured intervals to detect choice focus.
/// </summary>
public void Update()
{
if (!_manager.IsInDialogue || !_manager.CurrentDialogueUI.AreChoicesVisible())
return;
_raycastTimer += Time.deltaTime;
if (_raycastTimer >= _raycastInterval)
{
CheckForChoiceFocus();
_raycastTimer = 0f;
}
}
/// <summary>
/// Performs raycast from camera center to detect focused dialogue choices.
/// Manages focus state transitions, retention timers, visual feedback, and choice selection.
/// Implements stabilization to prevent rapid focus switching between choices.
/// </summary>
private void CheckForChoiceFocus()
{
if (_isFocusLocked)
{
if (_retentionTimer > 0f)
_retentionTimer -= Time.deltaTime;
else
_isFocusLocked = false;
return;
}
if (_mainCamera == null)
return;
ChoiceFocusHandler hitHandler = null;
if (RaycastHelper.RaycastFromCameraCenter(_mainCamera, _focusRange, _choiceLayer, out RaycastHit hit))
{
hitHandler = hit.collider.GetComponent<ChoiceFocusHandler>();
if (_cameraEffects != null && hitHandler != null)
_cameraEffects.ApplyAimAssist(hit.collider.bounds.center);
}
if (hitHandler != _currentFocusedHandler)
{
_retentionTimer -= Time.deltaTime;
if (hitHandler != null && _retentionTimer <= 0f)
{
if (_currentFocusedHandler != null)
{
_currentFocusedHandler.ResetFeedback(_recoveryDuration);
ResetAllUnfocusEffects();
}
_currentFocusedHandler = hitHandler;
_focusTimer = 0f;
_retentionTimer = _focusRetentionTime;
if (_cameraEffects != null)
_cameraEffects.LockAim(true);
ApplyUnfocusEffectToOthers(hitHandler);
DialogueAnimationSettings settings = _manager.CurrentAnimationSettings;
bool shouldRotate = settings == null || settings.EnableRotation;
if (shouldRotate && _manager.CurrentDialogueUI != null)
{
float focusSpeed = settings != null ? settings.FocusRotationSpeed : 60f;
_manager.CurrentDialogueUI.RotationAnimation(focusSpeed);
}
}
}
else if (hitHandler != null)
{
_retentionTimer = _focusRetentionTime;
}
bool isFocusActive = _currentFocusedHandler != null && (_retentionTimer > 0f);
if (isFocusActive)
{
_focusTimer += Time.deltaTime;
float progress = _focusTimer / _focusTime;
_currentFocusedHandler.ApplyFocusFeedback(progress);
DialogueAnimationSettings currentSettings = _manager.CurrentAnimationSettings;
bool shouldShake = currentSettings == null || currentSettings.EnableCameraShakeOnFocus;
if (shouldShake && _cameraEffects != null)
{
float shakeIntensity = currentSettings != null ? currentSettings.CameraShakeIntensity : _fallbackShakeIntensity;
float shakeSmoothness = currentSettings != null ? currentSettings.CameraShakeSmoothness : 10f;
_cameraEffects.ShakeCamera(progress / shakeIntensity, shakeSmoothness);
}
if (_focusTimer >= _focusTime)
{
ChoiceFocusHandler selectedHandler = _currentFocusedHandler;
if (selectedHandler.DialogueData != null)
{
OnChoiceMade?.Invoke(selectedHandler.DialogueData);
DialogueNode nextNode = selectedHandler.GetNextNode();
_manager.GoToNextNode(nextNode);
}
DialogueAnimationSettings settings = _manager.CurrentAnimationSettings;
bool shouldRotate = settings == null || settings.EnableRotation;
if (shouldRotate && _manager.CurrentDialogueUI != null)
{
float normalSpeed = settings != null ? settings.NormalRotationSpeed : 36f;
_manager.CurrentDialogueUI.RotationAnimation(normalSpeed);
}
ResetAnimationTimers();
ResetAllUnfocusEffects();
selectedHandler.ResetFeedback(_recoveryDuration);
if (_cameraEffects != null)
_cameraEffects.LockAim(false);
}
}
else if (_currentFocusedHandler != null && _retentionTimer <= 0f)
{
_currentFocusedHandler.ResetFeedback(_recoveryDuration);
ResetAllUnfocusEffects();
DialogueAnimationSettings settings = _manager.CurrentAnimationSettings;
bool shouldRotate = settings == null || settings.EnableRotation;
if (shouldRotate && _manager.CurrentDialogueUI != null)
{
float normalSpeed = settings != null ? settings.NormalRotationSpeed : 36f;
_manager.CurrentDialogueUI.RotationAnimation(normalSpeed);
}
ResetAnimationTimers();
if (_cameraEffects != null)
_cameraEffects.LockAim(false);
}
}
private void ApplyUnfocusEffectToOthers(ChoiceFocusHandler focusedHandler)
{
if (_manager.CurrentDialogueUI == null || _manager.CurrentDialogueUI.ChoiceContainer == null)
return;
DialogueAnimationSettings settings = _manager.CurrentAnimationSettings;
float shakeSlowdown = settings != null ? settings.UnfocusedShakeSpeedMultiplier : 0.3f;
foreach (Transform child in _manager.CurrentDialogueUI.ChoiceContainer.transform)
{
ChoiceFocusHandler handler = child.GetComponent<ChoiceFocusHandler>();
if (handler != null && handler != focusedHandler)
{
handler.SetShakeSpeedMultiplier(shakeSlowdown);
handler.ApplySketchFade();
}
}
}
private void ResetAllUnfocusEffects()
{
if (_manager.CurrentDialogueUI == null || _manager.CurrentDialogueUI.ChoiceContainer == null)
return;
foreach (Transform child in _manager.CurrentDialogueUI.ChoiceContainer.transform)
{
ChoiceFocusHandler handler = child.GetComponent<ChoiceFocusHandler>();
if (handler != null)
{
handler.SetShakeSpeedMultiplier(1f);
handler.ResetSketchFade();
}
}
}
private void ResetAnimationTimers()
{
_currentFocusedHandler = null;
_focusTimer = 0f;
_retentionTimer = 0f;
}
public void UnlockFocus()
{
_isFocusLocked = false;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 22514e9ce0f2e6c4b9f5f718ae139b09
@@ -0,0 +1,250 @@
using UnityEngine;
using System;
using Unheimlich.Core;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Features.DetectiveBoard.Data;
using Unheimlich.Features.DetectiveBoard;
using Unheimlich.Features.Player;
using Unheimlich.Features.Dialogue.UI;
using Unheimlich.Features.Dialogue;
using System.Collections.Generic;
using InputManager = Unheimlich.Core.Input.InputManager;
namespace Unheimlich.Features.Dialogue
{
public class DialogueManager : Singleton<DialogueManager>
{
[Header("State")]
public bool IsInDialogue = false;
[Header("Focus Settings")]
[SerializeField] private LayerMask _choiceLayer;
[SerializeField] private float _focusRange = 5f;
[SerializeField] private float _focusTime = 1.5f;
[SerializeField] private float _raycastInterval = 0.05f;
[Header("Focus Stabilization")]
[SerializeField] private float _recoveryDuration = 0.5f;
[SerializeField] private float _focusRetentionTime = 0.1f;
[Tooltip("Fallback camera shake intensity if not set in DialogueAnimationSettings")]
[SerializeField] private float _fallbackShakeIntensity = 30f;
public DialogueAnimationSettings CurrentAnimationSettings => _currentAnimationSettings;
public bool IsDialogueActive => IsInDialogue;
public Transform CurrentChoiceAnchor => _currentChoiceAnchor;
public DialogueUI CurrentDialogueUI => _activeDialogueUI;
public object CurrentOwner { get; private set; }
public DialogueConversation CurrentConversation => _currentConversation;
public DialogueNode CurrentNode => _currentNode;
public event Action<DialogueChoiceData> OnChoiceMade;
public event Action<object> OnDialogueCompleted;
private DialogueFocusSystem _focusSystem;
private Camera _mainCamera;
private DialogueAnimationSettings _currentAnimationSettings;
private DialogueUI _activeDialogueUI;
private Transform _currentChoiceAnchor;
private DialogueConversation _currentConversation;
private DialogueNode _currentNode;
private float _autoCloseTimer = 0f;
private bool _isWaitingForAutoClose = false;
protected override void OnAwake()
{
}
private void Start()
{
_mainCamera = Camera.main;
_focusSystem = new DialogueFocusSystem(
this,
_mainCamera,
PlayerController.Instance?.CameraEffects,
_choiceLayer,
_focusRange,
_focusTime,
_raycastInterval,
_recoveryDuration,
_focusRetentionTime,
_fallbackShakeIntensity
);
_focusSystem.OnChoiceMade += (choice) => OnChoiceMade?.Invoke(choice);
}
private void Update()
{
if (!IsInDialogue)
return;
if (!_activeDialogueUI.AreChoicesVisible())
{
if (_isWaitingForAutoClose && _currentNode != null && _currentNode.AutoCloseDelay > 0f)
{
_autoCloseTimer += Time.deltaTime;
if (_autoCloseTimer >= _currentNode.AutoCloseDelay)
{
_activeDialogueUI.FadeOutAndHide(() =>
{
OnDialogueCompleted?.Invoke(CurrentOwner);
CleanupDialogue();
});
IsInDialogue = false;
_isWaitingForAutoClose = false;
if (DialogueBlurEffectURP.Instance != null)
{
DialogueBlurEffectURP.Instance.HideBlur();
}
return;
}
}
var interactAction = InputManager.GetInteractAction();
if (interactAction != null && interactAction.WasPressedThisFrame())
{
EndDialogue();
}
}
else
{
_focusSystem?.Update();
}
}
public void StartConversation(DialogueConversation conversation, Transform choiceAnchor = null, DialogueAnimationSettings animationSettings = null, DialogueUI customDialogueUI = null, object owner = null)
{
if (conversation == null)
{
Debug.LogError("Cannot start conversation: conversation is null");
return;
}
DialogueNode firstNode = conversation.GetFirstNode();
if (firstNode == null)
{
Debug.LogError($"Cannot start conversation {conversation.name}: no dialogue nodes found");
return;
}
_currentConversation = conversation;
_currentNode = firstNode;
_currentChoiceAnchor = choiceAnchor;
_currentAnimationSettings = animationSettings;
_activeDialogueUI = customDialogueUI;
CurrentOwner = owner;
ShowCurrentNode();
}
private void ShowCurrentNode()
{
if (_currentNode == null || _currentConversation == null)
return;
UnlockFocus();
IsInDialogue = true;
if (_currentNode.ClueToUnlock != null)
{
if (DetectiveBoardManager.Instance != null)
{
DetectiveBoardManager.Instance.UnlockClue(_currentNode.ClueToUnlock);
}
else
{
Debug.LogWarning($"[DialogueManager] Cannot unlock clue '{_currentNode.ClueToUnlock.ClueID}': DetectiveBoardManager not found");
}
}
if(_currentChoiceAnchor == null)
{
Debug.LogWarning("No choice anchor found!");
return;
}
Transform anchor = _currentChoiceAnchor;
string speakerName = _currentConversation.GetLocalizedSpeakerName();
string dialogueText = _currentNode.GetLocalizedDialogueText();
DialogueDisplayMode displayMode = _currentConversation.DisplayMode;
_activeDialogueUI.ShowDialogueBox(speakerName, dialogueText, displayMode);
_autoCloseTimer = 0f;
_isWaitingForAutoClose = false;
if (_currentNode.Choices != null && _currentNode.Choices.Count > 0)
{
List<DialogueChoiceData> validChoices = new List<DialogueChoiceData>();
foreach (var choiceData in _currentNode.Choices)
{
if (choiceData != null && choiceData.IsValid())
validChoices.Add(choiceData);
}
if (validChoices.Count > 0)
_activeDialogueUI.ShowChoices(validChoices, anchor, _currentAnimationSettings);
}
else
_isWaitingForAutoClose = true;
}
public void GoToNextNode(DialogueNode nextNode)
{
if (nextNode == null)
{
OnDialogueCompleted?.Invoke(CurrentOwner);
EndDialogue();
return;
}
UnlockFocus();
if (_activeDialogueUI != null)
_activeDialogueUI.HideChoices();
_currentNode = nextNode;
ShowCurrentNode();
}
public void EndDialogue()
{
IsInDialogue = false;
if (_activeDialogueUI != null)
_activeDialogueUI.HideDialogueBox();
if (DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.HideBlur();
CleanupDialogue();
}
private void CleanupDialogue()
{
_currentChoiceAnchor = null;
_currentAnimationSettings = null;
_activeDialogueUI = null;
CurrentOwner = null;
_currentConversation = null;
_currentNode = null;
_autoCloseTimer = 0f;
_isWaitingForAutoClose = false;
}
public void UnlockFocus()
{
_focusSystem?.UnlockFocus();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bd83d1e8e266cff41b8a5c2928f1f80f
@@ -0,0 +1,84 @@
using UnityEngine;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Features.Dialogue;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Dialogue
{
public class DialogueStateHandler
{
public bool IsCompleted { get; private set; }
public bool HasPausedDialogue => _pausedConversation != null && _pausedNode != null;
private DialogueConversation _pausedConversation;
private DialogueNode _pausedNode;
private Transform _pausedChoiceAnchor;
private DialogueAnimationSettings _pausedAnimationSettings;
private DialogueUI _pausedDialogueUI;
private object _owner;
public DialogueStateHandler(object owner)
{
_owner = owner;
}
public void PauseDialogue()
{
if (DialogueManager.Instance == null || !DialogueManager.Instance.IsDialogueActive)
return;
DialogueManager dialogueManager = DialogueManager.Instance;
_pausedConversation = dialogueManager.CurrentConversation;
_pausedNode = dialogueManager.CurrentNode;
_pausedChoiceAnchor = dialogueManager.CurrentChoiceAnchor;
_pausedAnimationSettings = dialogueManager.CurrentAnimationSettings;
_pausedDialogueUI = dialogueManager.CurrentDialogueUI;
DialogueManager.Instance.EndDialogue();
}
public void ResumeDialogue()
{
if (!HasPausedDialogue || DialogueManager.Instance == null)
return;
DialogueManager.Instance.StartConversation(
_pausedConversation,
_pausedChoiceAnchor,
_pausedAnimationSettings,
_pausedDialogueUI,
_owner
);
ClearPausedDialogue();
}
public void MarkAsCompleted()
{
IsCompleted = true;
ClearPausedDialogue();
}
public void AllowRetrigger()
{
IsCompleted = false;
}
public void Reset()
{
IsCompleted = false;
ClearPausedDialogue();
}
private void ClearPausedDialogue()
{
_pausedConversation = null;
_pausedNode = null;
_pausedChoiceAnchor = null;
_pausedAnimationSettings = null;
_pausedDialogueUI = null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b328dc63103543940898cfa2dbd4ec36
@@ -0,0 +1,185 @@
using UnityEngine;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Features.Dialogue;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Dialogue
{
/// <summary>
/// Trigger zone that starts a dialogue sequence when player enters.
/// Supports pause/resume on exit/enter and optional one-time triggering.
/// </summary>
[RequireComponent(typeof(Collider))]
public class DialogueTriggerZone : MonoBehaviour
{
[Header("Dialogue Reference")]
[Tooltip("DialogueConversation to use for this trigger zone")]
[SerializeField] private DialogueConversation _conversation;
[Header("Trigger Settings")]
[Tooltip("Can the dialogue be retriggered after completion")]
[SerializeField] private bool _isRetriggerable = false;
[SerializeField] private bool _requirePlayerTag = true;
[SerializeField] private string _playerTag = "Player";
[Header("Distance Check")]
[Tooltip("Pause dialogue if player exits the trigger zone")]
[SerializeField] private bool _pauseOnExit = true;
[Header("Floating Word Anchor")]
[SerializeField] private Transform _floatingWordAnchor;
[Header("Animation Settings")]
[SerializeField] private DialogueAnimationSettings _animationSettings;
[Header("UI Reference")]
[Tooltip("Local DialogueUI for this trigger zone. Uses DialogueManager's UI if null")]
[SerializeField] private DialogueUI _localDialogueUI;
[Header("Blur Effect")]
[Tooltip("Enable blur effect when dialogue starts")]
[SerializeField] private bool _enableBlurEffect = true;
private bool _hasTriggered = false;
private Collider _triggerCollider;
private DialogueStateHandler _dialogueState;
private void Awake()
{
_triggerCollider = GetComponent<Collider>();
_dialogueState = new DialogueStateHandler(this);
if (!_triggerCollider.isTrigger)
{
Debug.LogWarning($"{gameObject.name}: Collider should be marked as Trigger!", this);
_triggerCollider.isTrigger = true;
}
if (_floatingWordAnchor == null)
_floatingWordAnchor = transform;
}
private void OnTriggerEnter(Collider other)
{
if (_requirePlayerTag && !other.CompareTag(_playerTag))
return;
if (_dialogueState.IsCompleted && !_isRetriggerable)
return;
if (_dialogueState.HasPausedDialogue)
{
_dialogueState.ResumeDialogue();
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.ShowBlur();
}
else if (!_hasTriggered || (_isRetriggerable && _dialogueState.IsCompleted))
{
TriggerDialogue();
}
}
private void OnTriggerExit(Collider other)
{
if (_requirePlayerTag && !other.CompareTag(_playerTag))
return;
if (_pauseOnExit && DialogueManager.Instance != null && DialogueManager.Instance.IsDialogueActive)
{
if ((Object)DialogueManager.Instance.CurrentOwner == this)
{
_dialogueState.PauseDialogue();
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.HideBlur();
}
}
}
private void TriggerDialogue()
{
if (DialogueManager.Instance == null)
{
Debug.LogError("DialogueManager not found in scene!", this);
return;
}
if (_conversation == null)
{
Debug.LogError($"{gameObject.name}: No conversation assigned!", this);
return;
}
_hasTriggered = true;
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
{
DialogueBlurEffectURP.Instance.ShowBlur();
}
DialogueManager.Instance.StartConversation(
_conversation,
_floatingWordAnchor,
_animationSettings,
_localDialogueUI,
this
);
DialogueManager.Instance.OnDialogueCompleted += OnDialogueCompleted;
}
private void OnDialogueCompleted(object owner)
{
if ((Object)owner == this)
{
_dialogueState.MarkAsCompleted();
if (_isRetriggerable)
{
_hasTriggered = false;
_dialogueState.AllowRetrigger();
}
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.HideBlur();
}
if (DialogueManager.Instance != null)
DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted;
}
public void ResetTrigger()
{
_hasTriggered = false;
_dialogueState.Reset();
}
private void OnDestroy()
{
if (DialogueManager.Instance != null)
DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted;
}
private void OnDrawGizmosSelected()
{
Collider col = GetComponent<Collider>();
if (col != null)
{
Gizmos.color = _hasTriggered ? Color.gray : Color.yellow;
Gizmos.matrix = transform.localToWorldMatrix;
if (col is BoxCollider box)
Gizmos.DrawWireCube(box.center, box.size);
else if (col is SphereCollider sphere)
Gizmos.DrawWireSphere(sphere.center, sphere.radius);
}
if (_floatingWordAnchor != null)
{
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere(_floatingWordAnchor.position, 0.2f);
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f33be20afd5d4c843a800ba1d8dd8437
@@ -0,0 +1,141 @@
using UnityEngine;
using Unheimlich.Core.Interaction;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Features.Dialogue;
using Unheimlich.Features.Player;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Dialogue
{
/// <summary>
/// NPC interactable that starts dialogue conversations.
/// Rotates to face player during dialogue and pauses if player moves too far away.
/// </summary>
public class NPCDialogueTrigger : InteractableBase
{
[Header("Dialogue Reference")]
[Tooltip("DialogueConversation to use for this NPC")]
public DialogueConversation Conversation;
[Header("Trigger Settings")]
[Tooltip("Can the dialogue be retriggered after completion")]
[SerializeField] private bool _isRetriggerable = true;
[Header("Floating Word Setting")]
[SerializeField] private Transform _floatingWordAnchor;
[Header("Animation Settings")]
[SerializeField] private DialogueAnimationSettings _animationSettings;
[Header("UI Reference")]
[Tooltip("Local DialogueUI for this NPC. Uses DialogueManager's UI if null")]
[SerializeField] private DialogueUI _localDialogueUI;
[Header("Distance Settings")]
[Tooltip("Maximum distance before dialogue pauses")]
[SerializeField] private float _maxDialogueDistance = 5f;
[Header("Blur Effect")]
[Tooltip("Enable blur effect when dialogue starts")]
[SerializeField] private bool _enableBlurEffect = false;
public Transform FloatingWordAnchor => _floatingWordAnchor;
private bool _isDialogueActive = false;
private DialogueStateHandler _dialogueState;
private void Awake()
{
_dialogueState = new DialogueStateHandler(this);
}
private void Start()
{
InteractionText = "Talk";
}
private void Update()
{
if (_isDialogueActive && PlayerController.Instance != null)
{
float distance = Vector3.Distance(transform.position, PlayerController.Instance.transform.position);
if (distance > _maxDialogueDistance && DialogueManager.Instance != null && DialogueManager.Instance.IsDialogueActive)
{
if ((Object)DialogueManager.Instance.CurrentOwner == this)
{
_dialogueState.PauseDialogue();
_isDialogueActive = false;
}
}
else
LookAtPlayer();
}
}
public override void Interact()
{
if (DialogueManager.Instance == null)
return;
if (_dialogueState.IsCompleted && !_isRetriggerable)
return;
if (_dialogueState.HasPausedDialogue)
{
_dialogueState.ResumeDialogue();
DialogueManager.Instance.OnDialogueCompleted += OnDialogueCompleted;
_isDialogueActive = true;
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.ShowBlur();
}
else
{
if (Conversation == null)
{
Debug.LogWarning($"NPC {gameObject.name} has no conversation configured!");
return;
}
DialogueManager.Instance.StartConversation(Conversation, _floatingWordAnchor, _animationSettings, _localDialogueUI, this);
DialogueManager.Instance.OnDialogueCompleted += OnDialogueCompleted;
_isDialogueActive = true;
if (_enableBlurEffect && DialogueBlurEffectURP.Instance != null)
DialogueBlurEffectURP.Instance.ShowBlur();
}
}
private void OnDialogueCompleted(object owner)
{
if ((Object)owner == this)
{
_dialogueState.MarkAsCompleted();
if (_isRetriggerable)
_dialogueState.AllowRetrigger();
_isDialogueActive = false;
}
if (DialogueManager.Instance != null)
DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted;
}
private void OnDestroy()
{
if (DialogueManager.Instance != null)
DialogueManager.Instance.OnDialogueCompleted -= OnDialogueCompleted;
}
public void LookAtPlayer()
{
if (PlayerController.Instance == null) return;
Vector3 lookAtPosition = PlayerController.Instance.transform.position;
lookAtPosition.y = transform.position.y;
transform.LookAt(lookAtPosition);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8696519b7eabaab4dbe80f2a4744cea0