Files
Ipseity-Demo/Assets/Unheimlich_POC/Scripts/Features/Player/Runtime/Camera/StressController.cs
T

95 lines
4.3 KiB
C#

using UnityEngine;
namespace Unheimlich.Features.Player
{
/// <summary>
/// Manages the player's stress level and forwards it to <see cref="Unheimlich.World.CameraSystem.LostFootageRig"/>.
/// Stress rises instantly to the requested target and decays back to zero over time when not sustained.
///
/// Intended to sit on <c>OctoPlayerFP</c> alongside other player-level components.
/// Call <see cref="AddStress"/>, <see cref="SetStress"/>, or <see cref="CalmDown"/> from
/// gameplay systems (proximity triggers, jump-scares, scripted events, etc.).
/// </summary>
public class StressController : MonoBehaviour
{
// ── Inspector ─────────────────────────────────────────────────────────────
[Header("References")]
[Tooltip("The LostFootageRig component on CameraPivot.")]
[SerializeField] private Unheimlich.World.CameraSystem.LostFootageRig _rig;
[Header("Decay")]
[Tooltip("Rate at which stress falls back to zero per second when not sustained.")]
[SerializeField] private float _decaySpeed = 0.3f;
[Tooltip("Stress must stay below this threshold for the rig to auto-deactivate.")]
[SerializeField] private float _deactivateThreshold = 0.05f;
[Header("Debug")]
[SerializeField] private bool _debugSustainStress;
[SerializeField] [Range(0f, 1f)] private float _debugStressValue;
// ── Runtime state ─────────────────────────────────────────────────────────
private float _currentStress;
private float _targetStress;
private bool _sustained; // true while an external system holds a target this frame
// ── Unity lifecycle ───────────────────────────────────────────────────────
private void Update()
{
if (_debugSustainStress)
SetStress(_debugStressValue);
_sustained = false;
if (_currentStress > _targetStress)
_currentStress = Mathf.MoveTowards(_currentStress, _targetStress, _decaySpeed * Time.deltaTime);
else
_currentStress = _targetStress;
_targetStress = 0f; // reset each frame; callers must re-assert every Update if sustained
if (_rig == null)
return;
_rig.StressLevel = _currentStress;
// Auto-toggle the rig based on stress level.
if (!_rig.IsActive && _currentStress > _deactivateThreshold)
_rig.SetActive(true);
else if (_rig.IsActive && _currentStress <= _deactivateThreshold)
_rig.SetActive(false);
}
// ── Public API ────────────────────────────────────────────────────────────
/// <summary>
/// Sets a one-shot stress spike that will decay naturally next frame.
/// For sustained stress, call this every frame from a trigger zone or event.
/// </summary>
public void SetStress(float value)
{
_targetStress = Mathf.Max(_targetStress, Mathf.Clamp01(value));
_currentStress = Mathf.Max(_currentStress, _targetStress);
}
/// <summary>Adds <paramref name="delta"/> on top of the current target stress.</summary>
public void AddStress(float delta) => SetStress(_targetStress + delta);
/// <summary>Immediately zeroes stress and deactivates the rig.</summary>
public void CalmDown()
{
_currentStress = 0f;
_targetStress = 0f;
_rig?.SetActive(false);
}
/// <summary>
/// Directly activates or deactivates the rig regardless of stress level.
/// Useful for scripted sequences where you want the effect without the stress system.
/// </summary>
public void ForceRig(bool active) => _rig?.SetActive(active);
}
}