chore: Project Restructuring & Theatre

This commit is contained in:
Alexandre Coirier
2026-05-13 12:24:48 +02:00
parent 4070916c1f
commit e96d0bf6e6
2145 changed files with 20957 additions and 44792 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e871b828a2e9ca4ba7cc5e025373372
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,37 @@
using UnityEngine;
namespace Unheimlich.Features.Diapason
{
[System.Serializable]
public class TapAnimationSettings
{
[Header("Tap Motion")]
[Tooltip("Elbow rotation during windup (degrees)")]
public float WindupRotation = 15f;
[Tooltip("Duration of windup (pull back)")]
public float WindupDuration = 0.1f;
[Tooltip("Duration of strike (forward snap)")]
public float StrikeDuration = 0.05f;
[Tooltip("Wrist snap rotation during strike (degrees)")]
public float WristSnapRotation = 10f;
[Header("Vibration Shake")]
[Tooltip("Shake intensity during vibration")]
public float ShakeIntensity = 2f;
[Tooltip("Shake speed (frequency)")]
public float ShakeSpeed = 30f;
}
public class EquippableTapSettings : MonoBehaviour
{
[SerializeField] private TapAnimationSettings _tapSettings = new TapAnimationSettings();
public TapAnimationSettings TapSettings => _tapSettings;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b46af809fa8f34d49b3dec606a505c5e
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: adbe6317f6c8e9e469b36e06ab2abbfb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,379 @@
using UnityEngine;
using Unheimlich.Core;
using Unheimlich.Core.Audio;
using Unheimlich.Features.OctoArms;
using InputManager = Unheimlich.Core.Input.InputManager;
using System;
using System.Collections;
namespace Unheimlich.Features.Diapason
{
public class DiapasonEquipmentManager : MonoBehaviour
{
[Header("References")]
[SerializeField] private OctoIkArmsImproved _armsSystem;
[SerializeField] private GameObject _diapasonPrefab;
[SerializeField] private int _equipmentArmIndex = 1;
[Header("Detection Settings")]
[SerializeField] private LayerMask _soundEmitterLayer;
[SerializeField] private float _detectionRadius = 0.15f;
[SerializeField] private Transform[] _detectionPoints;
[Header("Visual Feedback")]
[SerializeField] private GameObject _contactFeedbackPrefab;
[Header("Diapason Animation")]
[SerializeField] private string _vibratingBoolParam = "IsVibrating";
[SerializeField] private string _tapTriggerParam = "Tap";
[Header("Tap Settings")]
[SerializeField] private AudioClip _tapSound;
[SerializeField] [Range(0f, 1f)] private float _tapVolume = 1f;
[SerializeField] private float _vibrationDuration = 15f;
public bool IsEquipped => _isEquipped;
public AudioListenable CurrentDetectedEmitter => _currentDetectedEmitter;
public bool CanTap => _isEquipped && _currentDetectedEmitter != null && !_isVibrating && !_currentDetectedEmitter.HasBeenTapped;
public event Action<AudioListenable> OnEmitterDetected;
public event Action<AudioListenable> OnEmitterLost;
private GameObject _spawnedDiapason;
private bool _isEquipped = false;
private AudioListenable _currentDetectedEmitter;
private GameObject _contactFeedback;
private bool _isVibrating = false;
private AudioSource _audioSource;
private Coroutine _vibrationCoroutine;
private Animator _diapasonAnimator;
private ParticleSystem _diapasonParticles;
void Awake()
{
if (_armsSystem == null)
{
_armsSystem = GetComponent<OctoIkArmsImproved>();
if (_armsSystem == null)
{
Debug.LogError("[DiapasonEquipment] OctoIkArmsImproved not found!");
}
}
_audioSource = GetComponent<AudioSource>();
if (_audioSource == null)
{
_audioSource = gameObject.AddComponent<AudioSource>();
}
}
void Update()
{
if (_isEquipped && _armsSystem.GetArmState(_equipmentArmIndex) == ArmState.Equipped)
{
CheckForSoundEmitters();
var fireAction = InputManager.GetFireAction();
if (fireAction != null && fireAction.WasPressedThisFrame())
{
if (CanTap)
TapDiapason();
}
}
}
public void EquipDiapason()
{
if (_isEquipped)
{
Debug.LogWarning("[DiapasonEquipment] Diapason already equipped!");
return;
}
if (_diapasonPrefab == null)
{
Debug.LogError("[DiapasonEquipment] Diapason prefab not assigned!");
return;
}
_spawnedDiapason = Instantiate(_diapasonPrefab);
_spawnedDiapason.SetActive(true);
_diapasonAnimator = _spawnedDiapason.GetComponentInChildren<Animator>(true);
if (_diapasonAnimator == null)
{
Debug.LogWarning("[DiapasonEquipment] No Animator found on spawned diapason");
}
else
{
_diapasonAnimator.enabled = false;
}
_diapasonParticles = _spawnedDiapason.GetComponentInChildren<ParticleSystem>(true);
if (_diapasonParticles == null)
{
Debug.LogWarning("[DiapasonEquipment] No ParticleSystem found on spawned diapason");
}
_armsSystem.EquipObjectOnArm(_equipmentArmIndex, _spawnedDiapason, () => {
_isEquipped = true;
OnDiapasonEquipped();
});
}
public void UnequipDiapason()
{
if (!_isEquipped)
{
Debug.LogWarning("[DiapasonEquipment] Diapason not equipped!");
return;
}
if (_vibrationCoroutine != null)
{
StopCoroutine(_vibrationCoroutine);
_vibrationCoroutine = null;
}
if (_currentDetectedEmitter != null)
{
_currentDetectedEmitter.SetConcentrating(false);
_currentDetectedEmitter.StopListening(cancelConcentrationFade: false);
_currentDetectedEmitter = null;
}
_armsSystem.UnequipObjectFromArm(_equipmentArmIndex, () => {
_isEquipped = false;
_spawnedDiapason = null;
OnDiapasonUnequipped();
});
}
private void CheckForSoundEmitters()
{
if (_detectionPoints == null || _detectionPoints.Length == 0)
return;
AudioListenable closestEmitter = null;
float closestDistance = float.MaxValue;
foreach (Transform detectionPoint in _detectionPoints)
{
if (detectionPoint == null)
continue;
Collider[] hits = Physics.OverlapSphere(detectionPoint.position, _detectionRadius, _soundEmitterLayer);
foreach (Collider hit in hits)
{
AudioListenable emitter = hit.GetComponent<AudioListenable>();
if (emitter != null)
{
float distance = Vector3.Distance(detectionPoint.position, hit.transform.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestEmitter = emitter;
}
}
}
}
if (closestEmitter != _currentDetectedEmitter)
{
if (_currentDetectedEmitter != null)
{
OnEmitterExited(_currentDetectedEmitter);
}
_currentDetectedEmitter = closestEmitter;
if (_currentDetectedEmitter != null)
{
OnEmitterEntered(_currentDetectedEmitter);
}
}
}
private void OnDiapasonEquipped()
{
PlayerEvents.TriggerDiapasonEquip();
if (_diapasonAnimator != null)
{
_diapasonAnimator.enabled = true;
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
}
if (_diapasonParticles != null)
{
_diapasonParticles.Stop();
var emission = _diapasonParticles.emission;
emission.enabled = false;
}
}
private void OnDiapasonUnequipped()
{
PlayerEvents.TriggerDiapasonUnequip();
_isVibrating = false;
_diapasonAnimator = null;
_diapasonParticles = null;
}
public void TapDiapason()
{
if (!CanTap)
{
Debug.LogWarning("[DiapasonEquipment] Cannot tap: not equipped, no contact, or already tapped");
return;
}
TapAnimationSettings tapSettings = null;
if (_spawnedDiapason != null)
{
EquippableTapSettings equippable = _spawnedDiapason.GetComponent<EquippableTapSettings>();
if (equippable != null)
{
tapSettings = equippable.TapSettings;
}
}
ArmEquipment equipment = _armsSystem.GetArmEquipment(_equipmentArmIndex);
if (equipment != null && tapSettings != null)
{
equipment.PlayTapAnimation(tapSettings);
equipment.StartShake(tapSettings);
}
if (_tapSound != null && _audioSource != null)
{
_audioSource.PlayOneShot(_tapSound, _tapVolume);
}
if (_diapasonAnimator != null)
{
_diapasonAnimator.SetTrigger(_tapTriggerParam);
_diapasonAnimator.SetBool(_vibratingBoolParam, true);
}
if (_diapasonParticles != null)
{
var emission = _diapasonParticles.emission;
emission.enabled = true;
_diapasonParticles.Play();
}
_isVibrating = true;
if (_currentDetectedEmitter != null)
{
_currentDetectedEmitter.StartListening(transform.position);
}
PlayerEvents.TriggerDiapasonTap();
if (_vibrationCoroutine != null)
StopCoroutine(_vibrationCoroutine);
_vibrationCoroutine = StartCoroutine(StopVibrationAfterDuration());
}
private IEnumerator StopVibrationAfterDuration()
{
yield return new WaitForSeconds(_vibrationDuration);
if (_diapasonAnimator != null)
{
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
}
if (_diapasonParticles != null)
{
_diapasonParticles.Stop();
var emission = _diapasonParticles.emission;
emission.enabled = false;
}
if (_currentDetectedEmitter != null)
{
_currentDetectedEmitter.StopListening();
}
ArmEquipment equipment = _armsSystem.GetArmEquipment(_equipmentArmIndex);
if (equipment != null)
{
equipment.StopShake();
}
_isVibrating = false;
_vibrationCoroutine = null;
}
private void OnEmitterEntered(AudioListenable emitter)
{
emitter.SetConcentrating(true);
if (_contactFeedbackPrefab != null && _contactFeedback == null)
{
_contactFeedback = Instantiate(_contactFeedbackPrefab, emitter.transform);
_contactFeedback.transform.localPosition = Vector3.zero;
}
OnEmitterDetected?.Invoke(emitter);
}
private void OnEmitterExited(AudioListenable emitter)
{
emitter.SetConcentrating(false);
if (!emitter.HasBeenTapped)
{
emitter.StopListening();
}
if (_contactFeedback != null)
{
Destroy(_contactFeedback);
_contactFeedback = null;
}
if (_diapasonAnimator != null)
{
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
}
if (_diapasonParticles != null)
{
_diapasonParticles.Stop();
var emission = _diapasonParticles.emission;
emission.enabled = false;
}
_isVibrating = false;
OnEmitterLost?.Invoke(emitter);
}
void OnDrawGizmosSelected()
{
if (_detectionPoints == null || !_isEquipped)
return;
Gizmos.color = Color.yellow;
foreach (Transform detectionPoint in _detectionPoints)
{
if (detectionPoint != null)
{
Gizmos.DrawWireSphere(detectionPoint.position, _detectionRadius);
}
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 38b80731eb88f834ab3d79a566e40b48
@@ -0,0 +1,193 @@
using System.Collections;
using UnityEngine;
using Unheimlich.Core.Audio;
using Unheimlich.Core;
using Unheimlich.Core.Utils;
using Unheimlich.Features.Player;
using Unheimlich.World.CameraSystem;
using InputManager = Unheimlich.Core.Input.InputManager;
namespace Unheimlich.Features.Diapason
{
public class DiapasonListeningHandlerV2 : Singleton<DiapasonListeningHandlerV2>
{
[Header("Settings")]
[SerializeField] private bool _disablePlayerMovementDuringListen = true;
[SerializeField] private bool _enablePanMode = true;
[Header("Visual Feedback")]
[Tooltip("Vignette intensity during listening (0-1)")]
[SerializeField] [Range(0f, 1f)] private float _vignetteIntensity = 0.3f;
[Header("Audio")]
[SerializeField] private AudioClip _breathInClip;
[SerializeField] [Range(0f, 1f)] private float _breathInVolume = 1f;
[SerializeField] private float _concentrationDuration = 1f;
[SerializeField] private float _breathInDuration = 0.5f;
public bool IsListening { get; private set; }
public bool IsConcentrating { get; private set; }
private AudioSource _playerAudioSource;
private Coroutine _listeningCoroutine;
private CameraHeadBob _cameraHeadBob;
private CameraPanSettings _originalCameraSettings;
private AudioListenable _lastDetectedEmitter;
private bool _isFadingOut;
protected override void OnAwake()
{
_playerAudioSource = GetComponent<AudioSource>();
if (_playerAudioSource == null)
_playerAudioSource = gameObject.AddComponent<AudioSource>();
_cameraHeadBob = GetComponentInChildren<CameraHeadBob>();
}
void Update()
{
var diapasonAction = InputManager.GetDiapasonAction();
if (diapasonAction != null && diapasonAction.WasPressedThisFrame())
{
if (!IsListening && !IsConcentrating)
{
StartListeningMode();
}
else if (IsListening || IsConcentrating)
{
StopListeningMode();
}
}
if (IsListening && PlayerController.Instance?.CameraPanController != null)
{
PlayerController.Instance.CameraPanController.UpdatePan();
}
}
private void StartListeningMode()
{
if (_isFadingOut || PlayerController.Instance?.DiapasonEquipment == null)
return;
if (_listeningCoroutine != null)
StopCoroutine(_listeningCoroutine);
PlayerEvents.TriggerEnterListening();
_listeningCoroutine = StartCoroutine(ListeningSequence());
}
private IEnumerator ListeningSequence()
{
IsConcentrating = true;
InputManager.SetContext(InputManager.InputContext.Listening);
if (_disablePlayerMovementDuringListen && PlayerController.Instance?.Movement != null)
{
PlayerController.Instance.Movement.enabled = false;
}
PlayerController.Instance.DiapasonEquipment.EquipDiapason();
PlayBreathIn();
yield return new WaitForSeconds(_breathInDuration);
if (_cameraHeadBob != null)
{
float resetDuration = _concentrationDuration - _breathInDuration;
_cameraHeadBob.LerpToZero(resetDuration);
}
yield return new WaitForSeconds(_concentrationDuration - _breathInDuration);
IsConcentrating = false;
IsListening = true;
EnableVignette(true);
if (_enablePanMode && PlayerController.Instance?.CameraPanController != null)
{
PlayerController.Instance.CameraPanController.SaveOriginalState();
PlayerController.Instance.CameraPanController.StartPan();
}
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = false;
}
private void StopListeningMode()
{
if (_listeningCoroutine != null)
{
StopCoroutine(_listeningCoroutine);
_listeningCoroutine = null;
}
IsListening = false;
IsConcentrating = false;
_isFadingOut = true;
PlayerController.Instance.DiapasonEquipment.UnequipDiapason();
EnableVignette(false);
if (_enablePanMode && PlayerController.Instance?.CameraPanController != null)
{
PlayerController.Instance.CameraPanController.StopPan();
PlayerController.Instance.CameraPanController.ReturnToOriginalPosition(() =>
{
if (_originalCameraSettings != null && PlayerController.Instance?.CameraPanController != null)
{
PlayerController.Instance.CameraPanController.Settings = _originalCameraSettings;
_originalCameraSettings = null;
}
if (_disablePlayerMovementDuringListen && PlayerController.Instance?.Movement != null)
{
PlayerController.Instance.Movement.enabled = true;
}
_isFadingOut = false;
});
}
else
{
if (_disablePlayerMovementDuringListen && PlayerController.Instance?.Movement != null)
{
PlayerController.Instance.Movement.enabled = true;
}
_isFadingOut = false;
}
InputManager.SetContext(InputManager.InputContext.Normal);
PlayerEvents.TriggerExitListening();
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void PlayBreathIn()
{
if (_breathInClip != null && _playerAudioSource != null)
{
_playerAudioSource.PlayOneShot(_breathInClip, _breathInVolume);
}
}
private void EnableVignette(bool enable)
{
if (ListeningVignetteEffect.Instance == null)
return;
if (enable)
{
ListeningVignetteEffect.Instance.EnableVignetteWithIntensity(_vignetteIntensity);
}
else
{
ListeningVignetteEffect.Instance.EnableVignette(false);
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 46c1f473fbd3cac4397aabaa76d18357