Add utils + refacto

This commit is contained in:
2026-01-30 17:39:26 +01:00
parent 9ff17b5305
commit 23d3cb5d2c
29 changed files with 675 additions and 461 deletions
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using Unheimlich.Data.Dialogues;
using Unheimlich.Managers;
using Unheimlich.Gameplay.Player;
using Unheimlich.Utility;
namespace Unheimlich.Interactions.FloatingWords
{
@@ -219,12 +220,15 @@ namespace Unheimlich.Interactions.FloatingWords
if (_choiceTextComponent == null)
return;
if (_textScaleTweenId >= 0)
LeanTween.cancel(_textScaleTweenId);
TweenHelper.CancelTween(ref _textScaleTweenId);
_textScaleTweenId = LeanTween.scale(_choiceTextComponent.gameObject, Vector3.one * targetScale, duration)
.setEase(LeanTweenType.easeOutQuad)
.id;
_textScaleTweenId = TweenHelper.ScaleLocal(
_choiceTextComponent.gameObject,
Vector3.one * targetScale,
duration,
null,
LeanTweenType.easeOutQuad
);
}
public void ResetTextScale(float duration = 0.3f)
@@ -510,23 +514,20 @@ namespace Unheimlich.Interactions.FloatingWords
{
LeanTween.cancel(gameObject);
if (_textScaleTweenId >= 0)
LeanTween.cancel(_textScaleTweenId);
TweenHelper.CancelTween(ref _textScaleTweenId);
StopOrganicShake();
ResetSketchFade();
LeanTween.moveLocal(gameObject, _startLocalPos, duration)
.setEase(LeanTweenType.easeOutQuad)
.setOnComplete(() => {
_positionCaptured = false;
TweenHelper.MoveLocal(gameObject, _startLocalPos, duration, () => {
_positionCaptured = false;
if (DialogueManager.Instance != null)
DialogueManager.Instance.UnlockFocus();
if (DialogueManager.Instance != null)
DialogueManager.Instance.UnlockFocus();
StartOrganicShake();
});
StartOrganicShake();
}, LeanTweenType.easeOutQuad);
transform.localScale = Vector3.one * _originalScale;
@@ -2,14 +2,10 @@ using UnityEngine;
using System.Collections.Generic;
using Unheimlich.Data.Dialogues;
using Unheimlich.Gameplay.Player;
using Unheimlich.Utility;
namespace Unheimlich.Interactions.FloatingWords
{
/// <summary>
/// Utility class for spawning floating 3D text choices in world space.
/// Used for both dialogue choices and object descriptions. Handles positioning,
/// rotation, animations (spawn, merge, floating) using LeanTween for smooth effects.
/// </summary>
public static class FloatingWordsSpawner
{
private const float ROTATOR_SCALE = 0.01f;
@@ -249,26 +245,32 @@ namespace Unheimlich.Interactions.FloatingWords
CanvasGroup canvasGroup = words[i].GetComponent<CanvasGroup>();
if (canvasGroup != null)
{
LeanTween.value(words[i].gameObject, 1f, 0f, config.MergeDuration)
.setOnUpdate((float val) => { canvasGroup.alpha = val; })
.setEaseInQuad();
TweenHelper.FadeCanvasGroup(canvasGroup, 0f, config.MergeDuration, null, LeanTweenType.easeInQuad);
}
}
}
if (words.Count > 0 && words[0] != null)
{
LeanTween.scale(words[0].gameObject, Vector3.one * config.MergeScalePulse, config.MergeDuration / 2f)
.setEaseOutBack()
.setOnComplete(() =>
TweenHelper.ScaleLocal(
words[0].gameObject,
Vector3.one * config.MergeScalePulse,
config.MergeDuration / 2f,
() =>
{
if (words.Count > 0 && words[0] != null)
{
LeanTween.scale(words[0].gameObject, Vector3.one, config.MergeDuration / 2f)
.setEaseInBack()
.setOnComplete(() => onMergeComplete?.Invoke());
TweenHelper.ScaleLocal(
words[0].gameObject,
Vector3.one,
config.MergeDuration / 2f,
() => onMergeComplete.SafeInvoke(),
LeanTweenType.easeInBack
);
}
});
},
LeanTweenType.easeOutBack
);
}
}
@@ -292,13 +294,11 @@ namespace Unheimlich.Interactions.FloatingWords
{
if (words[i] != null)
{
LeanTween.cancel(words[i].gameObject);
words[i].gameObject.CancelAllTweens();
CanvasGroup canvasGroup = words[i].GetComponent<CanvasGroup>();
if (canvasGroup != null)
{
LeanTween.value(words[i].gameObject, canvasGroup.alpha, 1f, config.MergeDuration)
.setOnUpdate((float val) => { canvasGroup.alpha = val; })
.setEaseOutQuad();
TweenHelper.FadeCanvasGroup(canvasGroup, 1f, config.MergeDuration, null, LeanTweenType.easeOutQuad);
}
words[i].transform.localScale = Vector3.one;
}
@@ -306,7 +306,7 @@ namespace Unheimlich.Interactions.FloatingWords
if (words.Count > 0 && words[0] != null)
{
LeanTween.cancel(words[0].gameObject);
words[0].gameObject.CancelAllTweens();
words[0].transform.localScale = Vector3.one;
}
}
@@ -1,6 +1,7 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unheimlich.Utility;
namespace Unheimlich.Interactions.FloatingWords
{
@@ -93,42 +94,41 @@ namespace Unheimlich.Interactions.FloatingWords
_isEffectActive = true;
_scribbleTweenId = LeanTween.value(gameObject, 0f, 1f, scribbleDuration)
.setEase(LeanTweenType.easeInOutQuad)
.setOnUpdate((float val) => {
if (_scribbleMaterialInstance != null)
_scribbleMaterialInstance.SetFloat(ProgressID, val);
})
.setOnComplete(() => {
_scribbleTweenId = TweenHelper.AnimateMaterialFloat(
gameObject,
_scribbleMaterialInstance,
ProgressID,
0f,
1f,
scribbleDuration,
() => {
_scribbleTweenId = -1;
float ghostAlphaRatio = _ghostTextComponent != null ? (_originalGhostColor.a / _originalTextColor.a) : 0f;
_fadeTweenId = LeanTween.value(gameObject, _originalTextColor.a, finalAlpha, fadeDuration)
.setEase(LeanTweenType.easeInQuad)
.setOnUpdate((float val) => {
if (_textComponent != null)
{
Color textColor = _textComponent.color;
textColor.a = val;
_textComponent.color = textColor;
_textComponent.color = _textComponent.color.WithAlpha(val);
}
if (_ghostTextComponent != null)
{
Color ghostColor = _ghostTextComponent.color;
ghostColor.a = val * (_originalGhostColor.a / _originalTextColor.a);
_ghostTextComponent.color = ghostColor;
_ghostTextComponent.color = _ghostTextComponent.color.WithAlpha(val * ghostAlphaRatio);
}
if (_scribbleOverlay != null)
{
Color scribbleColor = _scribbleOverlay.color;
scribbleColor.a = val;
_scribbleOverlay.color = scribbleColor;
_scribbleOverlay.color = _scribbleOverlay.color.WithAlpha(val);
}
})
.setOnComplete(() => {
_fadeTweenId = -1;
}).id;
}).id;
},
LeanTweenType.easeInOutQuad);
}
public void ResetEffect()
@@ -141,17 +141,19 @@ namespace Unheimlich.Interactions.FloatingWords
if (currentProgress > 0f)
{
_scribbleTweenId = LeanTween.value(gameObject, currentProgress, 0f, 0.3f)
.setEase(LeanTweenType.easeOutQuad)
.setOnUpdate((float val) => {
if (_scribbleMaterialInstance != null)
_scribbleMaterialInstance.SetFloat(ProgressID, val);
})
.setOnComplete(() => {
_scribbleTweenId = TweenHelper.AnimateMaterialFloat(
gameObject,
_scribbleMaterialInstance,
ProgressID,
currentProgress,
0f,
0.3f,
() => {
_scribbleTweenId = -1;
if (_scribbleOverlay != null)
_scribbleOverlay.gameObject.SetActive(false);
}).id;
},
LeanTweenType.easeOutQuad);
}
}
@@ -161,34 +163,23 @@ namespace Unheimlich.Interactions.FloatingWords
if (currentAlpha < _originalTextColor.a)
{
_fadeTweenId = LeanTween.value(gameObject, currentAlpha, _originalTextColor.a, 0.3f)
.setEase(LeanTweenType.easeOutQuad)
.setOnUpdate((float val) => {
if (_textComponent != null)
{
Color c = _textComponent.color;
c.a = val;
_textComponent.color = c;
}
if (_ghostTextComponent != null)
{
Color c = _ghostTextComponent.color;
c.a = val * (_originalGhostColor.a / _originalTextColor.a);
_ghostTextComponent.color = c;
}
})
.setOnComplete(() => {
_fadeTweenId = -1;
}).id;
float ghostAlphaRatio = _ghostTextComponent != null ? (_originalGhostColor.a / _originalTextColor.a) : 0f;
_fadeTweenId = TweenHelper.FadeText(
gameObject,
_textComponent,
_ghostTextComponent,
_originalTextColor.a,
0.3f,
ghostAlphaRatio,
() => { _fadeTweenId = -1; },
LeanTweenType.easeOutQuad);
}
}
if (_scribbleOverlay != null)
{
Color c = _scribbleOverlay.color;
c.a = 1f;
_scribbleOverlay.color = c;
_scribbleOverlay.color = _scribbleOverlay.color.WithAlpha(1f);
}
_isEffectActive = false;
@@ -196,17 +187,8 @@ namespace Unheimlich.Interactions.FloatingWords
private void CancelActiveTweens()
{
if (_scribbleTweenId != -1)
{
LeanTween.cancel(_scribbleTweenId);
_scribbleTweenId = -1;
}
if (_fadeTweenId != -1)
{
LeanTween.cancel(_fadeTweenId);
_fadeTweenId = -1;
}
TweenHelper.CancelTween(ref _scribbleTweenId);
TweenHelper.CancelTween(ref _fadeTweenId);
}
private void OnDestroy()
@@ -1,15 +1,12 @@
using UnityEngine;
using Unheimlich.Core;
using Unheimlich.Managers;
using Unheimlich.Utility;
namespace Unheimlich.Interactions.Core
{
/// <summary>
/// Detects interactable objects in front of the player camera using raycasts.
/// Triggers interaction when player presses interact button while looking at an interactable.
/// </summary>
public class InteractionHandler : MonoBehaviour
{
public static InteractionHandler Instance { get; private set; }
public class InteractionHandler : Singleton<InteractionHandler>
{
[Header("Settings")]
[SerializeField] private float _interactionRange = 1f;
@@ -19,50 +16,32 @@ namespace Unheimlich.Interactions.Core
private InteractableBase _currentInteractable;
private Camera _playerCamera;
private float _raycastTimer;
private static readonly Vector3 ViewportCenter = new Vector3(0.5f, 0.5f, 0f);
private void Awake()
protected override void OnAwake()
{
if (Instance != null && Instance != this)
{
Destroy(this);
return;
}
Instance = this;
_playerCamera = GetComponent<Camera>();
}
private void Update()
{
_raycastTimer += Time.deltaTime;
if (_raycastTimer >= _raycastInterval)
if (RaycastHelper.ThrottledRaycastComponent(
ref _raycastTimer,
_raycastInterval,
_playerCamera,
_interactionRange,
_interactableLayers,
out InteractableBase interactable))
{
CheckForInteractable();
_raycastTimer = 0f;
_currentInteractable = interactable;
}
else if (_raycastTimer == 0f)
{
_currentInteractable = null;
}
HandleInteractionInput();
}
/// <summary>
/// Performs raycast from camera center to detect interactable objects within range.
/// Updates the current interactable reference for input handling.
/// </summary>
private void CheckForInteractable()
{
Ray ray = _playerCamera.ViewportPointToRay(ViewportCenter);
if (Physics.Raycast(ray, out RaycastHit hit, _interactionRange, _interactableLayers))
{
InteractableBase hitInteractable = hit.collider.GetComponent<InteractableBase>();
_currentInteractable = hitInteractable;
}
else
_currentInteractable = null;
}
private void HandleInteractionInput()
{
if (PlayerInputManager.Instance != null &&
@@ -79,7 +58,8 @@ namespace Unheimlich.Interactions.Core
{
Gizmos.color = _currentInteractable != null ? Color.green : Color.red;
Ray ray = _playerCamera.ViewportPointToRay(ViewportCenter);
Vector3 viewportCenter = new Vector3(0.5f, 0.5f, 0f);
Ray ray = _playerCamera.ViewportPointToRay(viewportCenter);
Gizmos.DrawRay(ray.origin, ray.direction * _interactionRange);
}
}
@@ -1,14 +1,18 @@
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
using Unheimlich.Core;
using Unheimlich.Gameplay.Items;
using InputManager = Unheimlich.Managers.PlayerInputManager;
namespace Unheimlich.Interactions.Core
{
public class PlayerInspectionHandler : MonoBehaviour
/// <summary>
/// Handles player item inspection mode.
/// When inspecting, disables player movement and allows item rotation using look input.
/// </summary>
public class PlayerInspectionHandler : Singleton<PlayerInspectionHandler>
{
public static PlayerInspectionHandler Instance { get; private set; }
[Header("Components")]
[SerializeField] private Transform _inspectionHoldPoint;
@@ -19,21 +23,7 @@ namespace Unheimlich.Interactions.Core
private Coroutine _interactionListener;
private bool _isUsingGamepad = false;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(this);
return;
}
Instance = this;
}
/// <summary>
/// Toggles inspection mode for an item. When inspecting, disables player movement
/// and allows item rotation using look input until interaction key is pressed again.
/// </summary>
public void ToggleInspection(InspectableItem item)
{
if (!IsInspecting)