Add utils + refacto
This commit is contained in:
@@ -2498,6 +2498,10 @@ PrefabInstance:
|
||||
propertyPath: _diapasonParticles
|
||||
value:
|
||||
objectReference: {fileID: 5090177222934034460}
|
||||
- target: {fileID: 3142789394009655648, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
|
||||
propertyPath: _diapasonTapVolume
|
||||
value: 0.3
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3142789394009655648, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
|
||||
propertyPath: _handTouchFeedback
|
||||
value:
|
||||
@@ -2536,7 +2540,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 23.7
|
||||
value: 25.9
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
@@ -2649,8 +2653,8 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 7093688fd39800645bbe00b6d9a3f27b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Audio.DiapasonDebugger
|
||||
_showDebugInfo: 1
|
||||
_showGizmos: 1
|
||||
_showDebugInfo: 0
|
||||
_showGizmos: 0
|
||||
_listeningRangeColor: {r: 0, g: 1, b: 1, a: 1}
|
||||
_activeTargetColor: {r: 0, g: 1, b: 0, a: 1}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.Audio
|
||||
{
|
||||
@@ -24,8 +25,8 @@ namespace Unheimlich.Audio
|
||||
private const string CONTINUOUS_AUDIO_SOURCE_NAME = "Continuous Audio Source";
|
||||
|
||||
// Volume multipliers for concentration system
|
||||
private const float BASELINE_VOLUME_MULTIPLIER = 0.3f;
|
||||
private const float FULL_VOLUME_MULTIPLIER = 1f;
|
||||
private const float BASELINE_VOLUME_MULTIPLIER = 0.1f;
|
||||
private const float FULL_VOLUME_MULTIPLIER = 1.5f;
|
||||
private const float CONCENTRATION_FADE_DURATION = 1f;
|
||||
private const float RELEASE_FADE_DURATION = 0.5f;
|
||||
|
||||
@@ -78,7 +79,8 @@ namespace Unheimlich.Audio
|
||||
private AudioClip _continuousClip;
|
||||
private Coroutine _volumeFadeCoroutine;
|
||||
private Coroutine _startListeningCoroutine;
|
||||
private Coroutine _concentrationFadeCoroutine;
|
||||
private int _concentrationFadeTweenId = -1;
|
||||
private int _crossfadeTweenId = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this emitter has been tapped during the current listening session.
|
||||
@@ -147,18 +149,34 @@ namespace Unheimlich.Audio
|
||||
/// </summary>
|
||||
public void SetConcentrating(bool concentrating)
|
||||
{
|
||||
TweenHelper.CancelTween(ref _concentrationFadeTweenId);
|
||||
|
||||
if (_concentrationFadeCoroutine != null)
|
||||
StopCoroutine(_concentrationFadeCoroutine);
|
||||
if (_continuousAudioSource == null)
|
||||
return;
|
||||
|
||||
if (concentrating)
|
||||
{
|
||||
_concentrationFadeCoroutine = StartCoroutine(FadeConcentrationVolume(BASELINE_VOLUME_MULTIPLIER, FULL_VOLUME_MULTIPLIER, CONCENTRATION_FADE_DURATION));
|
||||
}
|
||||
else
|
||||
{
|
||||
_concentrationFadeCoroutine = StartCoroutine(FadeConcentrationVolume(FULL_VOLUME_MULTIPLIER, BASELINE_VOLUME_MULTIPLIER, RELEASE_FADE_DURATION));
|
||||
}
|
||||
float baseVolume = _continuousBaseVolume;
|
||||
float fromMultiplier = concentrating ? BASELINE_VOLUME_MULTIPLIER : FULL_VOLUME_MULTIPLIER;
|
||||
float toMultiplier = concentrating ? FULL_VOLUME_MULTIPLIER : BASELINE_VOLUME_MULTIPLIER;
|
||||
float duration = concentrating ? CONCENTRATION_FADE_DURATION : RELEASE_FADE_DURATION;
|
||||
|
||||
float fromVolume = baseVolume * fromMultiplier;
|
||||
float toVolume = baseVolume * toMultiplier;
|
||||
|
||||
_concentrationFadeTweenId = TweenHelper.FadeVolume(
|
||||
_continuousAudioSource,
|
||||
toVolume,
|
||||
duration);
|
||||
}
|
||||
|
||||
public void ResetConcentrationVolume()
|
||||
{
|
||||
TweenHelper.CancelTween(ref _concentrationFadeTweenId);
|
||||
|
||||
if (_continuousAudioSource == null)
|
||||
return;
|
||||
|
||||
float baselineVolume = _continuousBaseVolume * BASELINE_VOLUME_MULTIPLIER;
|
||||
_continuousAudioSource.volume = baselineVolume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,8 +215,22 @@ namespace Unheimlich.Audio
|
||||
if (_volumeFadeCoroutine != null)
|
||||
StopCoroutine(_volumeFadeCoroutine);
|
||||
|
||||
TweenHelper.CancelTween(ref _crossfadeTweenId);
|
||||
|
||||
float crossfadeDuration = 1f;
|
||||
_volumeFadeCoroutine = StartCoroutine(CrossfadeSounds(crossfadeDuration));
|
||||
|
||||
if (_continuousAudioSource != null)
|
||||
{
|
||||
_crossfadeTweenId = TweenHelper.FadeVolume(
|
||||
_continuousAudioSource,
|
||||
0f,
|
||||
crossfadeDuration,
|
||||
() =>
|
||||
{
|
||||
if (_continuousAudioSource != null)
|
||||
_continuousAudioSource.Stop();
|
||||
});
|
||||
}
|
||||
|
||||
if (_emitterParticles != null)
|
||||
{
|
||||
@@ -231,7 +263,7 @@ namespace Unheimlich.Audio
|
||||
/// This is the only place where _hasBeenTapped is reset to false,
|
||||
/// allowing the emitter to be used again in a future listening session.
|
||||
/// </summary>
|
||||
public void StopListening()
|
||||
public void StopListening(bool cancelConcentrationFade = true)
|
||||
{
|
||||
bool wasBeenTapped = _hasBeenTapped;
|
||||
|
||||
@@ -244,8 +276,8 @@ namespace Unheimlich.Audio
|
||||
if (_startListeningCoroutine != null)
|
||||
StopCoroutine(_startListeningCoroutine);
|
||||
|
||||
if (_concentrationFadeCoroutine != null)
|
||||
StopCoroutine(_concentrationFadeCoroutine);
|
||||
if (cancelConcentrationFade)
|
||||
TweenHelper.CancelTween(ref _concentrationFadeTweenId);
|
||||
|
||||
if (_audioSource != null && _audioSource.isPlaying)
|
||||
_audioSource.Stop();
|
||||
@@ -400,59 +432,6 @@ namespace Unheimlich.Audio
|
||||
Gamepad.current.SetMotorSpeeds(intensity, intensity);
|
||||
}
|
||||
|
||||
private IEnumerator FadeConcentrationVolume(float fromMultiplier, float toMultiplier, float duration)
|
||||
{
|
||||
float elapsed = 0f;
|
||||
float baseVolume = _continuousBaseVolume;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / duration;
|
||||
float currentMultiplier = Mathf.Lerp(fromMultiplier, toMultiplier, t);
|
||||
|
||||
if (_continuousAudioSource != null)
|
||||
{
|
||||
_continuousAudioSource.volume = baseVolume * currentMultiplier;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (_continuousAudioSource != null)
|
||||
{
|
||||
_continuousAudioSource.volume = baseVolume * toMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator CrossfadeSounds(float fadeDuration)
|
||||
{
|
||||
if (_continuousAudioSource == null)
|
||||
yield break;
|
||||
|
||||
float startVolume = _continuousAudioSource.volume;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < fadeDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / fadeDuration;
|
||||
|
||||
if (_continuousAudioSource != null)
|
||||
{
|
||||
_continuousAudioSource.volume = Mathf.Lerp(startVolume, 0f, t);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (_continuousAudioSource != null)
|
||||
{
|
||||
_continuousAudioSource.volume = 0f;
|
||||
_continuousAudioSource.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVibration()
|
||||
{
|
||||
if (!_enableVibration || Gamepad.current == null)
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace Unheimlich.Audio
|
||||
private void RefreshListenablesList()
|
||||
{
|
||||
_allListenables = FindObjectsByType<AudioListenable>(FindObjectsSortMode.None);
|
||||
if (!_showDebugInfo)
|
||||
return;
|
||||
Debug.Log($"Found {_allListenables.Length} AudioListenable objects in scene");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a469312c19fe2fb40baa7642b1e73dcd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unheimlich.Core
|
||||
{
|
||||
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
public static T Instance { get; private set; }
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Debug.LogWarning($"[{typeof(T).Name}] Multiple instances detected! Destroying duplicate on GameObject '{gameObject.name}'.");
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this as T;
|
||||
OnAwake();
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
OnDestroyInstance();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnAwake() { }
|
||||
protected virtual void OnDestroyInstance() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 654e642c73c2b954fa86e0caac3f08c1
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using Unheimlich.Interactions.Core;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.Gameplay.Environment
|
||||
{
|
||||
@@ -29,21 +30,17 @@ namespace Unheimlich.Gameplay.Environment
|
||||
|
||||
public void ToggleDoor()
|
||||
{
|
||||
LeanTween.cancel(gameObject);
|
||||
gameObject.CancelAllTweens();
|
||||
|
||||
if (!IsOpen)
|
||||
{
|
||||
LeanTween.rotate(gameObject, _openRotation.eulerAngles, _animationDuration)
|
||||
.setEase(_easeType);
|
||||
|
||||
TweenHelper.RotateLocal(gameObject, _openRotation.eulerAngles, _animationDuration, null, _easeType);
|
||||
IsOpen = true;
|
||||
InteractionText = "Close";
|
||||
}
|
||||
else
|
||||
{
|
||||
LeanTween.rotate(gameObject, _closedRotation.eulerAngles, _animationDuration)
|
||||
.setEase(_easeType);
|
||||
|
||||
TweenHelper.RotateLocal(gameObject, _closedRotation.eulerAngles, _animationDuration, null, _easeType);
|
||||
IsOpen = false;
|
||||
InteractionText = "Open";
|
||||
}
|
||||
|
||||
+61
-87
@@ -2,6 +2,8 @@ using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Audio;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Utility;
|
||||
using InputManager = Unheimlich.Managers.PlayerInputManager;
|
||||
|
||||
namespace Unheimlich.Gameplay.Player
|
||||
@@ -16,14 +18,11 @@ namespace Unheimlich.Gameplay.Player
|
||||
/// - Visual feedback (vignette, cursor, particles)
|
||||
/// - Preventing multiple taps on the same emitter
|
||||
/// </summary>
|
||||
public class DiapasonListeningHandler : MonoBehaviour
|
||||
public class DiapasonListeningHandler : Singleton<DiapasonListeningHandler>
|
||||
{
|
||||
// Animator parameter names for diapason animations
|
||||
private const string ANIM_TRIGGER_TAP = "Tap";
|
||||
private const string ANIM_BOOL_VIBRATING = "IsVibrating";
|
||||
|
||||
public static DiapasonListeningHandler Instance { get; private set; }
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private GameObject _diapasonObject;
|
||||
[SerializeField] private Animator _diapasonAnimator;
|
||||
@@ -72,23 +71,18 @@ namespace Unheimlich.Gameplay.Player
|
||||
private AudioListenable _currentTargetEmitter;
|
||||
private AudioSource _playerAudioSource;
|
||||
private Coroutine _listeningCoroutine;
|
||||
private Coroutine _tweenCoroutine;
|
||||
private Coroutine _audioFadeCoroutine;
|
||||
private int _diapasonTweenId = -1;
|
||||
private int _audioListenerFadeTweenId = -1;
|
||||
private int _playerAudioFadeTweenId = -1;
|
||||
private Vector2 _originalCameraRotation;
|
||||
private float _originalAmbientVolume;
|
||||
private Vector3 _diapasonEquippedPosition;
|
||||
private Vector3 _diapasonHiddenPosition;
|
||||
private bool _canUseDiapason;
|
||||
private bool _isFadingOutConcentration;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
_playerAudioSource = GetComponent<AudioSource>();
|
||||
if (_playerAudioSource == null)
|
||||
_playerAudioSource = gameObject.AddComponent<AudioSource>();
|
||||
@@ -217,6 +211,9 @@ namespace Unheimlich.Gameplay.Player
|
||||
/// </summary>
|
||||
private void StartListeningMode()
|
||||
{
|
||||
if (_isFadingOutConcentration)
|
||||
return;
|
||||
|
||||
if (_listeningCoroutine != null)
|
||||
StopCoroutine(_listeningCoroutine);
|
||||
|
||||
@@ -240,17 +237,21 @@ namespace Unheimlich.Gameplay.Player
|
||||
|
||||
if (_diapasonObject != null)
|
||||
{
|
||||
if (_tweenCoroutine != null)
|
||||
StopCoroutine(_tweenCoroutine);
|
||||
TweenHelper.CancelTween(ref _diapasonTweenId);
|
||||
|
||||
_tweenCoroutine = StartCoroutine(TweenDiapasonPosition(_diapasonEquippedPosition, _diapasonTweenDuration, () =>
|
||||
{
|
||||
if (_diapasonAnimator != null)
|
||||
_diapasonTweenId = TweenHelper.MoveLocalWithCurve(
|
||||
_diapasonObject,
|
||||
_diapasonEquippedPosition,
|
||||
_diapasonTweenDuration,
|
||||
_diapasonTweenCurve,
|
||||
() =>
|
||||
{
|
||||
_diapasonAnimator.enabled = true;
|
||||
_diapasonAnimator.SetBool(ANIM_BOOL_VIBRATING, false);
|
||||
}
|
||||
}));
|
||||
if (_diapasonAnimator != null)
|
||||
{
|
||||
_diapasonAnimator.enabled = true;
|
||||
_diapasonAnimator.SetBool(ANIM_BOOL_VIBRATING, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
PlayBreathIn();
|
||||
@@ -294,9 +295,21 @@ namespace Unheimlich.Gameplay.Player
|
||||
|
||||
if (_playerAudioSource != null && _playerAudioSource.isPlaying)
|
||||
{
|
||||
if (_audioFadeCoroutine != null)
|
||||
StopCoroutine(_audioFadeCoroutine);
|
||||
_audioFadeCoroutine = StartCoroutine(FadeOutAudio(_playerAudioSource, _audioFadeDuration));
|
||||
TweenHelper.CancelTween(ref _playerAudioFadeTweenId);
|
||||
|
||||
float startVolume = _playerAudioSource.volume;
|
||||
_playerAudioFadeTweenId = TweenHelper.FadeVolume(
|
||||
_playerAudioSource,
|
||||
0f,
|
||||
_audioFadeDuration,
|
||||
() =>
|
||||
{
|
||||
if (_playerAudioSource != null)
|
||||
{
|
||||
_playerAudioSource.Stop();
|
||||
_playerAudioSource.volume = startVolume;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (_diapasonObject != null)
|
||||
@@ -307,10 +320,13 @@ namespace Unheimlich.Gameplay.Player
|
||||
_diapasonAnimator.enabled = false;
|
||||
}
|
||||
|
||||
if (_tweenCoroutine != null)
|
||||
StopCoroutine(_tweenCoroutine);
|
||||
TweenHelper.CancelTween(ref _diapasonTweenId);
|
||||
|
||||
_tweenCoroutine = StartCoroutine(TweenDiapasonPosition(_diapasonHiddenPosition, _diapasonTweenDuration));
|
||||
_diapasonTweenId = TweenHelper.MoveLocalWithCurve(
|
||||
_diapasonObject,
|
||||
_diapasonHiddenPosition,
|
||||
_diapasonTweenDuration,
|
||||
_diapasonTweenCurve);
|
||||
}
|
||||
|
||||
if (_diapasonParticles != null)
|
||||
@@ -331,13 +347,23 @@ namespace Unheimlich.Gameplay.Player
|
||||
|
||||
if (_currentTargetEmitter != null)
|
||||
{
|
||||
_currentTargetEmitter.StopListening();
|
||||
_currentTargetEmitter.SetConcentrating(false);
|
||||
_currentTargetEmitter.StopListening(cancelConcentrationFade: false);
|
||||
_currentTargetEmitter = null;
|
||||
|
||||
StartCoroutine(ResetFadingFlagAfterDelay());
|
||||
}
|
||||
|
||||
_canUseDiapason = false;
|
||||
}
|
||||
|
||||
private IEnumerator ResetFadingFlagAfterDelay()
|
||||
{
|
||||
_isFadingOutConcentration = true;
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
_isFadingOutConcentration = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates cursor position and camera panning during listening mode.
|
||||
/// Supports both gamepad (look input) and mouse (screen edges).
|
||||
@@ -492,55 +518,20 @@ namespace Unheimlich.Gameplay.Player
|
||||
#region If needed
|
||||
private void AttenuateAmbientSound(bool enable)
|
||||
{
|
||||
if (_audioFadeCoroutine != null)
|
||||
StopCoroutine(_audioFadeCoroutine);
|
||||
TweenHelper.CancelTween(ref _audioListenerFadeTweenId);
|
||||
|
||||
_audioFadeCoroutine = StartCoroutine(FadeAmbientSound(enable));
|
||||
}
|
||||
|
||||
private IEnumerator FadeAmbientSound(bool fadeOut)
|
||||
{
|
||||
//To do : Create audio tracks
|
||||
AudioListener listener = FindFirstObjectByType<AudioListener>();
|
||||
if (listener == null)
|
||||
yield break;
|
||||
return;
|
||||
|
||||
float startVolume = AudioListener.volume;
|
||||
float targetVolume = fadeOut ? _ambientAttenuationAmount : _originalAmbientVolume;
|
||||
float targetVolume = enable ? _ambientAttenuationAmount : _originalAmbientVolume;
|
||||
|
||||
if (!fadeOut)
|
||||
_originalAmbientVolume = startVolume;
|
||||
else
|
||||
if (!enable)
|
||||
_originalAmbientVolume = AudioListener.volume;
|
||||
|
||||
float elapsed = 0f;
|
||||
while (elapsed < _audioFadeDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / _audioFadeDuration;
|
||||
AudioListener.volume = Mathf.Lerp(startVolume, targetVolume, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
AudioListener.volume = targetVolume;
|
||||
_audioListenerFadeTweenId = TweenHelper.FadeVolume(gameObject, targetVolume, _audioFadeDuration);
|
||||
}
|
||||
#endregion
|
||||
private IEnumerator FadeOutAudio(AudioSource source, float duration)
|
||||
{
|
||||
float startVolume = source.volume;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = elapsed / duration;
|
||||
source.volume = Mathf.Lerp(startVolume, 0f, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
source.Stop();
|
||||
source.volume = startVolume;
|
||||
}
|
||||
|
||||
private void EnableVignette(bool enable)
|
||||
{
|
||||
@@ -551,23 +542,6 @@ namespace Unheimlich.Gameplay.Player
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator TweenDiapasonPosition(Vector3 targetPosition, float duration, System.Action onComplete = null)
|
||||
{
|
||||
Vector3 startPosition = _diapasonObject.transform.localPosition;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = _diapasonTweenCurve.Evaluate(elapsed / duration);
|
||||
_diapasonObject.transform.localPosition = Vector3.Lerp(startPosition, targetPosition, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
_diapasonObject.transform.localPosition = targetPosition;
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (_playerCamera != null && IsListening)
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
using UnityEngine;
|
||||
using Unheimlich.Core;
|
||||
|
||||
namespace Unheimlich.Gameplay.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton player reference accessible globally throughout the game.
|
||||
/// </summary>
|
||||
public class Player : MonoBehaviour
|
||||
public class Player : Singleton<Player>
|
||||
{
|
||||
public static Player Instance { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Gameplay.Portals;
|
||||
using InputManager = Unheimlich.Managers.PlayerInputManager;
|
||||
|
||||
@@ -10,12 +11,10 @@ namespace Unheimlich.Gameplay.Player
|
||||
/// Supports both mouse and gamepad input with adaptive sensitivity.
|
||||
/// Includes aim assist for dialogue choices and camera shake effects.
|
||||
/// </summary>
|
||||
public class PlayerLook : MonoBehaviour
|
||||
public class PlayerLook : Singleton<PlayerLook>
|
||||
{
|
||||
private const float INPUT_DEADZONE = 0.1f;
|
||||
private const float MOUSE_DELTA_MULTIPLIER = 0.001f;
|
||||
|
||||
public static PlayerLook Instance { get; private set; }
|
||||
|
||||
[Header("Components")]
|
||||
[SerializeField] private Transform _playerCamera, _playerCameraPivot;
|
||||
@@ -46,15 +45,8 @@ namespace Unheimlich.Gameplay.Player
|
||||
private float _verticalRotation;
|
||||
private bool _isUsingGamepad = false;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
QualitySettings.vSyncCount = 0;
|
||||
Application.targetFrameRate = _frameRate;
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
using UnityEngine;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Managers;
|
||||
|
||||
namespace Unheimlich.Gameplay.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles player movement, jumping, and gravity using CharacterController.
|
||||
/// Provides movement state information for other systems like camera head bob.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public class PlayerMovement : MonoBehaviour
|
||||
public class PlayerMovement : Singleton<PlayerMovement>
|
||||
{
|
||||
public static PlayerMovement Instance { get; private set; }
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private float _moveSpeed = 5f;
|
||||
@@ -24,15 +20,8 @@ namespace Unheimlich.Gameplay.Player
|
||||
private float _ySpeed;
|
||||
private Vector3 _moveDirection;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
CharacterController = GetComponent<CharacterController>();
|
||||
}
|
||||
|
||||
|
||||
+18
-17
@@ -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;
|
||||
|
||||
|
||||
+20
-20
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-59
@@ -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)
|
||||
|
||||
@@ -4,6 +4,7 @@ using Unheimlich.Gameplay.Player;
|
||||
using Unheimlich.Interactions.Dialogues;
|
||||
using Unheimlich.Interactions.FloatingWords;
|
||||
using Unheimlich.Data.Dialogues;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.Managers
|
||||
{
|
||||
@@ -32,8 +33,6 @@ namespace Unheimlich.Managers
|
||||
private readonly float _focusRetentionTime;
|
||||
private readonly float _fallbackShakeIntensity;
|
||||
|
||||
private static readonly Vector3 ViewportCenter = new Vector3(0.5f, 0.5f, 0f);
|
||||
|
||||
public event Action<DialogueChoiceData> OnChoiceMade;
|
||||
|
||||
public DialogueFocusSystem(
|
||||
@@ -96,16 +95,13 @@ namespace Unheimlich.Managers
|
||||
if (_mainCamera == null)
|
||||
return;
|
||||
|
||||
Ray ray = _mainCamera.ViewportPointToRay(ViewportCenter);
|
||||
|
||||
ChoiceFocusHandler hitHandler = null;
|
||||
bool raycastHitChoice = Physics.Raycast(ray, out RaycastHit hit, _focusRange, _choiceLayer);
|
||||
|
||||
if (raycastHitChoice)
|
||||
ChoiceFocusHandler hitHandler = null;
|
||||
|
||||
if (RaycastHelper.RaycastFromCameraCenter(_mainCamera, _focusRange, _choiceLayer, out RaycastHit hit))
|
||||
{
|
||||
hitHandler = hit.collider.GetComponent<ChoiceFocusHandler>();
|
||||
|
||||
if (_playerLook != null)
|
||||
if (_playerLook != null && hitHandler != null)
|
||||
_playerLook.ApplyAimAssist(hit.collider.bounds.center);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Data.Dialogues;
|
||||
using Unheimlich.Gameplay.Player;
|
||||
using Unheimlich.UI;
|
||||
@@ -8,9 +9,8 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Unheimlich.Managers
|
||||
{
|
||||
public class DialogueManager : MonoBehaviour
|
||||
{
|
||||
public static DialogueManager Instance { get; private set; }
|
||||
public class DialogueManager : Singleton<DialogueManager>
|
||||
{
|
||||
|
||||
[Header("State")]
|
||||
public bool IsInDialogue = false;
|
||||
@@ -51,14 +51,8 @@ namespace Unheimlich.Managers
|
||||
private float _autoCloseTimer = 0f;
|
||||
private bool _isWaitingForAutoClose = false;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Gameplay.Player;
|
||||
|
||||
namespace Unheimlich.Managers
|
||||
@@ -10,7 +11,7 @@ namespace Unheimlich.Managers
|
||||
/// Supports different input contexts (Normal, Dialogue, Listening) to control which inputs are active.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(PlayerInput))]
|
||||
public class PlayerInputManager : MonoBehaviour
|
||||
public class PlayerInputManager : Singleton<PlayerInputManager>
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines different input contexts that control which player actions are enabled.
|
||||
@@ -22,8 +23,6 @@ namespace Unheimlich.Managers
|
||||
Listening // Only look enabled, movement disabled (for diapason camera pan)
|
||||
}
|
||||
|
||||
public static PlayerInputManager Instance { get; private set; }
|
||||
|
||||
[Header("Input Values (Read only)")]
|
||||
public Vector2 MoveInput;
|
||||
public Vector2 LookInput;
|
||||
@@ -44,15 +43,8 @@ namespace Unheimlich.Managers
|
||||
private PlayerLook _playerLook;
|
||||
private CameraHeadBob _headBob;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
IsInputEnabled = true;
|
||||
|
||||
PlayerInput playerInput = GetComponent<PlayerInput>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Gameplay.Portals;
|
||||
|
||||
namespace Unheimlich.Managers
|
||||
@@ -9,9 +10,8 @@ namespace Unheimlich.Managers
|
||||
/// Monitors player distance to portals and loads/unloads room instances accordingly.
|
||||
/// Supports room pooling (keeping inactive rooms in memory) and distance-based activation.
|
||||
/// </summary>
|
||||
public class PortalRoomManager : MonoBehaviour
|
||||
public class PortalRoomManager : Singleton<PortalRoomManager>
|
||||
{
|
||||
public static PortalRoomManager Instance { get; private set; }
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private float _loadDistance = 15f;
|
||||
@@ -44,16 +44,6 @@ namespace Unheimlich.Managers
|
||||
public bool BoundsCalculated = false;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_player = GameObject.FindGameObjectWithTag("Player")?.transform;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using Unheimlich.Core;
|
||||
|
||||
namespace Unheimlich.UI
|
||||
{
|
||||
[RequireComponent(typeof(Camera))]
|
||||
public class DialogueBlurEffectURP : MonoBehaviour
|
||||
public class DialogueBlurEffectURP : Singleton<DialogueBlurEffectURP>
|
||||
{
|
||||
public static DialogueBlurEffectURP Instance { get; private set; }
|
||||
|
||||
[Header("Volume Settings")]
|
||||
[SerializeField] private Volume _globalVolume;
|
||||
@@ -43,15 +43,8 @@ namespace Unheimlich.UI
|
||||
private Camera _baseCam;
|
||||
private Camera _dialogueCam;
|
||||
|
||||
void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
_baseCam = GetComponent<Camera>();
|
||||
|
||||
if (_fadeCurve == null || _fadeCurve.keys.Length == 0)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.UI
|
||||
{
|
||||
public class DialogueScreenUI : MonoBehaviour
|
||||
public class DialogueScreenUI : Singleton<DialogueScreenUI>
|
||||
{
|
||||
public static DialogueScreenUI Instance { get; private set; }
|
||||
|
||||
[Header("UI References")]
|
||||
[SerializeField] private GameObject _dialoguePanel;
|
||||
@@ -17,16 +18,8 @@ namespace Unheimlich.UI
|
||||
|
||||
private CanvasGroup _canvasGroup;
|
||||
|
||||
private void Awake()
|
||||
protected override void OnAwake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Debug.LogWarning("[DialogueScreenUI] Multiple instances detected! Destroying duplicate.");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
if (_dialoguePanel != null)
|
||||
{
|
||||
@@ -37,12 +30,6 @@ namespace Unheimlich.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
public void Show(string speaker, string dialogue)
|
||||
{
|
||||
if (_speakerText != null)
|
||||
@@ -73,18 +60,19 @@ namespace Unheimlich.UI
|
||||
{
|
||||
if (_canvasGroup != null && _dialoguePanel != null)
|
||||
{
|
||||
LeanTween.cancel(_dialoguePanel);
|
||||
LeanTween.alphaCanvas(_canvasGroup, 0f, _fadeOutDuration)
|
||||
.setOnComplete(() =>
|
||||
{
|
||||
TweenHelper.FadeCanvasGroup(
|
||||
_canvasGroup,
|
||||
0f,
|
||||
_fadeOutDuration,
|
||||
() => {
|
||||
Hide();
|
||||
onComplete?.Invoke();
|
||||
onComplete.SafeInvoke();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
onComplete?.Invoke();
|
||||
onComplete.SafeInvoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using TMPro;
|
||||
using Unheimlich.Data.Dialogues;
|
||||
using Unheimlich.Gameplay.Player;
|
||||
using Unheimlich.Interactions.FloatingWords;
|
||||
using Unheimlich.Utility;
|
||||
|
||||
namespace Unheimlich.UI
|
||||
{
|
||||
@@ -43,6 +44,10 @@ namespace Unheimlich.UI
|
||||
|
||||
private DialogueDisplayMode _currentDisplayMode = DialogueDisplayMode.World;
|
||||
|
||||
private int _fadeCanvasTweenId = -1;
|
||||
private int _rotationTweenId = -1;
|
||||
private List<int> _floatingTweenIds = new List<int>();
|
||||
|
||||
private static readonly Vector3 ViewportCenter = new Vector3(0.5f, 0.5f, 0f);
|
||||
|
||||
private void Awake()
|
||||
@@ -91,7 +96,7 @@ namespace Unheimlich.UI
|
||||
|
||||
if (_dialogueCanvasGroup != null)
|
||||
{
|
||||
LeanTween.cancel(_dialoguePanel);
|
||||
TweenHelper.CancelTween(ref _fadeCanvasTweenId);
|
||||
_dialogueCanvasGroup.alpha = 1f;
|
||||
}
|
||||
}
|
||||
@@ -125,9 +130,12 @@ namespace Unheimlich.UI
|
||||
{
|
||||
if (_dialogueCanvasGroup != null && _dialoguePanel != null)
|
||||
{
|
||||
LeanTween.cancel(_dialoguePanel);
|
||||
LeanTween.alphaCanvas(_dialogueCanvasGroup, 0f, _fadeOutDuration)
|
||||
.setOnComplete(() =>
|
||||
TweenHelper.CancelTween(ref _fadeCanvasTweenId);
|
||||
_fadeCanvasTweenId = TweenHelper.FadeCanvasGroup(
|
||||
_dialogueCanvasGroup,
|
||||
0f,
|
||||
_fadeOutDuration,
|
||||
() =>
|
||||
{
|
||||
HideDialogueBox();
|
||||
onComplete?.Invoke();
|
||||
@@ -247,35 +255,18 @@ namespace Unheimlich.UI
|
||||
|
||||
float amplitude = _currentAnimationSettings.FloatingAmplitude;
|
||||
float duration = _currentAnimationSettings.FloatingDuration;
|
||||
float offset = index * 0.2f;
|
||||
float delay = index * 0.2f;
|
||||
|
||||
Vector3 startPos = choice.transform.localPosition;
|
||||
|
||||
LeanTween.value(choice, 0f, Mathf.PI * 2f, duration)
|
||||
.setDelay(offset)
|
||||
.setOnUpdate((float val) => {
|
||||
if (choice != null)
|
||||
{
|
||||
Vector3 newPos = startPos;
|
||||
newPos.y += Mathf.Sin(val) * amplitude;
|
||||
choice.transform.localPosition = newPos;
|
||||
}
|
||||
})
|
||||
.setLoopClamp()
|
||||
.setEase(LeanTweenType.linear);
|
||||
int tweenId = TweenHelper.FloatAnimation(choice, startPos, amplitude, duration, delay, Axis.Y);
|
||||
_floatingTweenIds.Add(tweenId);
|
||||
}
|
||||
|
||||
public void RotationAnimation(float degreesPerSecond = 60f)
|
||||
{
|
||||
if (degreesPerSecond <= 0f)
|
||||
return;
|
||||
|
||||
float duration = 360f / degreesPerSecond;
|
||||
|
||||
LeanTween.cancel(ChoiceContainer);
|
||||
LeanTween.rotateAroundLocal(ChoiceContainer, _currentRotationAxis, 360f, duration)
|
||||
.setLoopClamp()
|
||||
.setEase(LeanTweenType.linear);
|
||||
TweenHelper.CancelTween(ref _rotationTweenId);
|
||||
_rotationTweenId = TweenHelper.RotateAround(ChoiceContainer, _currentRotationAxis, degreesPerSecond);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -318,10 +309,17 @@ namespace Unheimlich.UI
|
||||
_currentAnchor = null;
|
||||
_currentAnimationSettings = null;
|
||||
_activeChoices.Clear();
|
||||
LeanTween.cancel(ChoiceContainer);
|
||||
|
||||
TweenHelper.CancelTween(ref _rotationTweenId);
|
||||
foreach (int tweenId in _floatingTweenIds)
|
||||
{
|
||||
int id = tweenId;
|
||||
TweenHelper.CancelTween(ref id);
|
||||
}
|
||||
_floatingTweenIds.Clear();
|
||||
|
||||
foreach (Transform child in ChoiceContainer.transform)
|
||||
{
|
||||
LeanTween.cancel(child.gameObject);
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unheimlich.Utility
|
||||
{
|
||||
public static class RaycastHelper
|
||||
{
|
||||
private static readonly Vector3 ViewportCenter = new Vector3(0.5f, 0.5f, 0f);
|
||||
|
||||
public static bool RaycastFromCameraCenter(Camera camera, float maxDistance,
|
||||
LayerMask layerMask, out RaycastHit hit)
|
||||
{
|
||||
if (camera == null)
|
||||
{
|
||||
hit = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
Ray ray = camera.ViewportPointToRay(ViewportCenter);
|
||||
return Physics.Raycast(ray, out hit, maxDistance, layerMask);
|
||||
}
|
||||
|
||||
public static bool RaycastFromCameraCenter<T>(Camera camera, float maxDistance,
|
||||
LayerMask layerMask, out T component) where T : Component
|
||||
{
|
||||
component = null;
|
||||
|
||||
if (RaycastFromCameraCenter(camera, maxDistance, layerMask, out RaycastHit hit))
|
||||
{
|
||||
component = hit.collider.GetComponent<T>();
|
||||
return component != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ThrottledRaycast(ref float timer, float interval,
|
||||
Camera camera, float maxDistance, LayerMask layerMask, out RaycastHit hit)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
|
||||
if (timer >= interval)
|
||||
{
|
||||
timer = 0f;
|
||||
return RaycastFromCameraCenter(camera, maxDistance, layerMask, out hit);
|
||||
}
|
||||
|
||||
hit = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ThrottledRaycastComponent<T>(ref float timer, float interval,
|
||||
Camera camera, float maxDistance, LayerMask layerMask, out T component) where T : Component
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
|
||||
if (timer >= interval)
|
||||
{
|
||||
timer = 0f;
|
||||
return RaycastFromCameraCenter(camera, maxDistance, layerMask, out component);
|
||||
}
|
||||
|
||||
component = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f37b9866154109148b3f7d2d3c121c36
|
||||
@@ -0,0 +1,224 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
namespace Unheimlich.Utility
|
||||
{
|
||||
public static class TweenHelper
|
||||
{
|
||||
public static int FadeCanvasGroup(CanvasGroup canvasGroup, float targetAlpha,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInQuad)
|
||||
{
|
||||
if (canvasGroup == null) return -1;
|
||||
|
||||
LeanTween.cancel(canvasGroup.gameObject);
|
||||
return LeanTween.alphaCanvas(canvasGroup, targetAlpha, duration)
|
||||
.setEase(easeType)
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int FadeText(TextMeshProUGUI text, float targetAlpha,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInQuad)
|
||||
{
|
||||
return FadeText(text?.gameObject, text, null, targetAlpha, duration, 1f, onComplete, easeType);
|
||||
}
|
||||
|
||||
public static int FadeText(GameObject targetObject, TextMeshProUGUI mainText,
|
||||
TextMeshProUGUI ghostText, float targetAlpha, float duration,
|
||||
float ghostAlphaRatio, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInQuad)
|
||||
{
|
||||
if (mainText == null || targetObject == null) return -1;
|
||||
|
||||
float startAlpha = mainText.color.a;
|
||||
LeanTween.cancel(targetObject);
|
||||
|
||||
return LeanTween.value(targetObject, startAlpha, targetAlpha, duration)
|
||||
.setEase(easeType)
|
||||
.setOnUpdate((float val) => {
|
||||
if (mainText != null)
|
||||
{
|
||||
Color c = mainText.color;
|
||||
c.a = val;
|
||||
mainText.color = c;
|
||||
}
|
||||
|
||||
if (ghostText != null)
|
||||
{
|
||||
Color gc = ghostText.color;
|
||||
gc.a = val * ghostAlphaRatio;
|
||||
ghostText.color = gc;
|
||||
}
|
||||
})
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int ScaleLocal(GameObject target, Vector3 targetScale,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInOutQuad)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
return LeanTween.scale(target, targetScale, duration)
|
||||
.setEase(easeType)
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int MoveLocal(GameObject target, Vector3 targetPosition,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInOutQuad)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
return LeanTween.moveLocal(target, targetPosition, duration)
|
||||
.setEase(easeType)
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int RotateLocal(GameObject target, Vector3 targetRotation,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInOutQuad)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
return LeanTween.rotate(target, targetRotation, duration)
|
||||
.setEase(easeType)
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int MoveLocalWithCurve(GameObject target, Vector3 targetPosition,
|
||||
float duration, AnimationCurve curve, System.Action onComplete = null)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
return LeanTween.moveLocal(target, targetPosition, duration)
|
||||
.setEase(curve)
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int FadeVolume(AudioSource source, float targetVolume,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInOutQuad)
|
||||
{
|
||||
if (source == null) return -1;
|
||||
|
||||
GameObject sourceObject = source.gameObject;
|
||||
LeanTween.cancel(sourceObject);
|
||||
|
||||
return LeanTween.value(sourceObject, source.volume, targetVolume, duration)
|
||||
.setEase(easeType)
|
||||
.setOnUpdate((float val) => {
|
||||
if (source != null)
|
||||
source.volume = val;
|
||||
})
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int FadeVolume(GameObject target, float targetVolume,
|
||||
float duration, System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.linear)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
float startVolume = AudioListener.volume;
|
||||
LeanTween.cancel(target);
|
||||
|
||||
return LeanTween.value(target, startVolume, targetVolume, duration)
|
||||
.setEase(easeType)
|
||||
.setOnUpdate((float val) => {
|
||||
AudioListener.volume = val;
|
||||
})
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int FloatAnimation(GameObject target, Vector3 basePosition,
|
||||
float amplitude, float duration, float delay = 0f, Axis axis = Axis.Y)
|
||||
{
|
||||
if (target == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
|
||||
return LeanTween.value(target, 0f, Mathf.PI * 2f, duration)
|
||||
.setDelay(delay)
|
||||
.setOnUpdate((float val) => {
|
||||
if (target != null)
|
||||
{
|
||||
Vector3 newPos = basePosition;
|
||||
float offset = Mathf.Sin(val) * amplitude;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case Axis.X: newPos.x += offset; break;
|
||||
case Axis.Y: newPos.y += offset; break;
|
||||
case Axis.Z: newPos.z += offset; break;
|
||||
}
|
||||
|
||||
target.transform.localPosition = newPos;
|
||||
}
|
||||
})
|
||||
.setLoopClamp()
|
||||
.setEase(LeanTweenType.linear)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int RotateAround(GameObject target, Vector3 axis, float degreesPerSecond)
|
||||
{
|
||||
if (target == null || degreesPerSecond <= 0f) return -1;
|
||||
|
||||
float duration = 360f / degreesPerSecond;
|
||||
LeanTween.cancel(target);
|
||||
|
||||
return LeanTween.rotateAroundLocal(target, axis, 360f, duration)
|
||||
.setLoopClamp()
|
||||
.setEase(LeanTweenType.linear)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static int AnimateMaterialFloat(GameObject target, Material material,
|
||||
int propertyID, float fromValue, float toValue, float duration,
|
||||
System.Action onComplete = null,
|
||||
LeanTweenType easeType = LeanTweenType.easeInOutQuad)
|
||||
{
|
||||
if (target == null || material == null) return -1;
|
||||
|
||||
LeanTween.cancel(target);
|
||||
|
||||
return LeanTween.value(target, fromValue, toValue, duration)
|
||||
.setEase(easeType)
|
||||
.setOnUpdate((float val) => {
|
||||
if (material != null)
|
||||
material.SetFloat(propertyID, val);
|
||||
})
|
||||
.setOnComplete(onComplete)
|
||||
.id;
|
||||
}
|
||||
|
||||
public static void CancelTween(ref int tweenId)
|
||||
{
|
||||
if (tweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(tweenId);
|
||||
tweenId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum Axis
|
||||
{
|
||||
X, Y, Z
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f70df97fd94f86a4aa2cb00353624ba4
|
||||
@@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unheimlich.Utility
|
||||
{
|
||||
public static class UnityExtensions
|
||||
{
|
||||
public static void SafeInvoke(this System.Action action)
|
||||
{
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
public static void SafeInvoke<T>(this System.Action<T> action, T arg)
|
||||
{
|
||||
action?.Invoke(arg);
|
||||
}
|
||||
|
||||
public static Color WithAlpha(this Color color, float alpha)
|
||||
{
|
||||
color.a = alpha;
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Vector3 WithY(this Vector3 vector, float y)
|
||||
{
|
||||
vector.y = y;
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static Vector3 WithX(this Vector3 vector, float x)
|
||||
{
|
||||
vector.x = x;
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static Vector3 WithZ(this Vector3 vector, float z)
|
||||
{
|
||||
vector.z = z;
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static void CancelAllTweens(this GameObject gameObject)
|
||||
{
|
||||
if (gameObject != null)
|
||||
LeanTween.cancel(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5c8821940a7678458f26015ee167fdf
|
||||
Reference in New Issue
Block a user