Start implementation of diapason mechanics
This commit is contained in:
+284
@@ -0,0 +1,284 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Audio;
|
||||
using InputManager = Unheimlich.Managers.PlayerInputManager;
|
||||
|
||||
namespace Unheimlich.Gameplay.Player
|
||||
{
|
||||
public class DiapasonListeningHandler : MonoBehaviour
|
||||
{
|
||||
public static DiapasonListeningHandler Instance { get; private set; }
|
||||
|
||||
[Header("References")]
|
||||
[SerializeField] private GameObject _diapasonObject;
|
||||
[SerializeField] private Animator _diapasonAnimator;
|
||||
[SerializeField] private Camera _playerCamera;
|
||||
[SerializeField] private Transform _cursorTransform;
|
||||
|
||||
[Header("Listening Settings")]
|
||||
[SerializeField] private float _listeningRange = 5f;
|
||||
[SerializeField] private LayerMask _listenableLayers;
|
||||
[SerializeField] private float _concentrationDuration = 1f;
|
||||
[SerializeField] private float _breathInDuration = 0.5f;
|
||||
|
||||
[Header("Camera Settings")]
|
||||
[SerializeField] private float _cameraPanSpeed = 2f;
|
||||
[SerializeField] private float _cameraPanBorderSize = 0.1f;
|
||||
[SerializeField] private float _maxCameraPanAngle = 15f;
|
||||
|
||||
[Header("Visual Feedback")]
|
||||
[SerializeField] private float _vignetteIntensity = 0.5f;
|
||||
[SerializeField] private ListeningVignetteEffect _vignetteEffect;
|
||||
|
||||
[Header("Audio")]
|
||||
[SerializeField] private AudioClip _breathInClip;
|
||||
[SerializeField] private AudioClip _diapasonTapClip;
|
||||
[SerializeField] private float _ambientAttenuationAmount = 0.3f;
|
||||
|
||||
[Header("Input Action")]
|
||||
[SerializeField] private InputActionReference _diapasonAction;
|
||||
|
||||
public bool IsListening { get; private set; }
|
||||
public bool IsConcentrating { get; private set; }
|
||||
|
||||
private AudioListenable _currentTargetEmitter;
|
||||
private AudioSource _playerAudioSource;
|
||||
private Coroutine _listeningCoroutine;
|
||||
private Vector2 _originalCameraRotation;
|
||||
private float _originalAmbientVolume;
|
||||
|
||||
private const string ANIM_TRIGGER_TAP = "Tap";
|
||||
private const string ANIM_BOOL_EQUIPPED = "IsEquipped";
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
_playerAudioSource = GetComponent<AudioSource>();
|
||||
if (_playerAudioSource == null)
|
||||
_playerAudioSource = gameObject.AddComponent<AudioSource>();
|
||||
|
||||
if (_diapasonObject != null)
|
||||
_diapasonObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!InputManager.IsInputEnabled)
|
||||
return;
|
||||
|
||||
if (_diapasonAction != null && _diapasonAction.action.WasPressedThisFrame())
|
||||
{
|
||||
if (!IsListening && !IsConcentrating)
|
||||
StartListeningMode();
|
||||
else if (IsListening)
|
||||
StopListeningMode();
|
||||
}
|
||||
|
||||
if (IsListening)
|
||||
{
|
||||
UpdateCursorAndCameraPan();
|
||||
CheckForListenableObject();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartListeningMode()
|
||||
{
|
||||
if (_listeningCoroutine != null)
|
||||
StopCoroutine(_listeningCoroutine);
|
||||
|
||||
_listeningCoroutine = StartCoroutine(ListeningSequence());
|
||||
}
|
||||
|
||||
private IEnumerator ListeningSequence()
|
||||
{
|
||||
IsConcentrating = true;
|
||||
InputManager.ToggleInput(false);
|
||||
|
||||
if (_diapasonObject != null)
|
||||
{
|
||||
_diapasonObject.SetActive(true);
|
||||
if (_diapasonAnimator != null)
|
||||
_diapasonAnimator.SetBool(ANIM_BOOL_EQUIPPED, true);
|
||||
}
|
||||
|
||||
PlayBreathIn();
|
||||
yield return new WaitForSeconds(_breathInDuration);
|
||||
|
||||
yield return new WaitForSeconds(_concentrationDuration - _breathInDuration);
|
||||
|
||||
IsConcentrating = false;
|
||||
IsListening = true;
|
||||
|
||||
_originalCameraRotation = new Vector2(transform.eulerAngles.y, _playerCamera.transform.eulerAngles.x);
|
||||
AttenuateAmbientSound(true);
|
||||
EnableVignette(true);
|
||||
|
||||
Cursor.lockState = CursorLockMode.Confined;
|
||||
Cursor.visible = true;
|
||||
}
|
||||
|
||||
private void StopListeningMode()
|
||||
{
|
||||
if (_listeningCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_listeningCoroutine);
|
||||
_listeningCoroutine = null;
|
||||
}
|
||||
|
||||
IsListening = false;
|
||||
IsConcentrating = false;
|
||||
|
||||
if (_diapasonObject != null)
|
||||
{
|
||||
if (_diapasonAnimator != null)
|
||||
_diapasonAnimator.SetBool(ANIM_BOOL_EQUIPPED, false);
|
||||
_diapasonObject.SetActive(false);
|
||||
}
|
||||
|
||||
AttenuateAmbientSound(false);
|
||||
EnableVignette(false);
|
||||
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
Cursor.visible = false;
|
||||
|
||||
InputManager.ToggleInput(true);
|
||||
|
||||
if (_currentTargetEmitter != null)
|
||||
{
|
||||
_currentTargetEmitter.StopListening();
|
||||
_currentTargetEmitter = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCursorAndCameraPan()
|
||||
{
|
||||
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 (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);
|
||||
|
||||
targetPitch = Mathf.Clamp(targetPitch, _originalCameraRotation.y - _maxCameraPanAngle, _originalCameraRotation.y + _maxCameraPanAngle);
|
||||
|
||||
Vector3 currentRotation = transform.eulerAngles;
|
||||
currentRotation.y = Mathf.Lerp(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);
|
||||
_playerCamera.transform.localEulerAngles = cameraRotation;
|
||||
}
|
||||
|
||||
private void CheckForListenableObject()
|
||||
{
|
||||
if (_playerCamera == null)
|
||||
return;
|
||||
|
||||
Ray ray = _playerCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, _listeningRange, _listenableLayers))
|
||||
{
|
||||
AudioListenable listenable = hit.collider.GetComponent<AudioListenable>();
|
||||
|
||||
if (listenable != null && listenable != _currentTargetEmitter)
|
||||
{
|
||||
if (_currentTargetEmitter != null)
|
||||
_currentTargetEmitter.StopListening();
|
||||
|
||||
_currentTargetEmitter = listenable;
|
||||
}
|
||||
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame && _currentTargetEmitter != null)
|
||||
{
|
||||
TriggerDiapasonTap();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentTargetEmitter != null)
|
||||
{
|
||||
_currentTargetEmitter.StopListening();
|
||||
_currentTargetEmitter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerDiapasonTap()
|
||||
{
|
||||
if (_diapasonAnimator != null)
|
||||
_diapasonAnimator.SetTrigger(ANIM_TRIGGER_TAP);
|
||||
|
||||
if (_diapasonTapClip != null && _playerAudioSource != null)
|
||||
_playerAudioSource.PlayOneShot(_diapasonTapClip);
|
||||
|
||||
if (_currentTargetEmitter != null)
|
||||
_currentTargetEmitter.StartListening(transform.position);
|
||||
}
|
||||
|
||||
private void PlayBreathIn()
|
||||
{
|
||||
if (_breathInClip != null && _playerAudioSource != null)
|
||||
_playerAudioSource.PlayOneShot(_breathInClip);
|
||||
}
|
||||
|
||||
private void AttenuateAmbientSound(bool enable)
|
||||
{
|
||||
AudioListener listener = FindFirstObjectByType<AudioListener>();
|
||||
if (listener != null)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
_originalAmbientVolume = AudioListener.volume;
|
||||
AudioListener.volume = _ambientAttenuationAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioListener.volume = _originalAmbientVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableVignette(bool enable)
|
||||
{
|
||||
if (_vignetteEffect != null)
|
||||
{
|
||||
_vignetteEffect.EnableVignette(enable);
|
||||
_vignetteEffect.SetIntensity(_vignetteIntensity);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
Gizmos.DrawRay(ray.origin, ray.direction * _listeningRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2094bd9c6f72e5b4cadf430f4d70f8f6
|
||||
@@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace Unheimlich.Gameplay.Player
|
||||
{
|
||||
public class ListeningVignetteEffect : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private Volume _globalVolume;
|
||||
|
||||
[Header("Settings")]
|
||||
[SerializeField] private float _targetIntensity = 0.5f;
|
||||
[SerializeField] private float _transitionSpeed = 2f;
|
||||
|
||||
private Vignette _vignette;
|
||||
private float _originalIntensity;
|
||||
private bool _isEnabled;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_globalVolume == null)
|
||||
_globalVolume = FindFirstObjectByType<Volume>();
|
||||
|
||||
if (_globalVolume != null && _globalVolume.profile != null)
|
||||
{
|
||||
if (_globalVolume.profile.TryGet(out Vignette vignette))
|
||||
{
|
||||
_vignette = vignette;
|
||||
_originalIntensity = _vignette.intensity.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_vignette == 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;
|
||||
}
|
||||
|
||||
public void EnableVignette(bool enable)
|
||||
{
|
||||
_isEnabled = enable;
|
||||
}
|
||||
|
||||
public void SetIntensity(float intensity)
|
||||
{
|
||||
_targetIntensity = Mathf.Clamp01(intensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 878ebc270c13e5c49a3813b1848f6ea5
|
||||
Reference in New Issue
Block a user