wip : Cleaning not uses & integration liminal spaces

This commit is contained in:
2026-05-20 15:50:41 +01:00
parent 1cff87b60b
commit 396ecddf99
807 changed files with 125823 additions and 273654 deletions
@@ -0,0 +1,61 @@
using UnityEngine;
using Unheimlich.Features.Player;
namespace Unheimlich.World.HouseOfLeaves
{
/// <summary>
/// Triggers an extreme FOV zoom when the player reaches the end of the corridor.
/// Attach to a trigger collider placed at the corridor exit.
/// </summary>
public class CorridorEndTrigger : MonoBehaviour
{
// ─────────────────────────────────────────────────────────────────────────
// Serialized Fields
// ─────────────────────────────────────────────────────────────────────────
[Header("Zoom")]
[Tooltip("Target FOV when the player hits the trigger. Low value = extreme zoom.")]
[SerializeField] private float _targetFov = 5f;
[Tooltip("Speed of the zoom lerp.")]
[SerializeField] private float _zoomSpeed = 3f;
// ─────────────────────────────────────────────────────────────────────────
// Private Fields
// ─────────────────────────────────────────────────────────────────────────
private bool _triggered;
// ─────────────────────────────────────────────────────────────────────────
// Unity Messages
// ─────────────────────────────────────────────────────────────────────────
private void OnTriggerEnter(Collider other)
{
if (_triggered) return;
if (other.GetComponent<OctoCore.Components.OctoPlayer>() == null) return;
_triggered = true;
PlayerController.Instance.CameraEffects.enabled = false;
var dolly = FindFirstObjectByType<DollyZoomEffect>();
if (dolly) dolly.SetEnabled(false);
var hol = FindFirstObjectByType<HouseOfLeavesController>();
if (hol) hol.enabled = false;
}
private void Update()
{
if (!_triggered) return;
if (PlayerController.Instance?.PlayerCamera == null) return;
PlayerController.Instance.PlayerCamera.fieldOfView = Mathf.Lerp(
PlayerController.Instance.PlayerCamera.fieldOfView,
_targetFov,
Time.deltaTime * _zoomSpeed
);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e2138d5849f491f4e8ed3ccee1061493
@@ -0,0 +1,131 @@
using UnityEngine;
namespace Unheimlich.World.HouseOfLeaves
{
/// <summary>
/// Physically moves the corridor walls inward based on the player's progression,
/// creating a genuine sense of spatial compression without relying on FOV tricks.
///
/// Reads progression from <see cref="HouseOfLeavesController"/> via its public
/// <see cref="HouseOfLeavesController.Progression"/> property.
/// </summary>
public class CorridorWallsController : MonoBehaviour
{
// ─────────────────────────────────────────────────────────────────────────
// Serialized Fields
// ─────────────────────────────────────────────────────────────────────────
[Header("References")]
[Tooltip("The HouseOfLeavesController driving the progression value.")]
[SerializeField] private HouseOfLeavesController _controller;
[Tooltip("Left wall plane.")]
[SerializeField] private Transform _wallLeft;
[Tooltip("Right wall plane.")]
[SerializeField] private Transform _wallRight;
[Tooltip("Ceiling plane.")]
[SerializeField] private Transform _wallCeiling;
[Tooltip("Floor plane.")]
[SerializeField] private Transform _wallFloor;
[Header("Compression")]
[Tooltip("How far (meters) each side wall moves inward at full progression.")]
[SerializeField] private float _maxSideInset = 2f;
[Tooltip("How far (meters) the ceiling moves down at full progression.")]
[SerializeField] private float _maxCeilingInset = 1f;
[Tooltip("How far (meters) the floor moves up at full progression.")]
[SerializeField] private float _maxFloorInset = 0f;
[Tooltip("Lerp speed applied to wall movement each frame.")]
[SerializeField] private float _lerpSpeed = 2f;
[Tooltip("Animation curve mapping progression [0,1] to compression [0,1]. " +
"Lets you tune when walls start closing in.")]
[SerializeField] private AnimationCurve _compressionCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
// ─────────────────────────────────────────────────────────────────────────
// Private Fields
// ─────────────────────────────────────────────────────────────────────────
private Vector3 _initialLeftPos;
private Vector3 _initialRightPos;
private Vector3 _initialCeilingPos;
private Vector3 _initialFloorPos;
private bool _isInitialized;
// ─────────────────────────────────────────────────────────────────────────
// Unity Messages
// ─────────────────────────────────────────────────────────────────────────
private void Start()
{
if (_controller == null)
{
Debug.LogError("[CorridorWallsController] HouseOfLeavesController reference is missing.");
return;
}
if (_wallLeft) _initialLeftPos = _wallLeft.position;
if (_wallRight) _initialRightPos = _wallRight.position;
if (_wallCeiling) _initialCeilingPos = _wallCeiling.position;
if (_wallFloor) _initialFloorPos = _wallFloor.position;
_isInitialized = true;
}
private void Update()
{
if (!_isInitialized) return;
float t = _compressionCurve.Evaluate(_controller.Progression);
float lerpDelta = Time.deltaTime * _lerpSpeed;
if (_wallLeft)
{
Vector3 target = _initialLeftPos + Vector3.right * _maxSideInset * t;
_wallLeft.position = Vector3.Lerp(_wallLeft.position, target, lerpDelta);
}
if (_wallRight)
{
Vector3 target = _initialRightPos + Vector3.left * _maxSideInset * t;
_wallRight.position = Vector3.Lerp(_wallRight.position, target, lerpDelta);
}
if (_wallCeiling)
{
Vector3 target = _initialCeilingPos + Vector3.down * _maxCeilingInset * t;
_wallCeiling.position = Vector3.Lerp(_wallCeiling.position, target, lerpDelta);
}
if (_wallFloor)
{
Vector3 target = _initialFloorPos + Vector3.up * _maxFloorInset * t;
_wallFloor.position = Vector3.Lerp(_wallFloor.position, target, lerpDelta);
}
}
// ─────────────────────────────────────────────────────────────────────────
// Editor
// ─────────────────────────────────────────────────────────────────────────
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (!_isInitialized) return;
Gizmos.color = Color.red;
if (_wallLeft) Gizmos.DrawWireCube(_initialLeftPos + Vector3.right * _maxSideInset, Vector3.one * 0.3f);
if (_wallRight) Gizmos.DrawWireCube(_initialRightPos + Vector3.left * _maxSideInset, Vector3.one * 0.3f);
if (_wallCeiling) Gizmos.DrawWireCube(_initialCeilingPos + Vector3.down * _maxCeilingInset, Vector3.one * 0.3f);
if (_wallFloor) Gizmos.DrawWireCube(_initialFloorPos + Vector3.up * _maxFloorInset, Vector3.one * 0.3f);
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 502932957cfd6bc44856b113b9f4fa87
@@ -0,0 +1,287 @@
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using Unheimlich.Features.Player;
namespace Unheimlich.World.HouseOfLeaves
{
/// <summary>
/// Orchestrates the core House of Leaves experience.
/// Script Execution Order: set to -10 so SetBaseFovOverride is written
/// before CameraEffects.Update consumes it in the same frame.
/// </summary>
public class HouseOfLeavesController : MonoBehaviour
{
// ─────────────────────────────────────────────────────────────────────────
// Serialized Fields
// ─────────────────────────────────────────────────────────────────────────
[Header("Corridor")]
[Tooltip("Total length of the corridor (meters).")]
[SerializeField] private float _corridorLength = 100f;
[Header("Speed Ramp")]
[SerializeField] private float _initialWalkSpeed = 10f;
[SerializeField] private float _maxWalkSpeed = 22f;
[Header("FOV Ramp")]
[SerializeField] private float _initialFov = 70f;
[SerializeField] private float _minFov = 45f;
[SerializeField] private float _fovLerpSpeed = 2f;
[Header("Darkness")]
[SerializeField] private Volume _postProcessVolume;
[SerializeField] private float _turningBackAngle = 100f;
[SerializeField] [Range(0f, 1f)] private float _maxVignetteIntensity = 0.6f;
[SerializeField] private float _maxExposureReduction = -3f;
[SerializeField] private float _darknessLerpSpeed = 2f;
[Header("Light Source")]
[SerializeField] private Transform _lightSourceReference;
[Header("Fracture")]
[SerializeField] private Material _fractureMaterial;
[SerializeField] private AnimationCurve _fractureCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
// ─────────────────────────────────────────────────────────────────────────
// Private Fields
// ─────────────────────────────────────────────────────────────────────────
private OctoCore.Components.OctoPlayer _octoPlayer;
private Camera _playerCamera;
private CameraEffects _cameraEffects;
private FieldInfo _settingsFieldInfo;
private FieldInfo _walkSpeedFieldInfo;
private object _settingsInstance;
private Vignette _vignette;
private ColorAdjustments _colorAdjustments;
private Vector3 _lastPlayerPosition;
private float _distanceTravelled;
private float _currentFov;
private Vector3 _lightForwardDirection;
private bool _isInitialized;
// ─────────────────────────────────────────────────────────────────────────
// Unity Messages
// ─────────────────────────────────────────────────────────────────────────
private void Start()
{
if (!TryResolvePlayerReferences()) return;
InitializeSpeedReflection();
InitializeFov();
InitializeLightDirection();
InitializePostProcess();
_lastPlayerPosition = PlayerController.Instance.transform.position;
_isInitialized = true;
}
private void Update()
{
if (!_isInitialized) return;
TrackDistance();
float t = Mathf.Clamp01(_distanceTravelled / _corridorLength);
TickSpeed(t);
TickFov(t);
TickDarkness();
TickFracture(t);
}
// ─────────────────────────────────────────────────────────────────────────
// Initialization
// ─────────────────────────────────────────────────────────────────────────
private bool TryResolvePlayerReferences()
{
if (PlayerController.Instance == null)
{
Debug.LogError("[HouseOfLeavesController] PlayerController.Instance not found.");
return false;
}
_octoPlayer = PlayerController.Instance.Movement;
_playerCamera = PlayerController.Instance.PlayerCamera;
_cameraEffects = PlayerController.Instance.CameraEffects;
if (_octoPlayer == null || _playerCamera == null)
{
Debug.LogError("[HouseOfLeavesController] OctoPlayer or PlayerCamera could not be resolved.");
return false;
}
if (_cameraEffects == null)
Debug.LogWarning("[HouseOfLeavesController] CameraEffects not found — FOV kick sync disabled.");
return true;
}
private void InitializeSpeedReflection()
{
System.Type playerType = typeof(OctoCore.Components.OctoPlayer);
_settingsFieldInfo = playerType.GetField(
"_settings", BindingFlags.NonPublic | BindingFlags.Instance);
if (_settingsFieldInfo == null)
{
Debug.LogError("[HouseOfLeavesController] Could not find '_settings' on OctoPlayer via reflection.");
return;
}
_settingsInstance = _settingsFieldInfo.GetValue(_octoPlayer);
_walkSpeedFieldInfo = _settingsInstance.GetType().GetField(
"WalkSpeed", BindingFlags.Public | BindingFlags.Instance);
if (_walkSpeedFieldInfo == null)
Debug.LogError("[HouseOfLeavesController] Could not find 'WalkSpeed' on OctoPlayer.Settings via reflection.");
}
private void InitializeFov()
{
_currentFov = _initialFov;
_playerCamera.fieldOfView = _initialFov;
}
private void InitializeLightDirection()
{
_lightForwardDirection = _lightSourceReference != null
? _lightSourceReference.forward
: PlayerController.Instance.transform.forward;
_lightForwardDirection.y = 0f;
_lightForwardDirection.Normalize();
}
private void InitializePostProcess()
{
if (_postProcessVolume == null)
{
Debug.LogWarning("[HouseOfLeavesController] No URP Volume assigned — darkness effect disabled.");
return;
}
_postProcessVolume.profile.TryGet(out _vignette);
_postProcessVolume.profile.TryGet(out _colorAdjustments);
}
// ─────────────────────────────────────────────────────────────────────────
// Distance Tracking
// ─────────────────────────────────────────────────────────────────────────
private void TrackDistance()
{
Vector3 currentPosition = PlayerController.Instance.transform.position;
Vector3 delta = currentPosition - _lastPlayerPosition;
delta.y = 0f;
_distanceTravelled += Vector3.Dot(delta, _lightForwardDirection);
_distanceTravelled = Mathf.Clamp(_distanceTravelled, 0f, _corridorLength);
_lastPlayerPosition = currentPosition;
}
// ─────────────────────────────────────────────────────────────────────────
// Tick Methods
// ─────────────────────────────────────────────────────────────────────────
private void TickSpeed(float t)
{
if (_walkSpeedFieldInfo == null || _settingsInstance == null) return;
float newSpeed = Mathf.Lerp(_initialWalkSpeed, _maxWalkSpeed, t);
_walkSpeedFieldInfo.SetValue(_settingsInstance, newSpeed);
}
/// <summary>
/// Lerps the FOV and submits it to CameraEffects as the base for this frame's
/// sprint kick. CameraEffects.Update then does the authoritative fieldOfView write.
/// This component must run before CameraEffects (Execution Order -10).
/// </summary>
private void TickFov(float t)
{
float targetFov = Mathf.Lerp(_initialFov, _minFov, t);
_currentFov = Mathf.Lerp(_currentFov, targetFov, Time.deltaTime * _fovLerpSpeed);
// Submit to CameraEffects — it will write fieldOfView = _currentFov + kickOffset.
// If CameraEffects is absent, write directly as fallback.
if (_cameraEffects != null)
_cameraEffects.SetBaseFovOverride(_currentFov);
else
_playerCamera.fieldOfView = _currentFov;
}
private void TickDarkness()
{
if (_vignette == null && _colorAdjustments == null) return;
Vector3 playerForward = PlayerController.Instance.transform.forward;
playerForward.y = 0f;
playerForward.Normalize();
float dot = Vector3.Dot(playerForward, _lightForwardDirection);
float angleDegrees = Mathf.Acos(Mathf.Clamp(dot, -1f, 1f)) * Mathf.Rad2Deg;
float darknessT = Mathf.Clamp01(
(angleDegrees - _turningBackAngle) / (180f - _turningBackAngle)
);
float lerpDelta = Time.deltaTime * _darknessLerpSpeed;
if (_vignette != null)
_vignette.intensity.value = Mathf.Lerp(_vignette.intensity.value, _maxVignetteIntensity * darknessT, lerpDelta);
if (_colorAdjustments != null)
_colorAdjustments.postExposure.value = Mathf.Lerp(_colorAdjustments.postExposure.value, _maxExposureReduction * darknessT, lerpDelta);
}
private void TickFracture(float t)
{
float fractureT = _fractureCurve.Evaluate(t);
_fractureMaterial?.SetFloat("_FractureAmount", fractureT);
}
// ─────────────────────────────────────────────────────────────────────────
// Public API
/// <summary>Current corridor progression in [0, 1].</summary>
public float Progression => _corridorLength > 0f
? Mathf.Clamp01(_distanceTravelled / _corridorLength)
: 0f;
// ─────────────────────────────────────────────────────────────────────────
public void ResetProgression()
{
_distanceTravelled = 0f;
_lastPlayerPosition = PlayerController.Instance.transform.position;
}
public void SetLightDirection(Vector3 worldDirection)
{
_lightForwardDirection = worldDirection;
_lightForwardDirection.y = 0f;
_lightForwardDirection.Normalize();
}
// ─────────────────────────────────────────────────────────────────────────
// Editor
// ─────────────────────────────────────────────────────────────────────────
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawRay(transform.position + Vector3.up, _lightForwardDirection * 4f);
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: af6f7d258d38edf44a956a642c1f414d
@@ -0,0 +1,75 @@
using UnityEngine;
namespace Unheimlich.World.HouseOfLeaves
{
/// <summary>
/// Animates the sand terrain rising from below the corridor floor
/// based on the player's progression through the corridor.
///
/// The terrain starts buried underground and slowly emerges as the
/// player advances, simulating sand flooding the corridor from below.
/// </summary>
public class SandTerrainController : MonoBehaviour
{
// ─────────────────────────────────────────────────────────────────────────
// Serialized Fields
// ─────────────────────────────────────────────────────────────────────────
[Header("References")]
[Tooltip("The HouseOfLeavesController driving the progression value.")]
[SerializeField] private HouseOfLeavesController _controller;
[Tooltip("The sand terrain Transform to animate.")]
[SerializeField] private Transform _sandTerrain;
[Header("Rise Settings")]
[Tooltip("Y position of the terrain at the start (buried underground).")]
[SerializeField] private float _startY = -4f;
[Tooltip("Y position of the terrain at full progression (emerged).")]
[SerializeField] private float _endY = 0.5f;
[Tooltip("Lerp speed applied to the vertical movement each frame.")]
[SerializeField] private float _lerpSpeed = 2f;
[Tooltip("Animation curve mapping progression [0,1] to rise amount [0,1]. " +
"Use this to delay the rise until mid-corridor for example.")]
[SerializeField] private AnimationCurve _riseCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
// ─────────────────────────────────────────────────────────────────────────
// Unity Messages
// ─────────────────────────────────────────────────────────────────────────
private void Start()
{
if (_controller == null)
{
Debug.LogError("[SandTerrainController] HouseOfLeavesController reference is missing.");
return;
}
if (_sandTerrain == null)
{
Debug.LogError("[SandTerrainController] Sand terrain Transform is missing.");
return;
}
// Initialize position immediately without lerp.
Vector3 startPos = _sandTerrain.position;
startPos.y = _startY;
_sandTerrain.position = startPos;
}
private void Update()
{
if (_controller == null || _sandTerrain == null) return;
float t = _riseCurve.Evaluate(_controller.Progression);
float targetY = Mathf.Lerp(_startY, _endY, t);
Vector3 pos = _sandTerrain.position;
pos.y = Mathf.Lerp(pos.y, targetY, Time.deltaTime * _lerpSpeed);
_sandTerrain.position = pos;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cb5cadc4360bf0d4a8b6d071a76cc0b7