Files
Ipseity-Demo/Assets/Unheimlich_POC/Scripts/Handlers/Interactions/ObjectDescriptionTrigger.cs
T

314 lines
11 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using Unheimlich.Data.Dialogues;
using Unheimlich.Gameplay.Player;
using OctoCore.Localization;
namespace Unheimlich.Interactions.FloatingWords
{
public class ObjectDescriptionTrigger : MonoBehaviour
{
[Header("Description")]
[Tooltip("Localized description text (recommended)")]
[SerializeField] private OctoLocalizedTextData _descriptionTextLocalized;
[Tooltip("Fallback description text if localized version is not set")]
[SerializeField] private string _descriptionText = "Mysterious Object";
[Header("Settings")]
[SerializeField] private ObjectDescriptionSettings _settings;
[Header("Anchor")]
[SerializeField] private Transform _descriptionAnchor;
[Header("Prefab")]
[SerializeField] private ChoiceFocusHandler _wordPrefab;
private Transform _playerTransform;
private Camera _mainCamera;
private List<ChoiceFocusHandler> _spawnedWords = new List<ChoiceFocusHandler>();
private GameObject _wordsContainer;
private GameObject _wordsRotator;
private bool _isActive = false;
private bool _isMerged = false;
private bool _hasBeenMergedOnce = false;
private bool _hasCompletedMergeOnce = false;
private Vector3[] _originalSpawnPositions;
private Vector3[] _basePositions;
private float _currentConvergenceRadius;
public bool IsAnimationActive => _isActive && (!_settings.MergeOnce || !_hasCompletedMergeOnce);
public bool IsInMergeOnceMode => _settings != null && _settings.MergeOnce;
void Start()
{
_playerTransform = Player.Instance.transform;
_mainCamera = Camera.main;
if (_playerTransform == null)
Debug.LogWarning($"[ObjectDescription] No player found for {gameObject.name}");
if (_descriptionAnchor == null)
_descriptionAnchor = transform;
if (_settings == null)
{
Debug.LogError($"[ObjectDescription] No settings assigned for {gameObject.name}");
enabled = false;
}
}
void Update()
{
if (_playerTransform == null || _settings == null) return;
float distanceToPlayer = Vector3.Distance(_playerTransform.position, transform.position);
if (!_isActive && distanceToPlayer <= _settings.ActivationDistance)
{
if (!_settings.MergeOnce || !_hasCompletedMergeOnce)
SpawnWords();
}
else if (_isActive && distanceToPlayer >= _settings.DeactivationDistance)
DespawnWords();
if (_isActive)
{
if (!_settings.MergeOnce || !_hasBeenMergedOnce)
{
UpdateWordConvergence();
UpdateContainerRotation();
}
}
}
private void SpawnWords()
{
if (_wordPrefab == null)
{
Debug.LogError($"[ObjectDescription] No word prefab assigned for {gameObject.name}");
return;
}
_isActive = true;
_isMerged = false;
_currentConvergenceRadius = _settings.SpawnRadius;
_wordsContainer = new GameObject($"{_descriptionText}_Container");
_wordsContainer.transform.position = _descriptionAnchor.position;
_wordsContainer.transform.rotation = _descriptionAnchor.rotation;
_wordsRotator = FloatingWordsSpawner.CreateWordsContainer(_descriptionText, _descriptionAnchor, _settings);
_wordsRotator.transform.SetParent(_wordsContainer.transform, false);
ObjectDescriptionTriggerReference triggerRef = _wordsRotator.AddComponent<ObjectDescriptionTriggerReference>();
triggerRef.Trigger = this;
string descText = _descriptionTextLocalized != null
? OctoLocalization.GetLocalizedText(_descriptionTextLocalized)
: _descriptionText;
List<DialogueChoiceData> dummyChoices = new List<DialogueChoiceData>();
for (int i = 0; i < _settings.WordCount; i++)
{
dummyChoices.Add(new DialogueChoiceData
{
ChoiceText = _descriptionTextLocalized,
NextNode = null
});
}
_spawnedWords = FloatingWordsSpawner.SpawnByMode(
dummyChoices,
_wordPrefab,
_wordsRotator.transform,
_settings,
out _originalSpawnPositions
);
_basePositions = new Vector3[_spawnedWords.Count];
for (int i = 0; i < _spawnedWords.Count; i++)
_basePositions[i] = _spawnedWords[i].transform.localPosition;
}
private void DespawnWords()
{
_isActive = false;
_isMerged = false;
foreach (var word in _spawnedWords)
{
if (word != null)
Destroy(word.gameObject);
}
_spawnedWords.Clear();
if (_wordsContainer != null)
Destroy(_wordsContainer);
// Debug.Log($"[ObjectDescription] Despawned words for '{descriptionText}'");
}
private void UpdateWordConvergence()
{
if (_mainCamera == null || _spawnedWords.Count == 0) return;
Vector2 screenCenter = new Vector2(Screen.width / 2f, Screen.height / 2f);
Ray ray = _mainCamera.ScreenPointToRay(screenCenter);
RaycastHit hit;
int layerMask = ~LayerMask.GetMask("Words", "UI");
bool isHoveringObject = false;
if (Physics.Raycast(ray, out hit, 100f, layerMask))
{
if (hit.collider.gameObject == gameObject || hit.collider.transform.IsChildOf(transform))
isHoveringObject = true;
}
float targetRadius = isHoveringObject ? _settings.MinConvergenceRadius : _settings.SpawnRadius;
_currentConvergenceRadius = Mathf.Lerp(_currentConvergenceRadius, targetRadius, Time.deltaTime * _settings.ConvergenceSpeed);
if (isHoveringObject && !_isMerged && _currentConvergenceRadius <= _settings.MinConvergenceRadius * 5f)
MergeWords();
else if (!isHoveringObject && _isMerged)
{
if (!_settings.MergeOnce || !_hasBeenMergedOnce)
UnmergeWords();
}
if (_isMerged) return;
float convergenceFactor = Mathf.InverseLerp(0f, _settings.SpawnRadius, _currentConvergenceRadius);
for (int i = 0; i < _spawnedWords.Count; i++)
{
if (_spawnedWords[i] == null) continue;
Vector3 targetLocalPos = GetConvergenceTargetPosition(_originalSpawnPositions[i], _currentConvergenceRadius);
_basePositions[i] = Vector3.Lerp(
_basePositions[i],
targetLocalPos,
Time.deltaTime * _settings.ConvergenceSpeed
);
_spawnedWords[i].transform.localPosition = _basePositions[i] + _spawnedWords[i].GetShakeOffset(convergenceFactor);
}
}
private Vector3 GetConvergenceTargetPosition(Vector3 originalPosition, float radius)
{
if (radius < 0.01f) return Vector3.zero;
switch (_settings.RotationAxis)
{
case RotationAxis.Forward:
Vector2 xyNormalized = new Vector2(originalPosition.x, originalPosition.y - _settings.SpawnHeightOffset).normalized;
return new Vector3(
xyNormalized.x * radius,
xyNormalized.y * radius + _settings.SpawnHeightOffset,
originalPosition.z
);
case RotationAxis.Up:
Vector2 xzNormalized = new Vector2(originalPosition.x, originalPosition.z).normalized;
return new Vector3(
xzNormalized.x * radius,
originalPosition.y,
xzNormalized.y * radius
);
case RotationAxis.Right:
Vector2 yzNormalized = new Vector2(originalPosition.y - _settings.SpawnHeightOffset, originalPosition.z).normalized;
return new Vector3(
originalPosition.x,
yzNormalized.x * radius + _settings.SpawnHeightOffset,
yzNormalized.y * radius
);
default:
return originalPosition.normalized * radius;
}
}
private void MergeWords()
{
if (_isMerged) return;
_isMerged = true;
_hasBeenMergedOnce = true;
FloatingWordsSpawner.MergeWords(_spawnedWords, _settings, () =>
{
if (_settings.MergeOnce)
{
LeanTween.delayedCall(_settings.MergeOnceDisplayDuration, () =>
{
FadeOutAndComplete();
});
}
});
}
private void FadeOutAndComplete()
{
if (_spawnedWords.Count > 0 && _spawnedWords[0] != null)
{
CanvasGroup canvasGroup = _spawnedWords[0].GetComponent<CanvasGroup>();
if (canvasGroup != null)
{
LeanTween.value(_spawnedWords[0].gameObject, 1f, 0f, _settings.MergeDuration)
.setOnUpdate((float val) => { canvasGroup.alpha = val; })
.setEaseInQuad()
.setOnComplete(() =>
{
_hasCompletedMergeOnce = true;
DespawnWords();
});
}
}
}
private void UnmergeWords()
{
if (!_isMerged) return;
_isMerged = false;
FloatingWordsSpawner.UnmergeWords(_spawnedWords, _settings);
}
private void UpdateContainerRotation()
{
FloatingWordsSpawner.UpdateContainerRotation(_wordsContainer, _wordsRotator, _playerTransform, _settings);
}
public ObjectDescriptionSettings GetSettings()
{
return _settings;
}
void OnDrawGizmosSelected()
{
if (_settings == null) return;
Transform anchor = _descriptionAnchor != null ? _descriptionAnchor : transform;
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, _settings.ActivationDistance);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, _settings.DeactivationDistance);
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(anchor.position, _settings.SpawnRadius);
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere(anchor.position, _settings.MinConvergenceRadius);
}
}
}