Snapshot before project reorganization

This commit is contained in:
2026-02-12 16:28:36 +01:00
parent 8758d6eaeb
commit 9b7bb2aa62
27 changed files with 1864 additions and 119 deletions
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -158,7 +158,7 @@ MonoBehaviour:
UseName: 1 UseName: 1
Sprite: {fileID: 0} Sprite: {fileID: 0}
Languages: Languages:
Default: 1 Default: 0
SaveWritten: {fileID: 11400000, guid: 32dca1ce9df9b064b8a0a2b3ab0fd8dd, type: 2} SaveWritten: {fileID: 11400000, guid: 32dca1ce9df9b064b8a0a2b3ab0fd8dd, type: 2}
SaveAudio: {fileID: 11400000, guid: 225ffb773e59f8141bacbba2a9ede731, type: 2} SaveAudio: {fileID: 11400000, guid: 225ffb773e59f8141bacbba2a9ede731, type: 2}
Overrides: [] Overrides: []
@@ -12,16 +12,18 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3e231c75dddecc0469543c190a9234b1, type: 3} m_Script: {fileID: 11500000, guid: 3e231c75dddecc0469543c190a9234b1, type: 3}
m_Name: DefaultCameraPanSettings m_Name: DefaultCameraPanSettings
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Data.CameraSettings.CameraPanSettings m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Data.CameraSettings.CameraPanSettings
PanMode: 0
PanSpeed: 3 PanSpeed: 3
PanBorderSize: 0.05 PanBorderSize: 0
MaxPanAngle: 10 MaxPanAngleX: 10
EnableRecentering: 0 MaxPanAngleY: 10
RecenterSpeed: 2 EnableRecentering: 1
RecenterDelay: 0.1 RecenterSpeed: 3
RecenterDelay: 0
AlignmentSpeed: 3 AlignmentSpeed: 3
AlignmentThreshold: 0.5 AlignmentThreshold: 0.5
DisableHeadBob: 1 FixedDistanceFromTarget: 2
ForceIdleHeadBob: 1 HeadBobMode: 2
UseSmoothStep: 1 UseSmoothStep: 1
AlignmentCurve: AlignmentCurve:
serializedVersion: 2 serializedVersion: 2
@@ -12,19 +12,40 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3e231c75dddecc0469543c190a9234b1, type: 3} m_Script: {fileID: 11500000, guid: 3e231c75dddecc0469543c190a9234b1, type: 3}
m_Name: DetectiveBoardPanSettings m_Name: DetectiveBoardPanSettings
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Data.CameraSettings.CameraPanSettings m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Data.CameraSettings.CameraPanSettings
PanSpeed: 2 PanMode: 1
PanSpeed: 3
PanBorderSize: 0.15 PanBorderSize: 0.15
MaxPanAngle: 45 MaxPanAngleX: 50
MaxPanAngleY: 30
EnableRecentering: 0 EnableRecentering: 0
RecenterSpeed: 0.5 RecenterSpeed: 0.5
RecenterDelay: 0.1 RecenterDelay: 0.1
AlignmentSpeed: 4 AlignmentSpeed: 4
AlignmentThreshold: 0.5 AlignmentThreshold: 0.5
FixedDistanceFromTarget: 4
HeadBobMode: 1 HeadBobMode: 1
UseSmoothStep: 1 UseSmoothStep: 1
AlignmentCurve: AlignmentCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: [] m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
@@ -0,0 +1,51 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3e231c75dddecc0469543c190a9234b1, type: 3}
m_Name: ListeningWallPanSettings
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Data.CameraSettings.CameraPanSettings
PanMode: 0
PanSpeed: 3
PanBorderSize: 0
MaxPanAngleX: 10
MaxPanAngleY: 10
EnableRecentering: 1
RecenterSpeed: 3
RecenterDelay: 0
AlignmentSpeed: 3
AlignmentThreshold: 0.5
FixedDistanceFromTarget: 4
HeadBobMode: 2
UseSmoothStep: 1
AlignmentCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 2
outSlope: 2
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3de044c9cf65729459b4104016637568
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -13,7 +13,7 @@ MonoBehaviour:
m_Name: ConversationDemoNPC m_Name: ConversationDemoNPC
m_EditorClassIdentifier: Assembly-CSharp::DialogueConversation m_EditorClassIdentifier: Assembly-CSharp::DialogueConversation
SpeakerName: Interlocuteur SpeakerName: Interlocuteur
DisplayMode: 1 DisplayMode: 0
DialogueNodes: DialogueNodes:
- {fileID: 11400000, guid: e6358f99b82fd39408e3272866b51c49, type: 2} - {fileID: 11400000, guid: e6358f99b82fd39408e3272866b51c49, type: 2}
- {fileID: 11400000, guid: f40a3fc5fb3ead644af358428fc5dc54, type: 2} - {fileID: 11400000, guid: f40a3fc5fb3ead644af358428fc5dc54, type: 2}
@@ -175,8 +175,6 @@ MonoBehaviour:
_continuousBaseVolume: 0.1 _continuousBaseVolume: 0.1
_hearingRangeMin: 2 _hearingRangeMin: 2
_hearingRangeMax: 8 _hearingRangeMax: 8
_listeningVolumeMultiplier: 3
_proximityVolumeMultiplier: 1.5
_reverbWetMix: 0.5 _reverbWetMix: 0.5
_staticAudioClip: {fileID: 0} _staticAudioClip: {fileID: 0}
_loopStaticAudio: 1 _loopStaticAudio: 1
@@ -211,11 +209,8 @@ MonoBehaviour:
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
_enableVibration: 1
_vibrationIntensityMin: 0.1
_vibrationIntensityMax: 0.3
_vibrationFrequency: 10
_emitterParticles: {fileID: 325388660204886872} _emitterParticles: {fileID: 325388660204886872}
_cameraPanSettings: {fileID: 11400000, guid: 3de044c9cf65729459b4104016637568, type: 2}
--- !u!65 &7881895566796712951 --- !u!65 &7881895566796712951
BoxCollider: BoxCollider:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -376,8 +376,8 @@ MonoBehaviour:
m_faceColor: m_faceColor:
serializedVersion: 2 serializedVersion: 2
rgba: 4294967295 rgba: 4294967295
m_fontSize: 10 m_fontSize: 15
m_fontSizeBase: 10 m_fontSizeBase: 15
m_fontWeight: 400 m_fontWeight: 400
m_enableAutoSizing: 0 m_enableAutoSizing: 0
m_fontSizeMin: 18 m_fontSizeMin: 18
@@ -215,8 +215,12 @@ PrefabInstance:
objectReference: {fileID: 461820781} objectReference: {fileID: 461820781}
- target: {fileID: 2754275979338379208, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3} - target: {fileID: 2754275979338379208, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3}
propertyPath: m_Enabled propertyPath: m_Enabled
value: 0 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 2754275979338379208, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3}
propertyPath: Conversation
value:
objectReference: {fileID: 11400000, guid: e9616b580e808fc4db9990454a298402, type: 2}
- target: {fileID: 2757010966349118316, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3} - target: {fileID: 2757010966349118316, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3}
propertyPath: m_Layer propertyPath: m_Layer
value: 7 value: 7
@@ -307,7 +311,7 @@ PrefabInstance:
objectReference: {fileID: 1929366845} objectReference: {fileID: 1929366845}
- target: {fileID: 8209576767969738346, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3} - target: {fileID: 8209576767969738346, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3}
propertyPath: m_VersionIndex propertyPath: m_VersionIndex
value: 6127 value: 6130
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 8358850242504541279, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3} - target: {fileID: 8358850242504541279, guid: 69f9e42d2acbf0344981fcdffd02d588, type: 3}
propertyPath: m_Layer propertyPath: m_Layer
@@ -1450,6 +1454,7 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
m_Bits: 128 m_Bits: 128
_boardController: {fileID: 0} _boardController: {fileID: 0}
_minInteractionDistance: 0.1
_maxInteractionDistance: 5 _maxInteractionDistance: 5
--- !u!1001 &996694521 --- !u!1001 &996694521
PrefabInstance: PrefabInstance:
@@ -1531,6 +1536,10 @@ PrefabInstance:
propertyPath: m_Mesh propertyPath: m_Mesh
value: value:
objectReference: {fileID: 362502328} objectReference: {fileID: 362502328}
- target: {fileID: 8209576767969738346, guid: 20e4ea3ceee86dd4ba3881425b65790d, type: 3}
propertyPath: m_VersionIndex
value: 5872
objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents: []
m_RemovedGameObjects: [] m_RemovedGameObjects: []
m_AddedGameObjects: [] m_AddedGameObjects: []
@@ -4216,6 +4225,10 @@ PrefabInstance:
propertyPath: _lookAction propertyPath: _lookAction
value: value:
objectReference: {fileID: 1891814281} objectReference: {fileID: 1891814281}
- target: {fileID: 953069181646740290, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: _defaultSettings
value:
objectReference: {fileID: 11400000, guid: 9973a518f73c3c1489819494e37d0980, type: 2}
- target: {fileID: 953069181646740290, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3} - target: {fileID: 953069181646740290, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: _playerTransform propertyPath: _playerTransform
value: value:
@@ -4318,7 +4331,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3} - target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: m_LocalPosition.x propertyPath: m_LocalPosition.x
value: 18.6 value: 22.1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3} - target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: m_LocalPosition.y propertyPath: m_LocalPosition.y
@@ -4326,7 +4339,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3} - target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: m_LocalPosition.z propertyPath: m_LocalPosition.z
value: 65.2 value: 69.2
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3} - target: {fileID: 5383576672370031505, guid: 92d3cde0c88c75f48a98d082c573338b, type: 3}
propertyPath: m_LocalRotation.w propertyPath: m_LocalRotation.w
@@ -2,6 +2,7 @@ using System.Collections;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using Unheimlich.Utility; using Unheimlich.Utility;
using Unheimlich.Data.CameraSettings;
namespace Unheimlich.Audio namespace Unheimlich.Audio
{ {
@@ -61,6 +62,9 @@ namespace Unheimlich.Audio
[Header("Visual Feedback")] [Header("Visual Feedback")]
[SerializeField] private ParticleSystem _emitterParticles; [SerializeField] private ParticleSystem _emitterParticles;
[Header("Camera Settings")]
[SerializeField] private CameraPanSettings _cameraPanSettings;
private AudioSource _audioSource; private AudioSource _audioSource;
private AudioSource _continuousAudioSource; private AudioSource _continuousAudioSource;
@@ -81,6 +85,11 @@ namespace Unheimlich.Audio
/// Used to prevent multiple taps on the same emitter. /// Used to prevent multiple taps on the same emitter.
/// </summary> /// </summary>
public bool HasBeenTapped => _hasBeenTapped; public bool HasBeenTapped => _hasBeenTapped;
/// <summary>
/// Returns the camera pan settings for this emitter, or null if not set.
/// </summary>
public CameraPanSettings CameraPanSettings => _cameraPanSettings;
private void Awake() private void Awake()
{ {
@@ -2,6 +2,15 @@ using UnityEngine;
namespace Unheimlich.Data.CameraSettings namespace Unheimlich.Data.CameraSettings
{ {
/// <summary>
/// Camera pan mode.
/// </summary>
public enum CameraPanMode
{
Pan,
FreeLook
}
/// <summary> /// <summary>
/// Head bob mode for camera pan. /// Head bob mode for camera pan.
/// </summary> /// </summary>
@@ -19,6 +28,10 @@ namespace Unheimlich.Data.CameraSettings
[CreateAssetMenu(fileName = "CameraPanSettings", menuName = "Unheimlich/Camera/Camera Pan Settings")] [CreateAssetMenu(fileName = "CameraPanSettings", menuName = "Unheimlich/Camera/Camera Pan Settings")]
public class CameraPanSettings : ScriptableObject public class CameraPanSettings : ScriptableObject
{ {
[Header("Pan Mode")]
[Tooltip("Pan: Smooth edge-based panning for object inspection | FreeLook: Direct mouse/stick control for detective board")]
public CameraPanMode PanMode = CameraPanMode.Pan;
[Header("Camera Pan")] [Header("Camera Pan")]
[Tooltip("Camera pan speed when moving the cursor/look stick")] [Tooltip("Camera pan speed when moving the cursor/look stick")]
public float PanSpeed = 2f; public float PanSpeed = 2f;
@@ -27,8 +40,11 @@ namespace Unheimlich.Data.CameraSettings
[Range(0f, 0.5f)] [Range(0f, 0.5f)]
public float PanBorderSize = 0.1f; public float PanBorderSize = 0.1f;
[Tooltip("Maximum angle the camera can pan from center")] [Tooltip("Maximum horizontal angle the camera can pan from center (left/right)")]
public float MaxPanAngle = 15f; public float MaxPanAngleX = 15f;
[Tooltip("Maximum vertical angle the camera can pan from center (up/down)")]
public float MaxPanAngleY = 15f;
[Header("Recentering")] [Header("Recentering")]
[Tooltip("Enable automatic return to center when idle")] [Tooltip("Enable automatic return to center when idle")]
@@ -47,6 +63,9 @@ namespace Unheimlich.Data.CameraSettings
[Tooltip("Threshold for alignment completion")] [Tooltip("Threshold for alignment completion")]
public float AlignmentThreshold = 0.5f; public float AlignmentThreshold = 0.5f;
[Tooltip("Fixed distance from the player to the target when aligning (in meters)")]
public float FixedDistanceFromTarget = 1.5f;
[Header("Head Bob Control")] [Header("Head Bob Control")]
[Tooltip("Head bob mode: Normal (default behavior), Idle (force subtle breathing), Disabled (no movement)")] [Tooltip("Head bob mode: Normal (default behavior), Idle (force subtle breathing), Disabled (no movement)")]
public HeadBobMode HeadBobMode = HeadBobMode.Idle; public HeadBobMode HeadBobMode = HeadBobMode.Idle;
@@ -1,6 +1,5 @@
using UnityEngine; using UnityEngine;
using UnityEditor; using UnityEditor;
using System.Collections.Generic;
using Unheimlich.Data.Dialogues; using Unheimlich.Data.Dialogues;
[CustomEditor(typeof(DialogueConversation))] [CustomEditor(typeof(DialogueConversation))]
@@ -99,7 +98,7 @@ public class DialogueConversationEditor : Editor
string path = AssetDatabase.GetAssetPath(conversation); string path = AssetDatabase.GetAssetPath(conversation);
string directory = System.IO.Path.GetDirectoryName(path); string directory = System.IO.Path.GetDirectoryName(path);
DialogueNode newNode = ScriptableObject.CreateInstance<DialogueNode>(); DialogueNode newNode = CreateInstance<DialogueNode>();
newNode.name = $"Node_{conversation.DialogueNodes.Count + 1}"; newNode.name = $"Node_{conversation.DialogueNodes.Count + 1}";
string nodePath = AssetDatabase.GenerateUniqueAssetPath($"{directory}/{newNode.name}.asset"); string nodePath = AssetDatabase.GenerateUniqueAssetPath($"{directory}/{newNode.name}.asset");
@@ -9,6 +9,9 @@ namespace Unheimlich.Gameplay.CameraControl
/// <summary> /// <summary>
/// Handles camera panning and player/camera alignment to targets. /// Handles camera panning and player/camera alignment to targets.
/// Uses CameraPanSettings ScriptableObject for configuration. /// Uses CameraPanSettings ScriptableObject for configuration.
/// Supports two modes:
/// - Pan: Smooth panning with edge detection (for object inspection)
/// - FreeLook: Direct mouse/stick control with angle clamping (for detective board)
/// </summary> /// </summary>
public class CameraPanController : MonoBehaviour public class CameraPanController : MonoBehaviour
{ {
@@ -16,8 +19,10 @@ namespace Unheimlich.Gameplay.CameraControl
[SerializeField] private UnityEngine.Camera _camera; [SerializeField] private UnityEngine.Camera _camera;
[SerializeField] private Transform _playerTransform; [SerializeField] private Transform _playerTransform;
[Header("Settings")] [Header("Default Settings")]
[SerializeField] private CameraPanSettings _settings; [SerializeField] private CameraPanSettings _defaultSettings;
private CameraPanSettings _settings;
private Vector2 _originalCameraRotation; private Vector2 _originalCameraRotation;
private Vector3 _originalCameraLocalPosition; private Vector3 _originalCameraLocalPosition;
@@ -28,7 +33,17 @@ namespace Unheimlich.Gameplay.CameraControl
private Coroutine _returnCoroutine; private Coroutine _returnCoroutine;
private float _timeSinceLastInput; private float _timeSinceLastInput;
private float _targetYaw;
private float _targetPitch;
private float _currentYaw;
private float _currentPitch;
private float _lerpSpeed;
private bool _needsUpdate;
private CameraPanMode _mode = CameraPanMode.Pan;
private Vector2 _lastMousePosition;
public bool IsPanning { get; private set; } public bool IsPanning { get; private set; }
public CameraPanMode Mode => _mode;
public CameraPanSettings Settings public CameraPanSettings Settings
{ {
@@ -52,10 +67,39 @@ namespace Unheimlich.Gameplay.CameraControl
_originalPlayerPosition = _playerTransform.position; _originalPlayerPosition = _playerTransform.position;
_originalPlayerRotation = _playerTransform.eulerAngles; _originalPlayerRotation = _playerTransform.eulerAngles;
if (_settings == null && _defaultSettings != null)
_settings = _defaultSettings;
}
private void LateUpdate()
{
if (IsPanning && _needsUpdate)
{
if (_mode == CameraPanMode.FreeLook)
{
float normalizedYaw = Mathf.Repeat(_currentYaw, 360f);
float normalizedPitch = _currentPitch;
_playerTransform.eulerAngles = new Vector3(0f, normalizedYaw, 0f);
_camera.transform.localEulerAngles = new Vector3(normalizedPitch, 0f, 0f);
}
else
{
_currentYaw = Mathf.LerpAngle(_currentYaw, _targetYaw, Time.deltaTime * _lerpSpeed);
_currentPitch = Mathf.LerpAngle(_currentPitch, _targetPitch, Time.deltaTime * _lerpSpeed);
float normalizedYaw = Mathf.Repeat(_currentYaw, 360f);
float normalizedPitch = _currentPitch;
_playerTransform.eulerAngles = new Vector3(0f, normalizedYaw, 0f);
_camera.transform.localEulerAngles = new Vector3(normalizedPitch, 0f, 0f);
}
}
} }
/// <summary> /// <summary>
/// Starts camera pan mode. /// Starts camera pan mode. The mode (Pan or FreeLook) is determined by the current settings.
/// </summary> /// </summary>
public void StartPan() public void StartPan()
{ {
@@ -66,13 +110,26 @@ namespace Unheimlich.Gameplay.CameraControl
} }
IsPanning = true; IsPanning = true;
_mode = _settings.PanMode;
_timeSinceLastInput = 0f; _timeSinceLastInput = 0f;
if (Mouse.current != null)
_lastMousePosition = Mouse.current.position.ReadValue();
float currentPitch = _camera.transform.localEulerAngles.x; float currentPitch = _camera.transform.localEulerAngles.x;
if (currentPitch > 180f) if (currentPitch > 180f)
currentPitch -= 360f; currentPitch -= 360f;
_originalCameraRotation = new Vector2(_playerTransform.eulerAngles.y, currentPitch); float currentYaw = _playerTransform.eulerAngles.y;
if (currentYaw > 180f)
currentYaw -= 360f;
_originalCameraRotation = new Vector2(currentYaw, currentPitch);
_currentYaw = currentYaw;
_currentPitch = currentPitch;
_targetYaw = currentYaw;
_targetPitch = currentPitch;
_needsUpdate = false;
} }
/// <summary> /// <summary>
@@ -88,6 +145,52 @@ namespace Unheimlich.Gameplay.CameraControl
/// Call this from Update when pan is active. /// Call this from Update when pan is active.
/// </summary> /// </summary>
public void UpdatePan() public void UpdatePan()
{
if (!IsPanning || _camera == null || _settings == null)
return;
if (_mode == CameraPanMode.FreeLook)
{
UpdateFreeLook();
}
else
{
UpdatePanMode();
}
}
private void UpdateFreeLook()
{
float lookX = 0f;
float lookY = 0f;
bool hasInput = false;
var lookAction = PlayerInput.GetLookAction();
if (lookAction != null)
{
Vector2 lookInput = lookAction.ReadValue<Vector2>();
if (lookInput.sqrMagnitude > 0.01f)
{
lookX = lookInput.x;
lookY = lookInput.y;
hasInput = true;
}
}
if (hasInput)
{
float sensitivity = _settings.PanSpeed * 0.1f;
_currentYaw += lookX * sensitivity;
_currentPitch -= lookY * sensitivity;
_currentYaw = Mathf.Clamp(_currentYaw, _originalCameraRotation.x - _settings.MaxPanAngleX, _originalCameraRotation.x + _settings.MaxPanAngleX);
_currentPitch = Mathf.Clamp(_currentPitch, _originalCameraRotation.y - _settings.MaxPanAngleY, _originalCameraRotation.y + _settings.MaxPanAngleY);
_needsUpdate = true;
}
}
private void UpdatePanMode()
{ {
if (!IsPanning || _camera == null || _settings == null) if (!IsPanning || _camera == null || _settings == null)
return; return;
@@ -111,31 +214,38 @@ namespace Unheimlich.Gameplay.CameraControl
if (!hasInput && Mouse.current != null) if (!hasInput && Mouse.current != null)
{ {
Vector2 mousePos = Mouse.current.position.ReadValue(); Vector2 mousePos = Mouse.current.position.ReadValue();
float screenWidth = Screen.width;
float screenHeight = Screen.height;
float borderPixels = _settings.PanBorderSize * Mathf.Min(screenWidth, screenHeight); bool mouseHasMoved = Vector2.Distance(mousePos, _lastMousePosition) > 0.1f;
_lastMousePosition = mousePos;
if (mousePos.x < borderPixels) if (mouseHasMoved)
{ {
panX = -(borderPixels - mousePos.x) / borderPixels; float screenWidth = Screen.width;
hasInput = true; float screenHeight = Screen.height;
}
else if (mousePos.x > screenWidth - borderPixels) float borderPixels = _settings.PanBorderSize * Mathf.Min(screenWidth, screenHeight);
{
panX = (mousePos.x - (screenWidth - borderPixels)) / borderPixels; if (mousePos.x < borderPixels)
hasInput = true; {
} panX = -(borderPixels - mousePos.x) / borderPixels;
hasInput = true;
if (mousePos.y < borderPixels) }
{ else if (mousePos.x > screenWidth - borderPixels)
panY = -(borderPixels - mousePos.y) / borderPixels; {
hasInput = true; panX = (mousePos.x - (screenWidth - borderPixels)) / borderPixels;
} hasInput = true;
else if (mousePos.y > screenHeight - borderPixels) }
{
panY = (mousePos.y - (screenHeight - borderPixels)) / borderPixels; if (mousePos.y < borderPixels)
hasInput = true; {
panY = -(borderPixels - mousePos.y) / borderPixels;
hasInput = true;
}
else if (mousePos.y > screenHeight - borderPixels)
{
panY = (mousePos.y - (screenHeight - borderPixels)) / borderPixels;
hasInput = true;
}
} }
} }
@@ -148,48 +258,39 @@ namespace Unheimlich.Gameplay.CameraControl
_timeSinceLastInput += Time.deltaTime; _timeSinceLastInput += Time.deltaTime;
} }
float currentYaw = _playerTransform.eulerAngles.y;
float currentPitch = _camera.transform.localEulerAngles.x;
if (currentPitch > 180f)
currentPitch -= 360f;
float targetYaw;
float targetPitch;
float lerpSpeed;
bool shouldRecenter = _settings.EnableRecentering && _timeSinceLastInput >= _settings.RecenterDelay; bool shouldRecenter = _settings.EnableRecentering && _timeSinceLastInput >= _settings.RecenterDelay;
if (hasInput) if (hasInput)
{ {
targetYaw = _originalCameraRotation.x + panX * _settings.MaxPanAngle; _targetYaw = _originalCameraRotation.x + panX * _settings.MaxPanAngleX;
targetPitch = _originalCameraRotation.y - panY * _settings.MaxPanAngle; _targetPitch = _originalCameraRotation.y - panY * _settings.MaxPanAngleY;
targetYaw = Mathf.Clamp(targetYaw, _originalCameraRotation.x - _settings.MaxPanAngle, _originalCameraRotation.x + _settings.MaxPanAngle); _targetYaw = Mathf.Clamp(_targetYaw, _originalCameraRotation.x - _settings.MaxPanAngleX, _originalCameraRotation.x + _settings.MaxPanAngleX);
targetPitch = Mathf.Clamp(targetPitch, _originalCameraRotation.y - _settings.MaxPanAngle, _originalCameraRotation.y + _settings.MaxPanAngle); _targetPitch = Mathf.Clamp(_targetPitch, _originalCameraRotation.y - _settings.MaxPanAngleY, _originalCameraRotation.y + _settings.MaxPanAngleY);
lerpSpeed = _settings.PanSpeed; _lerpSpeed = _settings.PanSpeed;
_needsUpdate = true;
} }
else if (shouldRecenter) else if (shouldRecenter)
{ {
targetYaw = _originalCameraRotation.x; _targetYaw = _originalCameraRotation.x;
targetPitch = _originalCameraRotation.y; _targetPitch = _originalCameraRotation.y;
lerpSpeed = _settings.RecenterSpeed; _lerpSpeed = _settings.RecenterSpeed;
_needsUpdate = true;
} }
else else if (_needsUpdate)
{ {
targetYaw = currentYaw; float yawDiff = Mathf.Abs(Mathf.DeltaAngle(_currentYaw, _targetYaw));
targetPitch = currentPitch; float pitchDiff = Mathf.Abs(Mathf.DeltaAngle(_currentPitch, _targetPitch));
lerpSpeed = 0f;
if (yawDiff < 0.01f && pitchDiff < 0.01f)
{
_needsUpdate = false;
}
} }
float newYaw = Mathf.LerpAngle(currentYaw, targetYaw, Time.deltaTime * lerpSpeed);
float newPitch = Mathf.LerpAngle(currentPitch, targetPitch, Time.deltaTime * lerpSpeed);
_playerTransform.eulerAngles = new Vector3(0f, newYaw, 0f);
_camera.transform.localEulerAngles = new Vector3(newPitch, 0f, 0f);
} }
/// <summary> /// <summary>
/// Aligns the player and camera to the target object. /// Aligns the player and camera to the target object.
/// - Player moves along target's local X axis to align with target center /// - Player moves to a fixed distance in front of the target
/// - Player rotates to face the target /// - Player rotates to face the target
/// - Camera pitch adjusts to look at target center /// - Camera pitch adjusts to look at target center
/// </summary> /// </summary>
@@ -259,6 +360,10 @@ namespace Unheimlich.Gameplay.CameraControl
if (startPitch > 180f) if (startPitch > 180f)
startPitch -= 360f; startPitch -= 360f;
Vector3 targetForward = target.forward;
Vector3 targetPlayerPos = targetCenter - targetForward * _settings.FixedDistanceFromTarget;
targetPlayerPos.y = startPlayerPos.y;
float elapsed = 0f; float elapsed = 0f;
float duration = 1f / _settings.AlignmentSpeed; float duration = 1f / _settings.AlignmentSpeed;
@@ -275,11 +380,6 @@ namespace Unheimlich.Gameplay.CameraControl
float targetYaw = targetRotation.eulerAngles.y; float targetYaw = targetRotation.eulerAngles.y;
float targetPitch = -Mathf.Asin(directionToTarget.y) * Mathf.Rad2Deg; float targetPitch = -Mathf.Asin(directionToTarget.y) * Mathf.Rad2Deg;
Vector3 targetRightAxis = target.right;
Vector3 playerToTargetCenter = targetCenter - _playerTransform.position;
float offsetAlongTargetRight = Vector3.Dot(playerToTargetCenter, targetRightAxis);
Vector3 targetPlayerPos = _playerTransform.position + targetRightAxis * offsetAlongTargetRight;
Vector3 currentPlayerPos = Vector3.Lerp(startPlayerPos, targetPlayerPos, t); Vector3 currentPlayerPos = Vector3.Lerp(startPlayerPos, targetPlayerPos, t);
_playerTransform.position = currentPlayerPos; _playerTransform.position = currentPlayerPos;
@@ -23,7 +23,7 @@ namespace Unheimlich.Gameplay.Environment
InteractionText = IsOpen ? "Close" : "Open"; InteractionText = IsOpen ? "Close" : "Open";
} }
public override void Interact(GameObject interactor) public override void Interact()
{ {
ToggleDoor(); ToggleDoor();
} }
@@ -41,7 +41,7 @@ namespace Unheimlich.Gameplay.Items
_levitatingObject = GetComponent<LevitatingObject>(); _levitatingObject = GetComponent<LevitatingObject>();
} }
public override void Interact(GameObject interactor) public override void Interact()
{ {
if (_blockInteractionDuringAnimation) if (_blockInteractionDuringAnimation)
{ {
@@ -25,6 +25,7 @@ namespace Unheimlich.Gameplay.Player
private HeadBobMode _overrideMode = HeadBobMode.Normal; private HeadBobMode _overrideMode = HeadBobMode.Normal;
private bool _hasOverride = false; private bool _hasOverride = false;
private Coroutine _resetCoroutine;
void Start() void Start()
{ {
@@ -80,6 +81,40 @@ namespace Unheimlich.Gameplay.Player
public void ClearOverride() public void ClearOverride()
{ {
_hasOverride = false; _hasOverride = false;
if (_resetCoroutine != null)
{
StopCoroutine(_resetCoroutine);
_resetCoroutine = null;
}
}
/// <summary>
/// Smoothly lerps the head bob position to zero over the specified duration.
/// </summary>
public void LerpToZero(float duration)
{
if (_resetCoroutine != null)
StopCoroutine(_resetCoroutine);
_resetCoroutine = StartCoroutine(LerpToZeroCoroutine(duration));
}
private System.Collections.IEnumerator LerpToZeroCoroutine(float duration)
{
Vector3 startPos = transform.localPosition;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
transform.localPosition = Vector3.Lerp(startPos, Vector3.zero, t);
yield return null;
}
transform.localPosition = Vector3.zero;
_resetCoroutine = null;
} }
private void ApplyBob(float speed, float amplitude) private void ApplyBob(float speed, float amplitude)
@@ -66,6 +66,7 @@ namespace Unheimlich.Gameplay.Player
private AudioListenable _currentTargetEmitter; private AudioListenable _currentTargetEmitter;
private AudioSource _playerAudioSource; private AudioSource _playerAudioSource;
private Coroutine _listeningCoroutine; private Coroutine _listeningCoroutine;
private Coroutine _vibrationCoroutine;
private int _diapasonTweenId = -1; private int _diapasonTweenId = -1;
private int _audioListenerFadeTweenId = -1; private int _audioListenerFadeTweenId = -1;
private int _playerAudioFadeTweenId = -1; private int _playerAudioFadeTweenId = -1;
@@ -74,7 +75,9 @@ namespace Unheimlich.Gameplay.Player
private Vector3 _diapasonHiddenPosition; private Vector3 _diapasonHiddenPosition;
private bool _canUseDiapason; private bool _canUseDiapason;
private bool _isFadingOutConcentration; private bool _isFadingOutConcentration;
private Coroutine _vibrationCoroutine;
private CameraHeadBob _cameraHeadBob;
private CameraPanSettings _originalCameraSettings;
protected override void OnAwake() protected override void OnAwake()
{ {
@@ -91,6 +94,8 @@ namespace Unheimlich.Gameplay.Player
_cameraPanController = gameObject.AddComponent<CameraPanController>(); _cameraPanController = gameObject.AddComponent<CameraPanController>();
} }
} }
_cameraHeadBob = GetComponentInChildren<CameraHeadBob>();
if (_diapasonObject != null) if (_diapasonObject != null)
{ {
@@ -236,6 +241,10 @@ namespace Unheimlich.Gameplay.Player
if (_currentTargetEmitter != null && _cameraPanController != null) if (_currentTargetEmitter != null && _cameraPanController != null)
{ {
_originalCameraSettings = _cameraPanController.Settings;
if(_currentTargetEmitter.CameraPanSettings != null)
_cameraPanController.Settings = _currentTargetEmitter.CameraPanSettings;
_currentTargetEmitter.SetConcentrating(true); _currentTargetEmitter.SetConcentrating(true);
_cameraPanController.AlignToTarget(_currentTargetEmitter.transform); _cameraPanController.AlignToTarget(_currentTargetEmitter.transform);
@@ -263,18 +272,23 @@ namespace Unheimlich.Gameplay.Player
PlayBreathIn(); PlayBreathIn();
yield return new WaitForSeconds(_breathInDuration); yield return new WaitForSeconds(_breathInDuration);
if (_cameraHeadBob != null)
{
float resetDuration = _concentrationDuration - _breathInDuration;
_cameraHeadBob.LerpToZero(resetDuration);
}
yield return new WaitForSeconds(_concentrationDuration - _breathInDuration); yield return new WaitForSeconds(_concentrationDuration - _breathInDuration);
IsConcentrating = false; IsConcentrating = false;
IsListening = true; IsListening = true;
EnableVignette(true); EnableVignette(true);
if (_cameraPanController != null) ApplyHeadBobSettings(_cameraPanController.Settings);
{ _cameraPanController.StartPan();
_cameraPanController.StartPan();
}
Cursor.lockState = CursorLockMode.Confined; Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = false; Cursor.visible = false;
@@ -311,7 +325,15 @@ namespace Unheimlich.Gameplay.Player
{ {
_cameraPanController.StopPan(); _cameraPanController.StopPan();
_cameraPanController.ReturnToOriginalPosition(); _cameraPanController.ReturnToOriginalPosition();
if (_originalCameraSettings != null)
{
_cameraPanController.Settings = _originalCameraSettings;
_originalCameraSettings = null;
}
} }
RestoreHeadBob();
if (_playerAudioSource != null && _playerAudioSource.isPlaying) if (_playerAudioSource != null && _playerAudioSource.isPlaying)
{ {
@@ -528,6 +550,28 @@ namespace Unheimlich.Gameplay.Player
_vignetteEffect.SetIntensity(_vignetteIntensity); _vignetteEffect.SetIntensity(_vignetteIntensity);
} }
} }
/// <summary>
/// Applies head bob settings based on CameraPanSettings configuration.
/// </summary>
private void ApplyHeadBobSettings(CameraPanSettings settings)
{
if (_cameraHeadBob == null || settings == null)
return;
_cameraHeadBob.SetMode(settings.HeadBobMode);
}
/// <summary>
/// Restores head bob to normal behavior.
/// </summary>
private void RestoreHeadBob()
{
if (_cameraHeadBob == null)
return;
_cameraHeadBob.ClearOverride();
}
private void OnDrawGizmosSelected() private void OnDrawGizmosSelected()
{ {
@@ -21,7 +21,7 @@ namespace Unheimlich.Gameplay.Portals
/// Handles interaction with the door. /// Handles interaction with the door.
/// Toggles both this door and the linked portal's door simultaneously. /// Toggles both this door and the linked portal's door simultaneously.
/// </summary> /// </summary>
public override void Interact(GameObject interactor) public override void Interact()
{ {
SyncToggle(); SyncToggle();
} }
@@ -27,12 +27,12 @@ namespace Unheimlich.Handlers.DetectiveBoard
_inspectableItem = GetComponent<InspectableItem>(); _inspectableItem = GetComponent<InspectableItem>();
} }
public override void Interact(GameObject interactor) public override void Interact()
{ {
if (_unlockOnlyOnce && _hasUnlocked) if (_unlockOnlyOnce && _hasUnlocked)
{ {
if (_inspectableItem != null) if (_inspectableItem != null)
_inspectableItem.Interact(interactor); _inspectableItem.Interact();
return; return;
} }
@@ -40,7 +40,7 @@ namespace Unheimlich.Handlers.DetectiveBoard
{ {
Debug.LogError("[ClueUnlockOnInteraction] No clue data assigned!"); Debug.LogError("[ClueUnlockOnInteraction] No clue data assigned!");
if (_inspectableItem != null) if (_inspectableItem != null)
_inspectableItem.Interact(interactor); _inspectableItem.Interact();
return; return;
} }
@@ -54,7 +54,7 @@ namespace Unheimlich.Handlers.DetectiveBoard
if (_inspectableItem != null) if (_inspectableItem != null)
{ {
_inspectableItem.Interact(interactor); _inspectableItem.Interact();
} }
} }
} }
@@ -73,7 +73,7 @@ namespace Unheimlich.Interactions.Dialogues
} }
} }
public override void Interact(GameObject interactor) public override void Interact()
{ {
if (DialogueManager.Instance == null) if (DialogueManager.Instance == null)
return; return;
@@ -48,7 +48,7 @@ namespace Unheimlich.Interactions.Core
if (interactAction != null && interactAction.WasPressedThisFrame()) if (interactAction != null && interactAction.WasPressedThisFrame())
{ {
if (_currentInteractable != null) if (_currentInteractable != null)
_currentInteractable.Interact(transform.parent.gameObject); _currentInteractable.Interact();
} }
} }
@@ -12,6 +12,6 @@ namespace Unheimlich.Interactions.Core
[Tooltip("Text displayed when the player looks at the object")] [Tooltip("Text displayed when the player looks at the object")]
public string InteractionText = "Interact"; public string InteractionText = "Interact";
public abstract void Interact(GameObject gameObject); public abstract void Interact();
} }
} }
@@ -2,6 +2,8 @@ using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using UnityEngine.UI; using UnityEngine.UI;
using Unheimlich.Gameplay.DetectiveBoard; using Unheimlich.Gameplay.DetectiveBoard;
using System.Collections.Generic;
using UnityEngine.EventSystems;
namespace Unheimlich.UI.DetectiveBoard namespace Unheimlich.UI.DetectiveBoard
{ {
@@ -20,7 +22,8 @@ namespace Unheimlich.UI.DetectiveBoard
[SerializeField] private DetectiveBoardController _boardController; [SerializeField] private DetectiveBoardController _boardController;
[Header("Settings")] [Header("Settings")]
[SerializeField] private float _maxInteractionDistance = 5f; [SerializeField] private float _minInteractionDistance = 0.1f;
[SerializeField] private float _maxInteractionDistance = 10f;
private DetectiveBoardCanvas _canvasManager; private DetectiveBoardCanvas _canvasManager;
private PostItNode _hoveredNode; private PostItNode _hoveredNode;
@@ -253,26 +256,20 @@ namespace Unheimlich.UI.DetectiveBoard
private PostItNode RaycastForNode() private PostItNode RaycastForNode()
{ {
if (_camera == null) if (_camera == null || Mouse.current == null)
return null; return null;
Vector2 mousePos = Mouse.current.position.ReadValue(); Vector2 mousePos = Mouse.current.position.ReadValue();
Ray ray = _camera.ScreenPointToRay(new Vector3(mousePos.x, mousePos.y, 0));
if (Physics.Raycast(ray, out RaycastHit hit, _maxInteractionDistance, _boardLayer)) GraphicRaycaster raycaster = _boardCanvas?.GetComponent<GraphicRaycaster>();
if (raycaster != null && EventSystem.current != null)
{ {
return hit.collider.GetComponentInParent<PostItNode>(); var pointerEventData = new PointerEventData(EventSystem.current)
}
GraphicRaycaster raycaster = _boardCanvas.GetComponent<GraphicRaycaster>();
if (raycaster != null)
{
var pointerEventData = new UnityEngine.EventSystems.PointerEventData(UnityEngine.EventSystems.EventSystem.current)
{ {
position = mousePos position = mousePos
}; };
var results = new System.Collections.Generic.List<UnityEngine.EventSystems.RaycastResult>(); var results = new List<RaycastResult>();
raycaster.Raycast(pointerEventData, results); raycaster.Raycast(pointerEventData, results);
foreach (var result in results) foreach (var result in results)
@@ -283,6 +280,17 @@ namespace Unheimlich.UI.DetectiveBoard
} }
} }
Ray ray = _camera.ScreenPointToRay(new Vector3(mousePos.x, mousePos.y, 0));
if (Physics.Raycast(ray, out RaycastHit hit, _maxInteractionDistance, _boardLayer))
{
float distance = hit.distance;
if (distance >= _minInteractionDistance)
{
return hit.collider.GetComponentInParent<PostItNode>();
}
}
return null; return null;
} }
} }
+15
View File
@@ -1,5 +1,13 @@
{ {
"dependencies": { "dependencies": {
"com.bezi.sidekick": {
"version": "file:com.bezi.sidekick",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.nuget.newtonsoft-json": "3.2.1"
}
},
"com.coiriergraphics.octocore": { "com.coiriergraphics.octocore": {
"version": "file:OctoCore", "version": "file:OctoCore",
"depth": 0, "depth": 0,
@@ -108,6 +116,13 @@
"dependencies": {}, "dependencies": {},
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.nuget.newtonsoft-json": {
"version": "3.2.2",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.probuilder": { "com.unity.probuilder": {
"version": "6.0.8", "version": "6.0.8",
"depth": 0, "depth": 0,
+1 -1
View File
@@ -13,7 +13,7 @@ TagManager:
- UI - UI
- Words - Words
- DetectiveBoard - DetectiveBoard
- - Player
- -
- -
- -
+2
View File
@@ -1,5 +1,7 @@
<Solution> <Solution>
<Project Path="OctoCore.Runtime.csproj" />
<Project Path="Assembly-CSharp-Editor.csproj" /> <Project Path="Assembly-CSharp-Editor.csproj" />
<Project Path="OctoCore.Editor.csproj" />
<Project Path="Assembly-CSharp.csproj" /> <Project Path="Assembly-CSharp.csproj" />
<Project Path="Bezi.Editor.csproj" /> <Project Path="Bezi.Editor.csproj" />
</Solution> </Solution>