95 lines
4.3 KiB
C#
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);
|
|
}
|
|
} |