wip : Cleaning not uses & integration liminal spaces
This commit is contained in:
@@ -4,7 +4,6 @@ using Unheimlich.Core;
|
||||
using Unheimlich.Features.Player.Data;
|
||||
using Unheimlich.Features.Dialogue;
|
||||
using InputManager = Unheimlich.Core.Input.InputManager;
|
||||
using OctoCore.Components;
|
||||
|
||||
namespace Unheimlich.Features.Player
|
||||
{
|
||||
@@ -28,6 +27,11 @@ namespace Unheimlich.Features.Player
|
||||
private float _baseFov = -1f;
|
||||
private float _currentFovOffset = 0f;
|
||||
|
||||
// External FOV override — when >= 0, UpdateFovKick uses this as the base FOV
|
||||
// instead of the locally cached snapshot. Set by HouseOfLeavesController each frame.
|
||||
// Consumed once per frame — caller must re-submit every Update.
|
||||
private float _externalBaseFov = -1f;
|
||||
|
||||
public bool IsAimLocked { get; private set; }
|
||||
public bool HasActiveLookInput { get; private set; }
|
||||
public bool IsUsingGamepad { get; private set; }
|
||||
@@ -53,24 +57,40 @@ namespace Unheimlich.Features.Player
|
||||
ApplyAimAssistInternal(_pendingAimAssistTarget);
|
||||
}
|
||||
|
||||
// ── FOV Kick ─────────────────────────────────────────────────────────────
|
||||
// ── FOV Kick ──────────────────────────────────────────────────────────────
|
||||
|
||||
private void UpdateFovKick()
|
||||
{
|
||||
if (Settings == null || PlayerController.Instance?.PlayerCamera == null) return;
|
||||
|
||||
// Capture base FOV once (handles cases where FOV is changed externally before Start).
|
||||
if (_baseFov < 0f)
|
||||
_baseFov = PlayerController.Instance.PlayerCamera.fieldOfView;
|
||||
// Use the external override if submitted this frame, otherwise fall back
|
||||
// to the locally cached base FOV.
|
||||
float effectiveBase = _externalBaseFov >= 0f ? _externalBaseFov : _baseFov;
|
||||
|
||||
float targetOffset = PlayerController.Instance.IsRunning ? Settings.fovKickAmount : 0f;
|
||||
_currentFovOffset = Mathf.Lerp(_currentFovOffset, targetOffset, Time.deltaTime * Settings.fovKickSpeed);
|
||||
if (effectiveBase < 0f)
|
||||
{
|
||||
effectiveBase = PlayerController.Instance.PlayerCamera.fieldOfView;
|
||||
_baseFov = effectiveBase;
|
||||
}
|
||||
|
||||
PlayerController.Instance.PlayerCamera.fieldOfView = _baseFov + _currentFovOffset;
|
||||
float targetOffset = PlayerController.Instance.IsRunning ? Settings.fovKickAmount : 0f;
|
||||
_currentFovOffset = Mathf.Lerp(_currentFovOffset, targetOffset, Time.deltaTime * Settings.fovKickSpeed);
|
||||
|
||||
PlayerController.Instance.PlayerCamera.fieldOfView = effectiveBase + _currentFovOffset;
|
||||
|
||||
// Consume the override — must be re-submitted next frame by the caller.
|
||||
_externalBaseFov = -1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the base FOV reference. Call this if the camera FOV is changed intentionally at runtime.
|
||||
/// Overrides the base FOV used by the sprint kick for this frame.
|
||||
/// Call every Update from HouseOfLeavesController — consumed automatically after use.
|
||||
/// Must be called before CameraEffects.Update runs (use Script Execution Order -10).
|
||||
/// </summary>
|
||||
public void SetBaseFovOverride(float fov) => _externalBaseFov = fov;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the locally cached base FOV to the camera's current fieldOfView.
|
||||
/// </summary>
|
||||
public void ResetBaseFov()
|
||||
{
|
||||
@@ -105,7 +125,7 @@ namespace Unheimlich.Features.Player
|
||||
|
||||
if (_shakeTimer <= 0f)
|
||||
{
|
||||
_shakeTimer = _shakeInterval * amplitude;
|
||||
_shakeTimer = _shakeInterval * amplitude;
|
||||
_shakeOriginalPos = PlayerController.Instance.CameraPivot.position;
|
||||
|
||||
float x = Random.Range(-1f, 1f) * amplitude;
|
||||
@@ -132,7 +152,7 @@ namespace Unheimlich.Features.Player
|
||||
public void ApplyAimAssist(Vector3 targetCenter)
|
||||
{
|
||||
_pendingAimAssistTarget = targetCenter;
|
||||
_hasAimAssistTarget = true;
|
||||
_hasAimAssistTarget = true;
|
||||
}
|
||||
|
||||
private void ApplyAimAssistInternal(Vector3 targetCenter)
|
||||
@@ -147,30 +167,27 @@ namespace Unheimlich.Features.Player
|
||||
IsAimLocked = false;
|
||||
|
||||
Vector3 directionToTarget = (targetCenter - PlayerController.Instance.CameraTransform.position).normalized;
|
||||
float angleError = Vector3.Angle(PlayerController.Instance.CameraTransform.forward, directionToTarget);
|
||||
float angleError = Vector3.Angle(PlayerController.Instance.CameraTransform.forward, directionToTarget);
|
||||
|
||||
if (IsAimLocked || angleError < Settings.aimAssistMaxAngle)
|
||||
{
|
||||
Vector3 targetDirection = directionToTarget;
|
||||
float targetYaw = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
|
||||
float targetPitch = -Mathf.Asin(targetDirection.y) * Mathf.Rad2Deg;
|
||||
float targetYaw = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
|
||||
float targetPitch = -Mathf.Asin(targetDirection.y) * Mathf.Rad2Deg;
|
||||
|
||||
float currentYaw = OctoPlayer.Instance.State.Yaw;
|
||||
float currentPitch = OctoPlayer.Instance.State.Pitch;
|
||||
float currentYaw = PlayerController.Instance.Movement.Yaw;
|
||||
float currentPitch = PlayerController.Instance.Movement.Pitch;
|
||||
|
||||
float newYaw = Mathf.LerpAngle(currentYaw, targetYaw, Settings.aimAssistStrength * Time.deltaTime);
|
||||
float newPitch = Mathf.Lerp(currentPitch, targetPitch, Settings.aimAssistStrength * Time.deltaTime);
|
||||
float newYaw = Mathf.LerpAngle(currentYaw, targetYaw, Settings.aimAssistStrength * Time.deltaTime);
|
||||
float newPitch = Mathf.Lerp(currentPitch, targetPitch, Settings.aimAssistStrength * Time.deltaTime);
|
||||
|
||||
OctoPlayer.Instance.SetYaw(newYaw);
|
||||
OctoPlayer.Instance.SetPitch(newPitch);
|
||||
PlayerController.Instance.Movement.Yaw = newYaw;
|
||||
PlayerController.Instance.Movement.Pitch = newPitch;
|
||||
}
|
||||
|
||||
_hasAimAssistTarget = false;
|
||||
}
|
||||
|
||||
public void LockAim(bool locked)
|
||||
{
|
||||
IsAimLocked = locked;
|
||||
}
|
||||
public void LockAim(bool locked) => IsAimLocked = locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using UnityEngine;
|
||||
using Unheimlich.Features.Player;
|
||||
|
||||
namespace Unheimlich.World.HouseOfLeaves
|
||||
{
|
||||
/// <summary>
|
||||
/// Simulates a Dolly Zoom (Vertigo effect) by applying a speed-driven additive FOV offset
|
||||
/// on top of the base FOV already written by <see cref="HouseOfLeavesController"/> and
|
||||
/// <see cref="CameraEffects"/> earlier in the frame.
|
||||
///
|
||||
/// Runs in <c>LateUpdate</c> — after both <see cref="HouseOfLeavesController.Update"/> and
|
||||
/// <see cref="CameraEffects.Update"/> — so it always layers on top of the final written value.
|
||||
/// Subtracts the previous frame's offset before adding the new one to avoid compounding.
|
||||
///
|
||||
/// The faster the player moves, the more the FOV pinches inward,
|
||||
/// compressing the perceived corridor space and amplifying claustrophobia.
|
||||
/// </summary>
|
||||
public class DollyZoomEffect : MonoBehaviour
|
||||
{
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Serialized Fields
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
[Header("Effect")]
|
||||
[Tooltip("Enable or disable the effect at runtime.")]
|
||||
[SerializeField] private bool _isEnabled = true;
|
||||
|
||||
[Tooltip("Maximum negative FOV offset at full speed (degrees). " +
|
||||
"Negative value pinches the FOV inward.")]
|
||||
[SerializeField] private float _maxFovOffset = -15f;
|
||||
|
||||
[Tooltip("Walk speed (km/h) at which the effect starts fading in.")]
|
||||
[SerializeField] private float _speedThreshold = 12f;
|
||||
|
||||
[Tooltip("Walk speed (km/h) at which the effect reaches its maximum.")]
|
||||
[SerializeField] private float _maxSpeedForEffect = 22f;
|
||||
|
||||
[Tooltip("Lerp speed for the FOV offset transitions.")]
|
||||
[SerializeField] private float _smoothSpeed = 3f;
|
||||
|
||||
[Header("Pulse (optional)")]
|
||||
[Tooltip("Adds a subtle sinusoidal oscillation to the FOV offset for extra unease.")]
|
||||
[SerializeField] private bool _enablePulse;
|
||||
|
||||
[Tooltip("Amplitude of the pulse oscillation (degrees).")]
|
||||
[SerializeField] private float _pulseAmplitude = 1.5f;
|
||||
|
||||
[Tooltip("Frequency of the pulse oscillation (Hz).")]
|
||||
[SerializeField] private float _pulseFrequency = 0.4f;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Private Fields
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private Camera _playerCamera;
|
||||
private float _currentFovOffset;
|
||||
private bool _isInitialized;
|
||||
|
||||
private float _previousFovOffset;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Unity Messages
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (PlayerController.Instance?.PlayerCamera == null)
|
||||
{
|
||||
Debug.LogError("[DollyZoomEffect] PlayerCamera could not be resolved.");
|
||||
return;
|
||||
}
|
||||
|
||||
_playerCamera = PlayerController.Instance.PlayerCamera;
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
// LateUpdate ensures this runs after HouseOfLeavesController and CameraEffects
|
||||
// have both written their FOV values in Update.
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!_isInitialized || !_isEnabled) return;
|
||||
|
||||
TickDollyZoom();
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Tick
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Computes the speed-driven FOV delta and applies it additively on top of
|
||||
/// the current <c>fieldOfView</c>. Strips the previous frame's offset first
|
||||
/// to avoid compounding the delta across frames.
|
||||
/// </summary>
|
||||
// Dans DollyZoomEffect, stocker le FOV base séparément
|
||||
private void TickDollyZoom()
|
||||
{
|
||||
float speedKmh = GetHorizontalSpeedKmh();
|
||||
float speedT = Mathf.Clamp01(
|
||||
(speedKmh - _speedThreshold) / Mathf.Max(0.01f, _maxSpeedForEffect - _speedThreshold)
|
||||
);
|
||||
|
||||
float targetOffset = _maxFovOffset * speedT;
|
||||
if (_enablePulse && speedT > 0.01f)
|
||||
targetOffset += Mathf.Sin(Time.time * _pulseFrequency * Mathf.PI * 2f) * _pulseAmplitude * speedT;
|
||||
|
||||
_currentFovOffset = Mathf.Lerp(_currentFovOffset, targetOffset, Time.deltaTime * _smoothSpeed);
|
||||
|
||||
_playerCamera.fieldOfView += _currentFovOffset - _previousFovOffset;
|
||||
_previousFovOffset = _currentFovOffset;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Helpers
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private float GetHorizontalSpeedKmh()
|
||||
{
|
||||
CharacterController charController = PlayerController.Instance?.CharController;
|
||||
if (charController == null) return 0f;
|
||||
|
||||
Vector3 horizontalVelocity = charController.velocity;
|
||||
horizontalVelocity.y = 0f;
|
||||
|
||||
return horizontalVelocity.magnitude * 3.6f;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Public API
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
public void SetEnabled(bool value) => _isEnabled = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 156759bdbd15e4a498d2d415ec86892b
|
||||
Reference in New Issue
Block a user