Update diapason mechanics

This commit is contained in:
2026-01-28 22:03:36 +01:00
parent bef8c6ef94
commit dcac15b3f2
35 changed files with 2461 additions and 116 deletions
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cd7d5d5d18db5a3458126a3a50a037b2
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 277628261bc57bc4098a8069501666f9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -22,6 +22,11 @@ namespace Unheimlich.Gameplay.Player
[SerializeField] private float _concentrationDuration = 1f;
[SerializeField] private float _breathInDuration = 0.5f;
[Header("Diapason Animation")]
[SerializeField] private float _diapasonTweenDuration = 0.3f;
[SerializeField] private float _diapasonHideOffset = -0.5f;
[SerializeField] private AnimationCurve _diapasonTweenCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
[Header("Camera Settings")]
[SerializeField] private float _cameraPanSpeed = 2f;
[SerializeField] private float _cameraPanBorderSize = 0.1f;
@@ -35,9 +40,12 @@ namespace Unheimlich.Gameplay.Player
[SerializeField] private AudioClip _breathInClip;
[SerializeField] private AudioClip _diapasonTapClip;
[SerializeField] private float _ambientAttenuationAmount = 0.3f;
[SerializeField] private float _audioFadeDuration = 0.5f;
[Header("Input Action")]
[SerializeField] private InputActionReference _diapasonAction;
[SerializeField] private InputActionReference _lookAction;
[SerializeField] private InputActionReference _fireAction;
public bool IsListening { get; private set; }
public bool IsConcentrating { get; private set; }
@@ -45,8 +53,13 @@ namespace Unheimlich.Gameplay.Player
private AudioListenable _currentTargetEmitter;
private AudioSource _playerAudioSource;
private Coroutine _listeningCoroutine;
private Coroutine _tweenCoroutine;
private Coroutine _audioFadeCoroutine;
private Vector2 _originalCameraRotation;
private float _originalAmbientVolume;
private Vector3 _diapasonEquippedPosition;
private Vector3 _diapasonHiddenPosition;
private bool _movementDisabled;
private const string ANIM_TRIGGER_TAP = "Tap";
private const string ANIM_BOOL_EQUIPPED = "IsEquipped";
@@ -65,19 +78,31 @@ namespace Unheimlich.Gameplay.Player
_playerAudioSource = gameObject.AddComponent<AudioSource>();
if (_diapasonObject != null)
{
_diapasonEquippedPosition = _diapasonObject.transform.localPosition;
_diapasonHiddenPosition = _diapasonEquippedPosition + Vector3.up * _diapasonHideOffset;
_diapasonObject.transform.localPosition = _diapasonHiddenPosition;
_diapasonObject.SetActive(false);
}
if (_diapasonAction == null)
{
Debug.LogError("[Diapason] _diapasonAction is NOT assigned! Please assign it in the Inspector.");
}
else
{
Debug.Log($"[Diapason] _diapasonAction assigned: {_diapasonAction.action.name}");
}
}
private void Update()
{
if (!InputManager.IsInputEnabled)
return;
if (_diapasonAction != null && _diapasonAction.action.WasPressedThisFrame())
{
Debug.Log($"[Diapason] Action pressed! IsListening={IsListening}, IsConcentrating={IsConcentrating}");
if (!IsListening && !IsConcentrating)
StartListeningMode();
else if (IsListening)
else if (IsListening || IsConcentrating)
StopListeningMode();
}
@@ -85,6 +110,7 @@ namespace Unheimlich.Gameplay.Player
{
UpdateCursorAndCameraPan();
CheckForListenableObject();
Debug.Log("Listening");
}
}
@@ -98,30 +124,43 @@ namespace Unheimlich.Gameplay.Player
private IEnumerator ListeningSequence()
{
Debug.Log("[Diapason] ListeningSequence START");
IsConcentrating = true;
InputManager.ToggleInput(false);
DisablePlayerMovement(true);
if (_diapasonObject != null)
{
_diapasonObject.SetActive(true);
if (_diapasonAnimator != null)
_diapasonAnimator.SetBool(ANIM_BOOL_EQUIPPED, true);
if (_tweenCoroutine != null)
StopCoroutine(_tweenCoroutine);
_tweenCoroutine = StartCoroutine(TweenDiapasonPosition(_diapasonEquippedPosition, _diapasonTweenDuration));
}
Debug.Log($"[Diapason] Playing breath in, waiting {_breathInDuration}s");
PlayBreathIn();
yield return new WaitForSeconds(_breathInDuration);
Debug.Log($"[Diapason] Concentrating, waiting {_concentrationDuration - _breathInDuration}s");
yield return new WaitForSeconds(_concentrationDuration - _breathInDuration);
Debug.Log("[Diapason] Setting IsListening = TRUE");
IsConcentrating = false;
IsListening = true;
_originalCameraRotation = new Vector2(transform.eulerAngles.y, _playerCamera.transform.eulerAngles.x);
float currentPitch = _playerCamera.transform.localEulerAngles.x;
if (currentPitch > 180f)
currentPitch -= 360f;
_originalCameraRotation = new Vector2(transform.eulerAngles.y, currentPitch);
AttenuateAmbientSound(true);
EnableVignette(true);
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = true;
Cursor.visible = false;
Debug.Log("[Diapason] ListeningSequence COMPLETE");
}
private void StopListeningMode()
@@ -135,11 +174,21 @@ namespace Unheimlich.Gameplay.Player
IsListening = false;
IsConcentrating = false;
if (_playerAudioSource != null && _playerAudioSource.isPlaying)
{
if (_audioFadeCoroutine != null)
StopCoroutine(_audioFadeCoroutine);
_audioFadeCoroutine = StartCoroutine(FadeOutAudio(_playerAudioSource, _audioFadeDuration));
}
if (_diapasonObject != null)
{
if (_diapasonAnimator != null)
_diapasonAnimator.SetBool(ANIM_BOOL_EQUIPPED, false);
_diapasonObject.SetActive(false);
if (_tweenCoroutine != null)
StopCoroutine(_tweenCoroutine);
_tweenCoroutine = StartCoroutine(TweenDiapasonPosition(_diapasonHiddenPosition, _diapasonTweenDuration, () => _diapasonObject.SetActive(false)));
}
AttenuateAmbientSound(false);
@@ -148,7 +197,7 @@ namespace Unheimlich.Gameplay.Player
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
InputManager.ToggleInput(true);
DisablePlayerMovement(false);
if (_currentTargetEmitter != null)
{
@@ -162,34 +211,49 @@ namespace Unheimlich.Gameplay.Player
if (_playerCamera == null)
return;
Vector2 viewportPos = _playerCamera.ScreenToViewportPoint(Mouse.current.position.ReadValue());
float panX = 0f;
float panY = 0f;
if (viewportPos.x < _cameraPanBorderSize)
panX = -1f;
else if (viewportPos.x > 1f - _cameraPanBorderSize)
panX = 1f;
if (_lookAction != null && _lookAction.action != null)
{
Vector2 lookInput = _lookAction.action.ReadValue<Vector2>();
if (lookInput.sqrMagnitude > 0.01f)
{
panX = lookInput.x;
panY = lookInput.y;
}
}
if (viewportPos.y < _cameraPanBorderSize)
panY = -1f;
else if (viewportPos.y > 1f - _cameraPanBorderSize)
panY = 1f;
if (panX == 0f && panY == 0f && Mouse.current != null)
{
Vector2 viewportPos = _playerCamera.ScreenToViewportPoint(Mouse.current.position.ReadValue());
if (viewportPos.x < _cameraPanBorderSize)
panX = -1f;
else if (viewportPos.x > 1f - _cameraPanBorderSize)
panX = 1f;
if (viewportPos.y < _cameraPanBorderSize)
panY = -1f;
else if (viewportPos.y > 1f - _cameraPanBorderSize)
panY = 1f;
}
float targetYaw = _originalCameraRotation.x + (panX * _maxCameraPanAngle);
float targetPitch = _originalCameraRotation.y - (panY * _maxCameraPanAngle);
targetYaw = Mathf.Clamp(targetYaw, _originalCameraRotation.x - _maxCameraPanAngle, _originalCameraRotation.x + _maxCameraPanAngle);
targetPitch = Mathf.Clamp(targetPitch, _originalCameraRotation.y - _maxCameraPanAngle, _originalCameraRotation.y + _maxCameraPanAngle);
targetPitch = Mathf.Clamp(targetPitch, -89f, 89f);
Vector3 currentRotation = transform.eulerAngles;
currentRotation.y = Mathf.Lerp(currentRotation.y, targetYaw, Time.deltaTime * _cameraPanSpeed);
currentRotation.y = Mathf.LerpAngle(currentRotation.y, targetYaw, Time.deltaTime * _cameraPanSpeed);
transform.eulerAngles = currentRotation;
Vector3 cameraRotation = _playerCamera.transform.localEulerAngles;
if (cameraRotation.x > 180f)
cameraRotation.x -= 360f;
cameraRotation.x = Mathf.Lerp(cameraRotation.x, targetPitch, Time.deltaTime * _cameraPanSpeed);
cameraRotation.x = Mathf.LerpAngle(cameraRotation.x, targetPitch, Time.deltaTime * _cameraPanSpeed);
_playerCamera.transform.localEulerAngles = cameraRotation;
}
@@ -198,23 +262,47 @@ namespace Unheimlich.Gameplay.Player
if (_playerCamera == null)
return;
Ray ray = _playerCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
Ray ray = _playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
if (Physics.Raycast(ray, out RaycastHit hit, _listeningRange, _listenableLayers))
{
Debug.Log($"Raycast hit: {hit.collider.gameObject.name}");
AudioListenable listenable = hit.collider.GetComponent<AudioListenable>();
if (listenable != null && listenable != _currentTargetEmitter)
if (listenable != null)
{
if (_currentTargetEmitter != null)
_currentTargetEmitter.StopListening();
Debug.Log($"AudioListenable found on {hit.collider.gameObject.name}!");
if (listenable != _currentTargetEmitter)
{
if (_currentTargetEmitter != null)
_currentTargetEmitter.StopListening();
_currentTargetEmitter = listenable;
_currentTargetEmitter = listenable;
Debug.Log($"_currentTargetEmitter set to {hit.collider.gameObject.name}");
}
}
else
{
Debug.LogWarning($"Raycast hit {hit.collider.gameObject.name} but NO AudioListenable found!");
}
if (Mouse.current.leftButton.wasPressedThisFrame && _currentTargetEmitter != null)
bool firePressed = false;
if (_fireAction != null && _fireAction.action != null && _fireAction.action.WasPressedThisFrame())
{
TriggerDiapasonTap();
firePressed = true;
}
else if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
{
firePressed = true;
}
if (firePressed)
{
Debug.Log($"Fire/Click detected! _currentTargetEmitter = {(_currentTargetEmitter != null ? _currentTargetEmitter.gameObject.name : "NULL")}");
if (_currentTargetEmitter != null)
{
TriggerDiapasonTap();
}
}
}
else
@@ -229,6 +317,8 @@ namespace Unheimlich.Gameplay.Player
private void TriggerDiapasonTap()
{
Debug.Log("[Diapason] TriggerDiapasonTap called!");
if (_diapasonAnimator != null)
_diapasonAnimator.SetTrigger(ANIM_TRIGGER_TAP);
@@ -236,7 +326,14 @@ namespace Unheimlich.Gameplay.Player
_playerAudioSource.PlayOneShot(_diapasonTapClip);
if (_currentTargetEmitter != null)
{
Debug.Log($"[Diapason] Starting listening on {_currentTargetEmitter.gameObject.name}");
_currentTargetEmitter.StartListening(transform.position);
}
else
{
Debug.LogWarning("[Diapason] TriggerDiapasonTap called but _currentTargetEmitter is NULL!");
}
}
private void PlayBreathIn()
@@ -246,20 +343,54 @@ namespace Unheimlich.Gameplay.Player
}
private void AttenuateAmbientSound(bool enable)
{
if (_audioFadeCoroutine != null)
StopCoroutine(_audioFadeCoroutine);
_audioFadeCoroutine = StartCoroutine(FadeAmbientSound(enable));
}
private IEnumerator FadeAmbientSound(bool fadeOut)
{
AudioListener listener = FindFirstObjectByType<AudioListener>();
if (listener != null)
if (listener == null)
yield break;
float startVolume = AudioListener.volume;
float targetVolume = fadeOut ? _ambientAttenuationAmount : _originalAmbientVolume;
if (!fadeOut)
_originalAmbientVolume = startVolume;
else
_originalAmbientVolume = AudioListener.volume;
float elapsed = 0f;
while (elapsed < _audioFadeDuration)
{
if (enable)
{
_originalAmbientVolume = AudioListener.volume;
AudioListener.volume = _ambientAttenuationAmount;
}
else
{
AudioListener.volume = _originalAmbientVolume;
}
elapsed += Time.deltaTime;
float t = elapsed / _audioFadeDuration;
AudioListener.volume = Mathf.Lerp(startVolume, targetVolume, t);
yield return null;
}
AudioListener.volume = targetVolume;
}
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)
@@ -271,12 +402,49 @@ 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 DisablePlayerMovement(bool disable)
{
if (_movementDisabled == disable)
return;
_movementDisabled = disable;
PlayerMovement playerMovement = GetComponent<PlayerMovement>();
if (playerMovement != null)
playerMovement.enabled = !disable;
PlayerLook playerLook = GetComponent<PlayerLook>();
if (playerLook != null)
playerLook.enabled = !disable;
CameraHeadBob headBob = GetComponentInChildren<CameraHeadBob>();
if (headBob != null)
headBob.enabled = !disable;
}
private void OnDrawGizmosSelected()
{
if (_playerCamera != null && IsListening)
{
Gizmos.color = _currentTargetEmitter != null ? Color.green : Color.yellow;
Ray ray = _playerCamera.ScreenPointToRay(Mouse.current != null ? Mouse.current.position.ReadValue() : Vector2.zero);
Ray ray = _playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
Gizmos.DrawRay(ray.origin, ray.direction * _listeningRange);
}
}
@@ -7,41 +7,65 @@ namespace Unheimlich.Gameplay.Player
public class ListeningVignetteEffect : MonoBehaviour
{
[Header("References")]
[SerializeField] private Volume _globalVolume;
[Tooltip("Dedicated Volume for listening mode (not shared with dialogue system)")]
[SerializeField] private Volume _listeningVolume;
[Header("Settings")]
[SerializeField] private float _targetIntensity = 0.5f;
[SerializeField] private float _transitionSpeed = 2f;
private Vignette _vignette;
private float _originalIntensity;
private bool _isEnabled;
private VolumeProfile _volumeProfile;
private void Awake()
{
if (_globalVolume == null)
_globalVolume = FindFirstObjectByType<Volume>();
if (_globalVolume != null && _globalVolume.profile != null)
if (_listeningVolume == null)
{
if (_globalVolume.profile.TryGet(out Vignette vignette))
GameObject volumeObject = new GameObject("Listening Mode Volume");
volumeObject.transform.SetParent(transform);
_listeningVolume = volumeObject.AddComponent<Volume>();
_listeningVolume.isGlobal = true;
_listeningVolume.priority = 1;
_listeningVolume.weight = 0f;
}
if (_listeningVolume.profile == null)
{
_volumeProfile = ScriptableObject.CreateInstance<VolumeProfile>();
_listeningVolume.profile = _volumeProfile;
_vignette = _volumeProfile.Add<Vignette>();
_vignette.active = true;
_vignette.intensity.Override(0f);
_vignette.smoothness.Override(0.4f);
_vignette.rounded.Override(true);
}
else
{
if (!_listeningVolume.profile.TryGet(out _vignette))
{
_vignette = vignette;
_originalIntensity = _vignette.intensity.value;
_vignette = _listeningVolume.profile.Add<Vignette>();
_vignette.active = true;
_vignette.intensity.Override(0f);
_vignette.smoothness.Override(0.4f);
_vignette.rounded.Override(true);
}
}
_listeningVolume.weight = 0f;
}
private void Update()
{
if (_vignette == null)
if (_vignette == null || _listeningVolume == null)
return;
float targetValue = _isEnabled ? _targetIntensity : _originalIntensity;
float currentValue = _vignette.intensity.value;
float newValue = Mathf.Lerp(currentValue, targetValue, Time.deltaTime * _transitionSpeed);
_vignette.intensity.value = newValue;
float targetWeight = _isEnabled ? 1f : 0f;
_listeningVolume.weight = Mathf.Lerp(_listeningVolume.weight, targetWeight, Time.deltaTime * _transitionSpeed);
if (_isEnabled)
_vignette.intensity.value = _targetIntensity;
}
public void EnableVignette(bool enable)
@@ -52,6 +76,14 @@ namespace Unheimlich.Gameplay.Player
public void SetIntensity(float intensity)
{
_targetIntensity = Mathf.Clamp01(intensity);
if (_vignette != null)
_vignette.intensity.value = _targetIntensity;
}
private void OnDestroy()
{
if (_volumeProfile != null)
Destroy(_volumeProfile);
}
}
}