Hallucination system setup & implementation with the infinite staircase + Fake volumetric lights test

This commit is contained in:
Ferlat Thibaud
2026-03-27 20:47:11 +01:00
parent 34d8ffd5b0
commit 395f6266d6
119 changed files with 44996 additions and 816 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a2f7d3c1e76b6f846aab39c9a7b1e4d0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -1633,6 +1633,38 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 0}
--- !u!1 &1845264189797205937
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7672205835170601754}
m_Layer: 0
m_Name: Lights
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7672205835170601754
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1845264189797205937}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6106054514537176826}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1889871080664232389
GameObject:
m_ObjectHideFlags: 0
@@ -3610,6 +3642,133 @@ Transform:
- {fileID: 6973467451822970723}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &6561772198196289027
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6106054514537176826}
- component: {fileID: 1561383798565192954}
- component: {fileID: 1738007627916794377}
m_Layer: 0
m_Name: Point Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6106054514537176826
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6561772198196289027}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.022, y: 3.202, z: 0.234}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7672205835170601754}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!108 &1561383798565192954
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6561772198196289027}
m_Enabled: 1
serializedVersion: 12
m_Type: 2
m_Color: {r: 1, g: 0, b: 0, a: 1}
m_Intensity: 4
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize2D: {x: 0.5, y: 0.5}
m_Shadows:
m_Type: 0
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!114 &1738007627916794377
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6561772198196289027}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_CustomShadowLayers: 0
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
m_RenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_ShadowRenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_Version: 4
m_LightLayerMask: 1
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &6979416532364228759
GameObject:
m_ObjectHideFlags: 0
@@ -3723,6 +3882,38 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: -5597002278806442958, guid: b340aeaa8fe5ca74a8239f4c48a4696c, type: 3}
--- !u!1 &7034115035068831925
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6475416792363205640}
m_Layer: 0
m_Name: UI
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6475416792363205640
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7034115035068831925}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 955499211626523072}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7410487783548504890
GameObject:
m_ObjectHideFlags: 0
@@ -3822,6 +4013,9 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 3115487469603733110}
- component: {fileID: 3196745709285988896}
- component: {fileID: 1169680603367944815}
- component: {fileID: 4908208547457426222}
m_Layer: 0
m_Name: StairsBase
m_TagString: Untagged
@@ -3844,8 +4038,64 @@ Transform:
m_Children:
- {fileID: 7462909150206692446}
- {fileID: 4322600816427849986}
- {fileID: 7672205835170601754}
- {fileID: 6475416792363205640}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: -8.478, z: 0}
--- !u!114 &3196745709285988896
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba6fa2b368d1e4f4bb84bc6af9f777bc, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.World.Environment.StaircaseSegment
_floatingLabel: {fileID: 7750062444441923575}
_triggerZone: {fileID: 4908208547457426222}
--- !u!65 &1169680603367944815
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 1.36, y: 4.4, z: 0.19}
--- !u!114 &4908208547457426222
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e8fd091b4319d48448d266a24e885dae, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Hallucination.HallucinationTriggerZone
_playerTag: Player
_gizmoColor: {r: 0.8, g: 0.5, b: 0, a: 0.35}
_retriggerable: 0
_delay: 0
_insanityAmount: 0.2
_hallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
_debugMode: 0
--- !u!1 &7510013575371704646
GameObject:
m_ObjectHideFlags: 0
@@ -5885,3 +6135,160 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 0}
--- !u!1001 &4270977911979322757
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 6475416792363205640}
m_Modifications:
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.x
value: 5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.z
value: 0.34
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.x
value: 1.46
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.y
value: 5.7
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4914436633015142662, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Name
value: FloatingLabel
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _fadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _nearFadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxScaleFactor
value: 1.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _minScaleFactor
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionAngle
value: 20
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _referenceDistance
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxVisibleDistance
value: 2
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionMaxOffset
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableAdaptiveScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionSmoothness
value: 10
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableCameraAttraction
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 33aceb76d5023f1449962aa926352661, type: 3}
--- !u!224 &955499211626523072 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 4270977911979322757}
m_PrefabAsset: {fileID: 0}
--- !u!114 &7750062444441923575 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 4270977911979322757}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f7a1b2f9cb1305a4993ea145d8106942, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Dialogue.UI.FloatingLabel
@@ -180,6 +180,133 @@ MeshRenderer:
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &360911790044642849
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8956947484573171284}
- component: {fileID: 1577264711912511501}
- component: {fileID: 96103591199514260}
m_Layer: 0
m_Name: Point Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8956947484573171284
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 360911790044642849}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.022, y: 3.202, z: 0.234}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2987768322512944755}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!108 &1577264711912511501
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 360911790044642849}
m_Enabled: 1
serializedVersion: 12
m_Type: 2
m_Color: {r: 1, g: 0, b: 0, a: 1}
m_Intensity: 4
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize2D: {x: 0.5, y: 0.5}
m_Shadows:
m_Type: 0
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!114 &96103591199514260
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 360911790044642849}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_CustomShadowLayers: 0
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
m_RenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_ShadowRenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_Version: 4
m_LightLayerMask: 1
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &819338907545832048
GameObject:
m_ObjectHideFlags: 0
@@ -2989,6 +3116,38 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 5286422146015209900, guid: b340aeaa8fe5ca74a8239f4c48a4696c, type: 3}
--- !u!1 &2691063619121523093
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2800190164765913839}
m_Layer: 0
m_Name: UI
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2800190164765913839
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2691063619121523093}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2766370729047581692}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &3095778496435318250
GameObject:
m_ObjectHideFlags: 0
@@ -4729,6 +4888,9 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 3115487469603733110}
- component: {fileID: 3637708139523255913}
- component: {fileID: 1686286678689969582}
- component: {fileID: 5097639534055030786}
m_Layer: 0
m_Name: StairsEnd
m_TagString: Untagged
@@ -4749,10 +4911,66 @@ Transform:
m_LocalScale: {x: 1, y: 0.6, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2800190164765913839}
- {fileID: 2987768322512944755}
- {fileID: 7462909150206692446}
- {fileID: 4322600816427849986}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: -8.478, z: 0}
--- !u!65 &3637708139523255913
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 1.36, y: 4.4, z: 0.19}
--- !u!114 &1686286678689969582
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e8fd091b4319d48448d266a24e885dae, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Hallucination.HallucinationTriggerZone
_playerTag: Player
_gizmoColor: {r: 0.8, g: 0.5, b: 0, a: 0.35}
_retriggerable: 0
_delay: 0
_insanityAmount: 0.2
_hallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
_debugMode: 0
--- !u!114 &5097639534055030786
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba6fa2b368d1e4f4bb84bc6af9f777bc, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.World.Environment.StaircaseSegment
_floatingLabel: {fileID: 4659891109299693003}
_triggerZone: {fileID: 1686286678689969582}
--- !u!1 &7510013575371704646
GameObject:
m_ObjectHideFlags: 0
@@ -5617,6 +5835,38 @@ MeshRenderer:
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &8767460852810816191
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2987768322512944755}
m_Layer: 0
m_Name: Lights
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2987768322512944755
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8767460852810816191}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8956947484573171284}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &8848280139758936371
GameObject:
m_ObjectHideFlags: 0
@@ -7356,3 +7606,160 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 0}
--- !u!1001 &1180802050176346041
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 2800190164765913839}
m_Modifications:
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.x
value: 5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.z
value: 0.34
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.x
value: 1.46
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.y
value: 5.7
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4914436633015142662, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Name
value: FloatingLabel
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _fadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _nearFadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxScaleFactor
value: 1.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _minScaleFactor
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionAngle
value: 20
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _referenceDistance
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxVisibleDistance
value: 2
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionMaxOffset
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableAdaptiveScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionSmoothness
value: 10
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableCameraAttraction
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 33aceb76d5023f1449962aa926352661, type: 3}
--- !u!224 &2766370729047581692 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 1180802050176346041}
m_PrefabAsset: {fileID: 0}
--- !u!114 &4659891109299693003 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 1180802050176346041}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f7a1b2f9cb1305a4993ea145d8106942, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Dialogue.UI.FloatingLabel
@@ -180,6 +180,38 @@ MeshRenderer:
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &620311903638983490
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8898755505698834002}
m_Layer: 0
m_Name: Lights
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8898755505698834002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 620311903638983490}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5062939725246933975}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &819338907545832048
GameObject:
m_ObjectHideFlags: 0
@@ -2528,6 +2560,38 @@ MeshRenderer:
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &4281036021430497506
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5731161095573585393}
m_Layer: 0
m_Name: UI
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5731161095573585393
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4281036021430497506}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3985649632040779150}
m_Father: {fileID: 3115487469603733110}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &4534100704992238928
GameObject:
m_ObjectHideFlags: 0
@@ -2978,6 +3042,133 @@ MeshRenderer:
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &5342711050672588385
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5062939725246933975}
- component: {fileID: 6967713886787817316}
- component: {fileID: 5868647276013307504}
m_Layer: 0
m_Name: Point Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5062939725246933975
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5342711050672588385}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.022, y: 3.202, z: 0.234}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8898755505698834002}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!108 &6967713886787817316
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5342711050672588385}
m_Enabled: 1
serializedVersion: 12
m_Type: 2
m_Color: {r: 1, g: 0, b: 0, a: 1}
m_Intensity: 4
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize2D: {x: 0.5, y: 0.5}
m_Shadows:
m_Type: 0
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!114 &5868647276013307504
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5342711050672588385}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_CustomShadowLayers: 0
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
m_RenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_ShadowRenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_Version: 4
m_LightLayerMask: 1
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &5482332585898417170
GameObject:
m_ObjectHideFlags: 0
@@ -3704,6 +3895,9 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 3115487469603733110}
- component: {fileID: 1835344237701021809}
- component: {fileID: 2612053290384903047}
- component: {fileID: 7086844795149334991}
m_Layer: 0
m_Name: StairsStart
m_TagString: Untagged
@@ -3724,10 +3918,66 @@ Transform:
m_LocalScale: {x: 1, y: 0.6, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5731161095573585393}
- {fileID: 8898755505698834002}
- {fileID: 7462909150206692446}
- {fileID: 4322600816427849986}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: -8.478, z: 0}
--- !u!114 &1835344237701021809
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba6fa2b368d1e4f4bb84bc6af9f777bc, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.World.Environment.StaircaseSegment
_floatingLabel: {fileID: 5872837924559567801}
_triggerZone: {fileID: 7086844795149334991}
--- !u!65 &2612053290384903047
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 1.36, y: 4.4, z: 0.19}
--- !u!114 &7086844795149334991
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7463796094361621415}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e8fd091b4319d48448d266a24e885dae, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Hallucination.HallucinationTriggerZone
_playerTag: Player
_gizmoColor: {r: 0.8, g: 0.5, b: 0, a: 0.35}
_retriggerable: 0
_delay: 0
_insanityAmount: 0.2
_hallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
_debugMode: 0
--- !u!1 &7510013575371704646
GameObject:
m_ObjectHideFlags: 0
@@ -5252,113 +5502,39 @@ MonoBehaviour:
m_ManualUV: 0
elementGroup: -1
m_TextureGroup: -1
- m_Indexes: 520000005300000051000000520000005100000050000000
m_SmoothingGroup: -1
m_Uv:
m_UseWorldSpace: 0
m_FlipU: 0
m_FlipV: 0
m_SwapUV: 0
m_Fill: 1
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Rotation: 0
m_Anchor: 9
m_Material: {fileID: 0}
m_SubmeshIndex: 0
m_ManualUV: 0
elementGroup: -1
m_TextureGroup: -1
- m_Indexes: 560000005700000055000000560000005500000054000000
m_SmoothingGroup: -1
m_Uv:
m_UseWorldSpace: 0
m_FlipU: 0
m_FlipV: 0
m_SwapUV: 0
m_Fill: 1
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Rotation: 0
m_Anchor: 9
m_Material: {fileID: 0}
m_SubmeshIndex: 0
m_ManualUV: 0
elementGroup: -1
m_TextureGroup: -1
- m_Indexes: 5a0000005b000000590000005a0000005900000058000000
m_SmoothingGroup: -1
m_Uv:
m_UseWorldSpace: 0
m_FlipU: 0
m_FlipV: 0
m_SwapUV: 0
m_Fill: 1
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Rotation: 0
m_Anchor: 9
m_Material: {fileID: 0}
m_SubmeshIndex: 0
m_ManualUV: 0
elementGroup: -1
m_TextureGroup: -1
- m_Indexes: 5e0000005f0000005d0000005e0000005d0000005c000000
m_SmoothingGroup: -1
m_Uv:
m_UseWorldSpace: 0
m_FlipU: 0
m_FlipV: 0
m_SwapUV: 0
m_Fill: 1
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Rotation: 0
m_Anchor: 9
m_Material: {fileID: 0}
m_SubmeshIndex: 0
m_ManualUV: 0
elementGroup: -1
m_TextureGroup: -1
m_SharedVertices:
- m_Vertices: 000000001e000000
- m_Vertices: 010000001f000000200000003e000000
- m_Vertices: 00000000
- m_Vertices: 0100000018000000
- m_Vertices: 0200000004000000
- m_Vertices: 03000000050000002200000024000000
- m_Vertices: 03000000050000001a0000001c000000
- m_Vertices: 0600000008000000
- m_Vertices: 07000000090000002600000028000000
- m_Vertices: 07000000090000001e00000020000000
- m_Vertices: 0a0000000c000000
- m_Vertices: 0b0000000d0000002a0000002c000000
- m_Vertices: 0b0000000d0000002200000024000000
- m_Vertices: 0e00000010000000
- m_Vertices: 0f000000110000002e00000030000000
- m_Vertices: 0f000000110000002600000028000000
- m_Vertices: 1200000014000000
- m_Vertices: 13000000150000003200000034000000
- m_Vertices: 1600000018000000
- m_Vertices: 17000000190000003600000038000000
- m_Vertices: 1a0000001c000000
- m_Vertices: 1b0000001d0000003a0000003c000000
- m_Vertices: 210000003f000000400000005e000000
- m_Vertices: 23000000250000004200000044000000
- m_Vertices: 27000000290000004600000048000000
- m_Vertices: 2b0000002d0000004a0000004c000000
- m_Vertices: 2f000000310000004e00000050000000
- m_Vertices: 33000000350000005200000054000000
- m_Vertices: 37000000390000005600000058000000
- m_Vertices: 3b0000003d0000005a0000005c000000
- m_Vertices: 410000005f000000
- m_Vertices: 13000000150000002a0000002c000000
- m_Vertices: 16000000
- m_Vertices: 170000002e000000
- m_Vertices: 300000004e000000
- m_Vertices: 190000003200000034000000
- m_Vertices: 1b0000001d0000003600000038000000
- m_Vertices: 1f000000210000003a0000003c000000
- m_Vertices: 23000000250000003e00000040000000
- m_Vertices: 27000000290000004200000044000000
- m_Vertices: 2b0000002d0000004600000048000000
- m_Vertices: 2f0000004a0000004c000000
- m_Vertices: 310000004f000000
- m_Vertices: 3300000035000000
- m_Vertices: 3700000039000000
- m_Vertices: 3b0000003d000000
- m_Vertices: 3f00000041000000
- m_Vertices: 4300000045000000
- m_Vertices: 4700000049000000
- m_Vertices: 4b0000004d000000
- m_Vertices: 4f00000051000000
- m_Vertices: 5300000055000000
- m_Vertices: 5700000059000000
- m_Vertices: 5b0000005d000000
m_SharedTextures: []
m_Positions:
- {x: 1, y: -1, z: 0}
- {x: 1, y: -0.3333333, z: 0}
- {x: 0.70710677, y: -1, z: 0.70710677}
- {x: 0.70710677, y: -0.3333333, z: 0.70710677}
- {x: 0.70710677, y: -1, z: 0.70710677}
- {x: 0.70710677, y: -0.3333333, z: 0.70710677}
- {x: -0.00000004371139, y: -1, z: 1}
@@ -5383,14 +5559,6 @@ MonoBehaviour:
- {x: 0.000000011924881, y: -0.3333333, z: -1}
- {x: 0.70710665, y: -1, z: -0.7071069}
- {x: 0.70710665, y: -0.3333333, z: -0.7071069}
- {x: 0.70710665, y: -1, z: -0.7071069}
- {x: 0.70710665, y: -0.3333333, z: -0.7071069}
- {x: 1, y: -1, z: 0}
- {x: 1, y: -0.3333333, z: 0}
- {x: 1, y: -0.3333333, z: 0}
- {x: 1, y: 0.33333337, z: 0}
- {x: 0.70710677, y: -0.3333333, z: 0.70710677}
- {x: 0.70710677, y: 0.33333337, z: 0.70710677}
- {x: 0.70710677, y: -0.3333333, z: 0.70710677}
- {x: 0.70710677, y: 0.33333337, z: 0.70710677}
- {x: -0.00000004371139, y: -0.3333333, z: 1}
@@ -5415,10 +5583,6 @@ MonoBehaviour:
- {x: 0.000000011924881, y: 0.33333337, z: -1}
- {x: 0.70710665, y: -0.3333333, z: -0.7071069}
- {x: 0.70710665, y: 0.33333337, z: -0.7071069}
- {x: 0.70710665, y: -0.3333333, z: -0.7071069}
- {x: 0.70710665, y: 0.33333337, z: -0.7071069}
- {x: 1, y: -0.3333333, z: 0}
- {x: 1, y: 0.33333337, z: 0}
- {x: 1, y: 0.33333337, z: 0}
- {x: 1, y: 1, z: 0}
- {x: 0.70710677, y: 0.33333337, z: 0.70710677}
@@ -5452,10 +5616,6 @@ MonoBehaviour:
- {x: 1, y: 0.33333337, z: 0}
- {x: 1, y: 1, z: 0}
m_Textures0:
- {x: 0.38268346, y: -1}
- {x: 0.38268346, y: -0.3333333}
- {x: -0.3826834, y: -1}
- {x: -0.3826834, y: -0.3333333}
- {x: 0.38268343, y: -1}
- {x: 0.38268343, y: -0.3333333}
- {x: -0.3826835, y: -1}
@@ -5480,14 +5640,6 @@ MonoBehaviour:
- {x: 0.3826834, y: -0.3333333}
- {x: -0.3826833, y: -1}
- {x: -0.3826833, y: -0.3333333}
- {x: 0.38268352, y: -1}
- {x: 0.38268352, y: -0.3333333}
- {x: -0.38268352, y: -1}
- {x: -0.38268352, y: -0.3333333}
- {x: 0.38268346, y: -0.3333333}
- {x: 0.38268346, y: 0.33333337}
- {x: -0.3826834, y: -0.3333333}
- {x: -0.3826834, y: 0.33333337}
- {x: 0.38268343, y: -0.3333333}
- {x: 0.38268343, y: 0.33333337}
- {x: -0.3826835, y: -0.3333333}
@@ -5512,10 +5664,6 @@ MonoBehaviour:
- {x: 0.3826834, y: 0.33333337}
- {x: -0.3826833, y: -0.3333333}
- {x: -0.3826833, y: 0.33333337}
- {x: 0.38268352, y: -0.3333333}
- {x: 0.38268352, y: 0.33333337}
- {x: -0.38268352, y: -0.3333333}
- {x: -0.38268352, y: 0.33333337}
- {x: 0.38268346, y: 0.33333337}
- {x: 0.38268346, y: 1}
- {x: -0.3826834, y: 0.33333337}
@@ -5551,10 +5699,6 @@ MonoBehaviour:
m_Textures2: []
m_Textures3: []
m_Tangents:
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
@@ -5579,14 +5723,6 @@ MonoBehaviour:
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.38268346, y: 0, z: -0.92387956, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
- {x: 0.9238795, y: 0, z: -0.38268346, w: -1}
@@ -5611,10 +5747,6 @@ MonoBehaviour:
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.92387956, y: 0, z: -0.38268337, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: -0.38268352, y: 0, z: -0.9238795, w: -1}
- {x: 0.38268346, y: 0, z: -0.9238795, w: -1}
- {x: 0.38268346, y: 0, z: -0.9238795, w: -1}
- {x: 0.38268346, y: 0, z: -0.9238795, w: -1}
@@ -5656,7 +5788,7 @@ MonoBehaviour:
m_PreserveMeshAssetOnDestroy: 0
assetGuid:
m_Mesh: {fileID: 0}
m_VersionIndex: 836
m_VersionIndex: 839
m_IsSelectable: 1
m_SelectedFaces:
m_SelectedEdges: []
@@ -5767,3 +5899,160 @@ MeshCollider:
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 0}
--- !u!1001 &92549780786379211
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 5731161095573585393}
m_Modifications:
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.x
value: 5
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_SizeDelta.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalPosition.z
value: 0.34
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.x
value: 1.46
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_AnchoredPosition.y
value: 5.7
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4914436633015142662, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: m_Name
value: FloatingLabel
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _fadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _nearFadeRange
value: 0.4
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxScaleFactor
value: 1.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _minScaleFactor
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionAngle
value: 20
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _referenceDistance
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _maxVisibleDistance
value: 2
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionMaxOffset
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableAdaptiveScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _attractionSmoothness
value: 10
objectReference: {fileID: 0}
- target: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
propertyPath: _enableCameraAttraction
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 33aceb76d5023f1449962aa926352661, type: 3}
--- !u!224 &3985649632040779150 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 3893100950868132933, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 92549780786379211}
m_PrefabAsset: {fileID: 0}
--- !u!114 &5872837924559567801 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5820989873902797426, guid: 33aceb76d5023f1449962aa926352661, type: 3}
m_PrefabInstance: {fileID: 92549780786379211}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f7a1b2f9cb1305a4993ea145d8106942, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Dialogue.UI.FloatingLabel
@@ -201,7 +201,7 @@ MonoBehaviour:
_fadeRange: 1
_minDistance: 0.2
_nearFadeRange: 0.8
_enableAdaptiveScale: 1
_enableAdaptiveScale: 0
_referenceDistance: 2.5
_minScaleFactor: 0.5
_maxScaleFactor: 3
@@ -213,6 +213,12 @@ MonoBehaviour:
_ghostAlpha: 0.3
_ghostDelay: 0.15
_ghostDepthOffset: 0.02
_enableCameraAttraction: 0
_attractionAngle: 10
_attractionMaxOffset: 0.3
_attractionSmoothness: 4
_enableOneShot: 0
_seenAlphaThreshold: 0.5
_fadeInDuration: 0.5
_cullCheckInterval: 0.4
--- !u!114 &4494761007484843882
File diff suppressed because one or more lines are too long
@@ -13,8 +13,12 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Hallucination.HallucinationEvent
_label: 'RoomB Entry Vision '
_spawnGhostWord: 1
_ghostWordText: 'Ils savent '
_ghostWordSpawnOffset: {x: 0, y: 1.5, z: 2}
_ghostWordLifetime: 3
_sanityCost: 0.2
_labelOverrides:
- Target: {fileID: 0}
ShakeRadius: 0
ShakeSpeed: 0
ShakeSmoothness: 0
GhostEnabled: 0
GhostAlpha: 0
Duration: 0
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 24f457d56f9b515468d79eb53d678dc5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,36 @@
%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: 0}
m_Name: StaircaseSequenceData
m_EditorClassIdentifier: Assembly-CSharp:Unheimlich.World.Environment:StaircaseSequenceData
Slots:
- SlotIndex: 0
Word: 'What ? '
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 1
Word: It's to long
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 2
Word: 'Where am i ? '
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 3
Word: 'Am i lost ? '
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 4
Word: 'Wtf ? '
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 5
Word: Pull me out !
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
- SlotIndex: 6
Word: 'The end ? '
HallucinationEvent: {fileID: 11400000, guid: 1b7413ee4aaff444c802580243ca8c8a, type: 2}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a2a0c4a28fd71cc41bd284570d58a7b9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
%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: b4c627a455825134087ba8c6f8931aed, type: 3}
m_Name: StairsHallucinationWords
m_EditorClassIdentifier: Assembly-CSharp::Unheimlich.Features.Hallucination.HallucinationEvent
_label: Stairs hallu !
_sanityCost: 0.1
_labelOverrides: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1b7413ee4aaff444c802580243ca8c8a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,167 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-8730880457597845575
MonoBehaviour:
m_ObjectHideFlags: 3
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: 0b2db86121404754db890f4c8dfe81b2, type: 3}
m_Name: Bloom
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Bloom
active: 1
skipIterations:
m_OverrideState: 0
m_Value: 1
threshold:
m_OverrideState: 1
m_Value: 1
intensity:
m_OverrideState: 1
m_Value: 6.07
scatter:
m_OverrideState: 1
m_Value: 1
clamp:
m_OverrideState: 1
m_Value: 65472
tint:
m_OverrideState: 1
m_Value: {r: 0.27672952, g: 0.27672952, b: 0.27672952, a: 1}
highQualityFiltering:
m_OverrideState: 1
m_Value: 0
filter:
m_OverrideState: 1
m_Value: 1
downscale:
m_OverrideState: 0
m_Value: 0
maxIterations:
m_OverrideState: 0
m_Value: 6
dirtTexture:
m_OverrideState: 0
m_Value: {fileID: 0}
dimension: 1
dirtIntensity:
m_OverrideState: 0
m_Value: 0
--- !u!114 &-8301503217428336494
MonoBehaviour:
m_ObjectHideFlags: 3
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: 29fa0085f50d5e54f8144f766051a691, type: 3}
m_Name: FilmGrain
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.FilmGrain
active: 1
type:
m_OverrideState: 1
m_Value: 9
intensity:
m_OverrideState: 1
m_Value: 1
response:
m_OverrideState: 1
m_Value: 0.8
texture:
m_OverrideState: 0
m_Value: {fileID: 0}
--- !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: d7fd9488000d3734a9e00ee676215985, type: 3}
m_Name: Hallucinations Volume Profile
m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile
components:
- {fileID: 5048160815353275902}
- {fileID: 2293496333911105441}
- {fileID: 7109066975785212743}
- {fileID: -8301503217428336494}
- {fileID: -8730880457597845575}
--- !u!114 &2293496333911105441
MonoBehaviour:
m_ObjectHideFlags: 3
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: c5e1dc532bcb41949b58bc4f2abfbb7e, type: 3}
m_Name: LensDistortion
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.LensDistortion
active: 1
intensity:
m_OverrideState: 1
m_Value: -0.66
xMultiplier:
m_OverrideState: 0
m_Value: 1
yMultiplier:
m_OverrideState: 0
m_Value: 1
center:
m_OverrideState: 0
m_Value: {x: 0.5, y: 0.5}
scale:
m_OverrideState: 0
m_Value: 1
--- !u!114 &5048160815353275902
MonoBehaviour:
m_ObjectHideFlags: 3
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: 81180773991d8724ab7f2d216912b564, type: 3}
m_Name: ChromaticAberration
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ChromaticAberration
active: 1
intensity:
m_OverrideState: 1
m_Value: 1
--- !u!114 &7109066975785212743
MonoBehaviour:
m_ObjectHideFlags: 3
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: 899c54efeace73346a0a16faa3afe726, type: 3}
m_Name: Vignette
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Vignette
active: 1
color:
m_OverrideState: 1
m_Value: {r: 0, g: 0, b: 0, a: 1}
center:
m_OverrideState: 0
m_Value: {x: 0.5, y: 0.5}
intensity:
m_OverrideState: 1
m_Value: 0.14
smoothness:
m_OverrideState: 1
m_Value: 0.385
rounded:
m_OverrideState: 0
m_Value: 0
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: da4f12fdf6a4ac541962ed2bc5dfbad2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because one or more lines are too long
@@ -1,98 +1,77 @@
using UnityEngine;
using TMPro;
using System.Collections;
using System.Collections.Generic;
using Unheimlich.Features.Hallucination;
namespace Unheimlich.Features.Dialogue.UI
{
/// <summary>
/// Non-interactive floating word/phrase for world-space storytelling (thoughts, guidance, atmosphere).
/// Uses TextMeshPro 3D (not Canvas). Designed to sit alongside BillboardUI on the same prefab.
/// Non-interactive floating word/phrase for world-space storytelling.
///
/// Features:
/// - Adaptive scale: label always appears the same angular size in the player's camera.
/// - Max distance: fades out progressively when player is far away.
/// - Min distance: label is pushed away from the camera so it never clips into the player's face.
/// - Optional organic shake: label drifts gently around its home position.
/// - Optional ghost trail: a semi-transparent copy follows with a position delay.
/// - Optional camera attraction: label is gently pulled toward screen center when the player looks near it.
/// - Optional one-shot: label permanently disappears after being seen and moving away.
/// Changes from previous version:
/// - Registers/unregisters itself with HallucinationLabelRegistry on enable/disable
/// so the HallucinationManager can drive baseline behaviour without FindObjectsOfType.
/// - Exposes SetShakeParams() and SetGhostTrail() for runtime overrides.
/// - ApplyBaseline() / ApplyOverride() drive the two-layer system.
/// </summary>
public class FloatingLabel : MonoBehaviour
{
// ─── Inspector ─────────────────────────────────────────────────────────
[Header("Text")]
[Tooltip("Leave empty to keep text set directly on the TextMeshPro component.")]
[SerializeField] [TextArea] private string _overrideText;
[SerializeField] private TextMeshPro _textComponent;
[Header("Visibility")]
[Tooltip("Player distance beyond which the label becomes invisible.")]
[SerializeField] private float _maxVisibleDistance = 10f;
[Tooltip("Distance range over which the label fades in/out near the max visibility boundary.")]
[SerializeField] private float _fadeRange = 1.5f;
[Header("Min Distance")]
[Tooltip("When the camera is closer than this, the label slides away to stay readable.")]
[SerializeField] private float _minDistance = 0.5f;
[Tooltip("Distance range over which the label fades out as the player approaches min distance.")]
[SerializeField] private float _nearFadeRange = 0.8f;
[Header("Adaptive Scale")]
[Tooltip("Scale adjusts so the label always appears the same size in the camera view.")]
[SerializeField] private bool _enableAdaptiveScale = true;
[Tooltip("Distance at which the label renders at its Inspector-set scale (1:1 reference).")]
[SerializeField] private float _referenceDistance = 3f;
[Tooltip("Minimum scale multiplier (relative to base scale). Prevents the label from shrinking too much up close.")]
[SerializeField] private float _minScaleFactor = 0.2f;
[Tooltip("Maximum scale multiplier (relative to base scale). Prevents the label from growing too large at a distance.")]
[SerializeField] private float _maxScaleFactor = 3f;
[Header("Organic Shake (Optional)")]
[SerializeField] private bool _enableOrganicShake = false;
[Tooltip("Max drift radius in world units around the home position.")]
[SerializeField] private float _shakeRadius = 0.05f;
[Tooltip("How often a new shake target is picked (per second).")]
[SerializeField] private float _shakeSpeed = 1.5f;
[Tooltip("Higher = smoother drift transition.")]
[SerializeField] private float _shakeSmoothness = 2f;
[Header("Organic Shake — Baseline")]
[Tooltip("Prefab defaults. HallucinationManager lerps these at runtime based on sanity.")]
[SerializeField] private bool _enableOrganicShake = false;
[SerializeField] private float _shakeRadius = 0.05f;
[SerializeField] private float _shakeSpeed = 1.5f;
[SerializeField] private float _shakeSmoothness = 2f;
[Header("Ghost Trail (Optional)")]
[SerializeField] private bool _enableGhostTrail = false;
[Tooltip("Opacity of the ghost copy.")]
[Header("Ghost Trail — Baseline")]
[Tooltip("Prefab defaults. HallucinationManager lerps these at runtime based on sanity.")]
[SerializeField] private bool _enableGhostTrail = false;
[SerializeField] [Range(0f, 1f)] private float _ghostAlpha = 0.3f;
[Tooltip("How many seconds the ghost lags behind the main label.")]
[SerializeField] private float _ghostDelay = 0.15f;
[Tooltip("How far behind the main label the ghost is pushed (along the camera-to-label ray). Ensures the ghost is always occluded by the main word regardless of viewing angle.")]
[SerializeField] private float _ghostDepthOffset = 0.02f;
[SerializeField] private float _ghostDelay = 0.15f;
[SerializeField] private float _ghostDepthOffset = 0.02f;
[Header("Camera Attraction (Optional)")]
[Tooltip("When enabled, the label is gently pulled toward the screen center when the player looks near it.")]
[SerializeField] private bool _enableCameraAttraction = false;
[Tooltip("Half-angle (degrees) within which attraction is active. " +
"Below this angle the label is drawn toward the screen center. " +
"Keep small (e.g. 8-15°) so it only triggers when the player is really looking at the word.")]
[SerializeField] private bool _enableCameraAttraction = false;
[SerializeField] [Range(1f, 45f)] private float _attractionAngle = 10f;
[Tooltip("Maximum world-space offset applied toward the screen center at full attraction strength.")]
[SerializeField] private float _attractionMaxOffset = 0.3f;
[Tooltip("How quickly the attraction offset interpolates toward its target (higher = snappier).")]
[SerializeField] private float _attractionMaxOffset = 0.3f;
[SerializeField] private float _attractionSmoothness = 4f;
[Header("One-Shot (Optional)")]
[Tooltip("When enabled, the label permanently disappears once the player has seen it and then moved away.")]
[SerializeField] private bool _enableOneShot = false;
[Tooltip("Alpha threshold above which the label is considered 'seen'. " +
"The player must look at the label long enough to exceed this visibility before the one-shot condition can trigger.")]
[SerializeField] private bool _enableOneShot = false;
[SerializeField] [Range(0.01f, 1f)] private float _seenAlphaThreshold = 0.5f;
[Header("Reappear Fade")]
[Tooltip("Duration of the fade-in when the label reappears after being culled.")]
[SerializeField] private float _fadeInDuration = 0.5f;
[Header("Performance")]
[Tooltip("How often (in seconds) distance culling is evaluated. Higher = cheaper but slightly delayed visibility toggle.")]
[SerializeField] private float _cullCheckInterval = 0.4f;
// ── State ──────────────────────────────────────────────────────────────
// ─── Runtime state ─────────────────────────────────────────────────────
private Camera _camera;
private Vector3 _localHomePosition;
private Vector3 _homePosition;
private Vector3 _baseScale;
@@ -101,75 +80,94 @@ namespace Unheimlich.Features.Dialogue.UI
private float _cullTimer;
private float _fadeInAlpha = 1f;
// Shake
// Shake — live values driven by baseline or override
private bool _isShaking;
private Vector3 _shakeOffset;
private Vector3 _shakeTarget;
private float _shakeTimer;
private float _liveShakeRadius;
private float _liveShakeSpeed;
private float _liveShakeSmoothness;
// Ghost trail
private TextMeshPro _ghostText;
private Queue<Vector3> _positionHistory = new Queue<Vector3>();
// Ghost trail — live values
private bool _liveGhostEnabled;
private float _liveGhostAlpha;
private TextMeshPro _ghostText;
private Queue<Vector3> _positionHistory = new();
private float _historyTimer;
private const float HISTORY_SAMPLE_RATE = 0.016f;
// Camera attraction
// World-space offset currently applied on top of the home+shake position.
private Vector3 _attractionOffset;
// One-shot
// True once the label has been visible above the threshold at least once.
private bool _hasBeenSeen;
// True once the one-shot has fired and the label should stay invisible forever.
private bool _permanentlyHidden;
// ── Unity ──────────────────────────────────────────────────────────────
// Override coroutine
private Coroutine _overrideCoroutine;
// Baseline snapshot (so revert after override is accurate)
private float _baselineShakeRadius;
private float _baselineShakeSpeed;
private float _baselineShakeSmoothness;
private bool _baselineGhostEnabled;
private float _baselineGhostAlpha;
// ─── Unity ─────────────────────────────────────────────────────────────
private void Awake()
{
_camera = Camera.main;
if (_textComponent == null)
_textComponent = GetComponent<TextMeshPro>();
// Initialise live values from inspector defaults
_liveShakeRadius = _shakeRadius;
_liveShakeSpeed = _shakeSpeed;
_liveShakeSmoothness = _shakeSmoothness;
_liveGhostEnabled = _enableGhostTrail;
_liveGhostAlpha = _ghostAlpha;
}
private void Start()
{
_homePosition = transform.position;
_localHomePosition = transform.localPosition;
_baseScale = transform.localScale;
if (_textComponent != null && !string.IsNullOrEmpty(_overrideText))
_textComponent.text = _overrideText;
SaveBaselineSnapshot();
SetupGhostTrail();
if (_enableOrganicShake)
StartShake();
StartShakeInternal();
}
private void OnEnable() => HallucinationLabelRegistry.Register(this);
private void OnDisable() => HallucinationLabelRegistry.Unregister(this);
private void Update()
{
if (_permanentlyHidden) return;
if (_camera == null)
{
_camera = Camera.main;
return;
}
if (_camera == null) { _camera = Camera.main; return; }
// Low-frequency distance cull: skip all logic and disable renderers when out of range.
// ── Distance cull ──────────────────────────────────────────────────
_cullTimer += Time.deltaTime;
if (_cullTimer >= _cullCheckInterval)
{
_cullTimer = 0f;
bool shouldBeActive = Vector3.Distance(_camera.transform.position, _homePosition)
<= _maxVisibleDistance + _fadeRange;
bool shouldBeActive = Vector3.Distance(_camera.transform.position, transform.position)
<= _maxVisibleDistance + _fadeRange;
if (shouldBeActive != _isActive)
{
_isActive = shouldBeActive;
_textComponent.enabled = _isActive;
if (_ghostText != null) _ghostText.enabled = _isActive;
// Reset fade-in so the label doesn't pop in abruptly.
if (_ghostText != null) _ghostText.enabled = _isActive && _liveGhostEnabled;
if (_isActive) _fadeInAlpha = 0f;
}
}
@@ -178,19 +176,16 @@ namespace Unheimlich.Features.Dialogue.UI
UpdatePosition();
// Compute the distance-based alpha first so one-shot and attraction can read it.
float dist = Vector3.Distance(_camera.transform.position, _homePosition);
float dist = Vector3.Distance(_camera.transform.position, transform.position);
float alpha = ComputeAlpha(dist) * _fadeInAlpha;
// One-shot: track visibility and trigger permanent hide when the player walks away after seeing the label.
// ── One-shot ───────────────────────────────────────────────────────
if (_enableOneShot)
{
if (!_hasBeenSeen && alpha >= _seenAlphaThreshold)
_hasBeenSeen = true;
if (!_hasBeenSeen && alpha >= _seenAlphaThreshold) _hasBeenSeen = true;
if (_hasBeenSeen && alpha <= 0f)
{
_permanentlyHidden = true;
_permanentlyHidden = true;
_textComponent.enabled = false;
if (_ghostText != null) _ghostText.enabled = false;
return;
@@ -200,55 +195,149 @@ namespace Unheimlich.Features.Dialogue.UI
UpdateCameraAttraction(alpha);
ApplyAlpha(alpha);
UpdateAdaptiveScale();
if (_isShaking)
UpdateShake();
if (_isShaking) UpdateShake();
UpdateGhostTrail();
}
// ── Position ───────────────────────────────────────────────────────────
// ─── Public API — two-layer system ─────────────────────────────────────
/// <summary>
/// Pushes sanity-driven baseline values. Ignored while an override is active.
/// Called every frame by HallucinationManager for labels within range.
/// </summary>
public void ApplyBaseline(float shakeRadius, float shakeSpeed, float shakeSmoothness,
bool ghostEnabled, float ghostAlpha)
{
if (_overrideCoroutine != null) return;
SetShakeParams(shakeRadius, shakeSpeed, shakeSmoothness);
SetGhostTrail(ghostEnabled, ghostAlpha);
// Keep snapshot fresh so revert after override is correct
_baselineShakeRadius = shakeRadius;
_baselineShakeSpeed = shakeSpeed;
_baselineShakeSmoothness = shakeSmoothness;
_baselineGhostEnabled = ghostEnabled;
_baselineGhostAlpha = ghostAlpha;
}
/// <summary>
/// Applies a timed override then reverts to the last baseline snapshot.
/// Called by HallucinationEvent at trigger time.
/// </summary>
public void ApplyOverride(float shakeRadius, float shakeSpeed, float shakeSmoothness,
bool ghostEnabled, float ghostAlpha,
float duration)
{
if (_overrideCoroutine != null) StopCoroutine(_overrideCoroutine);
_overrideCoroutine = StartCoroutine(OverrideRoutine(
shakeRadius, shakeSpeed, shakeSmoothness,
ghostEnabled, ghostAlpha, duration));
}
private IEnumerator OverrideRoutine(float shakeRadius, float shakeSpeed, float shakeSmoothness,
bool ghostEnabled, float ghostAlpha, float duration)
{
SetShakeParams(shakeRadius, shakeSpeed, shakeSmoothness);
SetGhostTrail(ghostEnabled, ghostAlpha);
yield return new WaitForSeconds(duration);
SetShakeParams(_baselineShakeRadius, _baselineShakeSpeed, _baselineShakeSmoothness);
SetGhostTrail(_baselineGhostEnabled, _baselineGhostAlpha);
_overrideCoroutine = null;
}
// ─── Low-level setters (public for editor tooling / direct calls) ───────
public void SetShakeParams(float radius, float speed, float smoothness)
{
_liveShakeRadius = radius;
_liveShakeSpeed = speed;
_liveShakeSmoothness = smoothness;
if (radius > 0f && !_isShaking) StartShakeInternal();
else if (radius <= 0f) _isShaking = false;
}
public void SetGhostTrail(bool enabled, float alpha)
{
_liveGhostEnabled = enabled;
_liveGhostAlpha = alpha;
if (_ghostText != null) _ghostText.enabled = _isActive && enabled;
}
// ─── Existing API ──────────────────────────────────────────────────────
public void SetText(string text)
{
_overrideText = text;
if (_textComponent != null) _textComponent.text = text;
if (_ghostText != null) _ghostText.text = text;
}
public void SetHomePosition(Vector3 worldPos)
{
_homePosition = worldPos;
transform.position = worldPos;
}
public void ResetOneShot()
{
_hasBeenSeen = false;
_permanentlyHidden = false;
if (_textComponent != null) _textComponent.enabled = true;
if (_ghostText != null) _ghostText.enabled = true;
_fadeInAlpha = 0f;
}
// ─── Internals ─────────────────────────────────────────────────────────
private void SaveBaselineSnapshot()
{
_baselineShakeRadius = _shakeRadius;
_baselineShakeSpeed = _shakeSpeed;
_baselineShakeSmoothness = _shakeSmoothness;
_baselineGhostEnabled = _enableGhostTrail;
_baselineGhostAlpha = _ghostAlpha;
}
private void UpdatePosition()
{
if (transform.parent != null)
_homePosition = transform.parent.TransformPoint(_localHomePosition);
Vector3 toHome = _homePosition - _camera.transform.position;
float dist = toHome.magnitude;
Vector3 basePos;
if (dist < _minDistance && dist > 0.001f)
basePos = _camera.transform.position + toHome.normalized * _minDistance;
else
basePos = _homePosition + _shakeOffset;
Vector3 basePos = (dist < _minDistance && dist > 0.001f)
? _camera.transform.position + toHome.normalized * _minDistance
: _homePosition + _shakeOffset;
transform.position = basePos + _attractionOffset;
}
// ── Visibility (distance fade) ─────────────────────────────────────────
private void ApplyAlpha(float alpha)
{
if (_textComponent == null) return;
if (_fadeInAlpha < 1f)
_fadeInAlpha = Mathf.MoveTowards(_fadeInAlpha, 1f, Time.deltaTime / Mathf.Max(_fadeInDuration, 0.001f));
_fadeInAlpha = Mathf.MoveTowards(_fadeInAlpha, 1f,
Time.deltaTime / Mathf.Max(_fadeInDuration, 0.001f));
SetTextAlpha(_textComponent, alpha);
if (_ghostText != null)
SetTextAlpha(_ghostText, alpha * _ghostAlpha);
if (_ghostText != null && _liveGhostEnabled)
SetTextAlpha(_ghostText, alpha * _liveGhostAlpha);
}
private float ComputeAlpha(float dist)
{
// Far fade-out
if (dist >= _maxVisibleDistance)
return 0f;
if (dist >= _maxVisibleDistance) return 0f;
float farFadeStart = _maxVisibleDistance - _fadeRange;
if (dist > farFadeStart && _fadeRange > 0f)
return 1f - (dist - farFadeStart) / _fadeRange;
// Near fade-out
float nearFadeEnd = _minDistance + _nearFadeRange;
if (dist < nearFadeEnd && _nearFadeRange > 0f)
return Mathf.Clamp01((dist - _minDistance) / _nearFadeRange);
@@ -263,104 +352,62 @@ namespace Unheimlich.Features.Dialogue.UI
text.color = c;
}
// ── Adaptive Scale ─────────────────────────────────────────────────────
private void UpdateAdaptiveScale()
{
if (!_enableAdaptiveScale) return;
float dist = Vector3.Distance(_camera.transform.position, transform.position);
float scaleFactor = Mathf.Clamp(dist / Mathf.Max(_referenceDistance, 0.001f), _minScaleFactor, _maxScaleFactor);
float scaleFactor = Mathf.Clamp(dist / Mathf.Max(_referenceDistance, 0.001f),
_minScaleFactor, _maxScaleFactor);
transform.localScale = _baseScale * scaleFactor;
if (_ghostText != null)
_ghostText.transform.localScale = transform.localScale;
if (_ghostText != null) _ghostText.transform.localScale = transform.localScale;
}
// ── Camera Attraction ──────────────────────────────────────────────────
/// <summary>
/// Pulls the label toward the screen center when the player is looking near it.
/// Strength uses a quadratic falloff so it only kicks in meaningfully
/// when the gaze angle is truly small.
/// </summary>
private void UpdateCameraAttraction(float currentAlpha)
{
if (!_enableCameraAttraction)
{
_attractionOffset = Vector3.zero;
return;
}
if (!_enableCameraAttraction) { _attractionOffset = Vector3.zero; return; }
// Direction from camera to the label's home position.
Vector3 toLabel = _homePosition - _camera.transform.position;
float dist = toLabel.magnitude;
if (dist < 0.001f) { _attractionOffset = Vector3.zero; return; }
if (dist < 0.001f)
{
_attractionOffset = Vector3.zero;
return;
}
// Angle between the camera's forward direction and the direction to the label.
float angleDeg = Vector3.Angle(_camera.transform.forward, toLabel.normalized);
float t = Mathf.Clamp01(1f - angleDeg / Mathf.Max(_attractionAngle, 0.001f));
float strength = t * t * currentAlpha;
// Quadratic falloff: 1 at angleDeg==0, 0 at angleDeg==_attractionAngle and beyond.
float t = Mathf.Clamp01(1f - angleDeg / Mathf.Max(_attractionAngle, 0.001f));
float strength = t * t; // quadratic — only strong when really close to center
// Also scale with the distance-based alpha so attraction is zero when the label is faded out.
strength *= currentAlpha;
// Target offset: move the label to where Camera.forward ray at distance |toLabel| lands.
Vector3 labelOnCenterRay = _camera.transform.position + _camera.transform.forward * dist;
Vector3 targetOffset = (labelOnCenterRay - _homePosition) * strength;
// Clamp magnitude so it never overrides the home position completely.
if (targetOffset.magnitude > _attractionMaxOffset)
targetOffset = targetOffset.normalized * _attractionMaxOffset;
_attractionOffset = Vector3.Lerp(
_attractionOffset,
targetOffset,
Time.deltaTime * _attractionSmoothness
);
_attractionOffset = Vector3.Lerp(_attractionOffset, targetOffset,
Time.deltaTime * _attractionSmoothness);
}
// ── Organic Shake ──────────────────────────────────────────────────────
private Vector3 RandomShakeTarget()
{
float scaledRadius = _shakeRadius * transform.localScale.x;
Vector2 circle = Random.insideUnitCircle * scaledRadius;
return new Vector3(circle.x, circle.y, 0f);
}
private void StartShake()
private void StartShakeInternal()
{
_isShaking = true;
_shakeTimer = 0f;
_shakeTarget = RandomShakeTarget();
}
private void UpdateShake()
private Vector3 RandomShakeTarget()
{
_shakeTimer += Time.deltaTime * _shakeSpeed;
if (_shakeTimer >= 1f)
{
_shakeTimer = 0f;
_shakeTarget = RandomShakeTarget();
}
_shakeOffset = Vector3.Lerp(_shakeOffset, _shakeTarget, Time.deltaTime * _shakeSmoothness);
float scaledRadius = _liveShakeRadius * transform.localScale.x;
Vector2 circle = Random.insideUnitCircle * scaledRadius;
return new Vector3(circle.x, circle.y, 0f);
}
// ── Ghost Trail ────────────────────────────────────────────────────────
private void UpdateShake()
{
_shakeTimer += Time.deltaTime * _liveShakeSpeed;
if (_shakeTimer >= 1f) { _shakeTimer = 0f; _shakeTarget = RandomShakeTarget(); }
_shakeOffset = Vector3.Lerp(_shakeOffset, _shakeTarget, Time.deltaTime * _liveShakeSmoothness);
}
private void SetupGhostTrail()
{
if (!_enableGhostTrail || _textComponent == null) return;
// Ghost GO is always created when the feature might be enabled at runtime
if (_textComponent == null) return;
GameObject ghostObj = new GameObject($"Ghost_{gameObject.name}");
ghostObj.transform.SetParent(transform.parent, false);
@@ -369,17 +416,13 @@ namespace Unheimlich.Features.Dialogue.UI
ghostObj.transform.localScale = transform.localScale;
ghostObj.layer = gameObject.layer;
_ghostText = ghostObj.AddComponent<TextMeshPro>();
_ghostText.font = _textComponent.font;
_ghostText.fontSize = _textComponent.fontSize;
_ghostText.alignment = _textComponent.alignment;
_ghostText.text = _textComponent.text;
_ghostText.color = new Color(
_textComponent.color.r,
_textComponent.color.g,
_textComponent.color.b,
_ghostAlpha
);
_ghostText = ghostObj.AddComponent<TextMeshPro>();
_ghostText.font = _textComponent.font;
_ghostText.fontSize = _textComponent.fontSize;
_ghostText.alignment = _textComponent.alignment;
_ghostText.text = _textComponent.text;
_ghostText.color = new Color(_textComponent.color.r, _textComponent.color.g,
_textComponent.color.b, _liveGhostAlpha);
MeshRenderer mainRenderer = _textComponent.GetComponent<MeshRenderer>();
MeshRenderer ghostRenderer = _ghostText.GetComponent<MeshRenderer>();
@@ -390,59 +433,30 @@ namespace Unheimlich.Features.Dialogue.UI
}
ghostObj.AddComponent<BillboardUI>();
// Start hidden — the manager or an override will enable it when needed
_ghostText.enabled = _liveGhostEnabled;
}
private void UpdateGhostTrail()
{
if (!_enableGhostTrail || _ghostText == null) return;
if (!_liveGhostEnabled || _ghostText == null) return;
_historyTimer += Time.deltaTime;
if (_historyTimer >= HISTORY_SAMPLE_RATE)
{
_positionHistory.Enqueue(transform.position);
_historyTimer = 0f;
int maxSize = Mathf.CeilToInt(_ghostDelay / HISTORY_SAMPLE_RATE);
while (_positionHistory.Count > maxSize)
_positionHistory.Dequeue();
while (_positionHistory.Count > maxSize) _positionHistory.Dequeue();
}
Vector3 ghostPos = _positionHistory.Count > 0
? _positionHistory.Peek()
: transform.position;
Vector3 ghostPos = _positionHistory.Count > 0 ? _positionHistory.Peek() : transform.position;
_ghostText.transform.position = ghostPos + _camera.transform.forward * _ghostDepthOffset;
_ghostText.text = _textComponent.text;
_ghostText.fontSize = _textComponent.fontSize;
}
// ── Public API ─────────────────────────────────────────────────────────
/// <summary>Sets the displayed text at runtime.</summary>
public void SetText(string text)
{
_overrideText = text;
if (_textComponent != null) _textComponent.text = text;
if (_ghostText != null) _ghostText.text = text;
}
/// <summary>Teleports the label's home position without animation.</summary>
public void SetHomePosition(Vector3 worldPos)
{
_homePosition = worldPos;
transform.position = worldPos;
}
/// <summary>Resets the one-shot state so the label can be seen again.</summary>
public void ResetOneShot()
{
_hasBeenSeen = false;
_permanentlyHidden = false;
if (_textComponent != null) _textComponent.enabled = true;
if (_ghostText != null) _ghostText.enabled = true;
_fadeInAlpha = 0f;
}
#if UNITY_EDITOR
private void OnValidate()
{
@@ -1,42 +1,86 @@
using System.Collections.Generic;
using UnityEngine;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Hallucination
{
// ─── Per-label override data ───────────────────────────────────────────────
/// <summary>
/// Describes how a specific FloatingLabel should behave when a HallucinationEvent fires.
/// </summary>
[System.Serializable]
public class FloatingLabelOverride
{
[Tooltip("The FloatingLabel to override when this event fires.")]
public FloatingLabel Target;
[Header("Shake Override")]
[Tooltip("Absolute shake radius applied during the override (world units). 0 = no shake.")]
[Min(0f)] public float ShakeRadius = 0.15f;
[Tooltip("Shake speed during the override.")]
[Min(0f)] public float ShakeSpeed = 3f;
[Tooltip("Shake smoothness during the override.")]
[Min(0f)] public float ShakeSmoothness = 4f;
[Header("Ghost Trail Override")]
public bool GhostEnabled = true;
[Range(0f, 1f)] public float GhostAlpha = 0.5f;
[Header("Duration")]
[Tooltip("How long the override lasts (seconds) before reverting to the sanity baseline.")]
[Min(0f)] public float Duration = 2f;
}
// ─── ScriptableObject ──────────────────────────────────────────────────────
/// <summary>
/// ScriptableObject describing a discrete hallucination event.
/// Configure in the inspector and pass to HallucinationManager.TriggerHallucinationEvent().
///
/// Ghost word spawn removed. Words live on FloatingLabel components in the scene.
/// LabelOverrides targets specific labels with timed shake/ghost overrides.
/// </summary>
[CreateAssetMenu(fileName = "HallucinationEvent", menuName = "Unheimlich/Hallucination/Hallucination Event")]
[CreateAssetMenu(
fileName = "HallucinationEvent",
menuName = "Unheimlich/Hallucination/Hallucination Event")]
public class HallucinationEvent : ScriptableObject
{
[Header("Identity")]
[Tooltip("Human-readable label for this event (used in logs and the inspector)")]
[SerializeField] private string _label;
[Header("Ghost Word")]
[Tooltip("Spawn a ghost word that moves toward the player")]
[SerializeField] private bool _spawnGhostWord;
[Tooltip("Text displayed by the ghost word")]
[SerializeField] private string _ghostWordText;
[Tooltip("World-space spawn position offset from the anchor point")]
[SerializeField] private Vector3 _ghostWordSpawnOffset = new Vector3(0f, 1.5f, 2f);
[Tooltip("Duration before the ghost word disappears (seconds)")]
[SerializeField] private float _ghostWordLifetime = 3f;
[Header("Sanity Cost")]
[Tooltip("Sanity added to the player when this event fires (0 = no change)")]
[SerializeField, Range(0f, 1f)] private float _sanityCost = 0f;
// ─── Public Accessors ──────────────────────────────────────────────────────
[Header("Floating Label Overrides")]
[Tooltip("One entry per FloatingLabel to affect when this event fires.")]
[SerializeField] private List<FloatingLabelOverride> _labelOverrides = new();
public string Label => _label;
public bool SpawnGhostWord => _spawnGhostWord;
public string GhostWordText => _ghostWordText;
public Vector3 GhostWordSpawnOffset => _ghostWordSpawnOffset;
public float GhostWordLifetime => _ghostWordLifetime;
public float SanityCost => _sanityCost;
// ─── Public Accessors ──────────────────────────────────────────────────
public string Label => _label;
public float SanityCost => _sanityCost;
public IReadOnlyList<FloatingLabelOverride> LabelOverrides => _labelOverrides;
// ─── Internal ─────────────────────────────────────────────────────────
/// <summary>
/// Pushes all label overrides onto their target FloatingLabels.
/// Called by HallucinationManager.TriggerHallucinationEvent().
/// </summary>
internal void ApplyLabelOverrides()
{
foreach (FloatingLabelOverride entry in _labelOverrides)
{
if (entry.Target == null) continue;
entry.Target.ApplyOverride(
entry.ShakeRadius,
entry.ShakeSpeed,
entry.ShakeSmoothness,
entry.GhostEnabled,
entry.GhostAlpha,
entry.Duration);
}
}
}
}
}
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using UnityEngine;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Hallucination
{
/// <summary>
/// Static registry that FloatingLabel instances self-register into on OnEnable/OnDisable.
/// Lets HallucinationManager iterate active labels in a radius without any FindObjectsOfType.
/// </summary>
public static class HallucinationLabelRegistry
{
private static readonly HashSet<FloatingLabel> _labels = new();
public static void Register(FloatingLabel label) => _labels.Add(label);
public static void Unregister(FloatingLabel label) => _labels.Remove(label);
/// <summary>
/// Returns all registered labels whose transform is within <paramref name="radius"/>
/// of <paramref name="center"/>. Results are written into <paramref name="results"/>
/// (which is cleared first) to avoid allocations per call.
/// </summary>
public static void GetLabelsInRadius(Vector3 center, float radius, List<FloatingLabel> results)
{
results.Clear();
float sqrRadius = radius * radius;
foreach (FloatingLabel label in _labels)
{
if (label == null) continue;
if ((label.transform.position - center).sqrMagnitude <= sqrRadius)
results.Add(label);
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 63e30fb837ed3ab4182c89a053c11a6a
@@ -3,41 +3,27 @@ using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using System;
using System.Collections;
using System.Collections.Generic;
using Unheimlich.Core;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.Features.Hallucination
{
/// <summary>
/// Central manager for the hallucination system.
/// Tracks the player's sanity level (0 = sane, 1 = fully insane) and drives all
/// hallucination effects: individual URP post-process overrides (with lerp), word shake
/// intensity, and ghost-word visibility via the HallucinationWordSpawner.
///
/// Effects are applied directly on VolumeProfile overrides rather than on volume.weight,
/// so multiple volumes coexist without parameter conflicts.
/// </summary>
public class HallucinationManager : Singleton<HallucinationManager>
{
// ─── Constants ─────────────────────────────────────────────────────────────
private const float MinSanity = 0f;
private const float MaxSanity = 1f;
// ─── Inspector ─────────────────────────────────────────────────────────────
[Header("Sanity")]
[Tooltip("Starting sanity level (0 = sane, 1 = fully insane)")]
[SerializeField, Range(0f, 1f)] private float _initialSanity = 0f;
[Tooltip("Sanity naturally recovers over time at this rate per second (0 = no recovery)")]
[SerializeField, Range(0f, 0.1f)] private float _sanityRecoveryRate = 0f;
[Header("Effect Lerp")]
[Tooltip("Speed at which visual effects lerp toward the target sanity value")]
[SerializeField] private float _effectLerpSpeed = 2f;
[Header("URP Post-Process Volume")]
[Tooltip("Volume containing the hallucination overrides (Chromatic Aberration, Lens Distortion, etc.)")]
[SerializeField] private Volume _hallucinationVolume;
[Header("Chromatic Aberration")]
@@ -62,151 +48,175 @@ namespace Unheimlich.Features.Hallucination
[Header("Bloom")]
[SerializeField] private bool _driveBloom = true;
[Tooltip("Bloom intensity at sanity = 0")]
[SerializeField, Min(0f)] private float _bloomIntensityMin = 0f;
[Tooltip("Bloom intensity at sanity = 1")]
[SerializeField, Min(0f)] private float _bloomIntensityMax = 1f;
[Tooltip("Bloom threshold at sanity = 0 — raise this to suppress any bleed at zero sanity")]
[SerializeField, Min(0f)] private float _bloomThresholdMin = 1f;
[Tooltip("Bloom threshold at sanity = 1")]
[SerializeField, Min(0f)] private float _bloomThresholdMax = 0.5f;
[Tooltip("Bloom scatter (spread) at sanity = 0")]
[SerializeField, Min(0f)] private float _bloomIntensityMin = 0f;
[SerializeField, Min(0f)] private float _bloomIntensityMax = 1f;
[SerializeField, Min(0f)] private float _bloomThresholdMin = 1f;
[SerializeField, Min(0f)] private float _bloomThresholdMax = 0.5f;
[SerializeField, Range(0f, 1f)] private float _bloomScatterMin = 0f;
[Tooltip("Bloom scatter (spread) at sanity = 1")]
[SerializeField, Range(0f, 1f)] private float _bloomScatterMax = 0.7f;
[Tooltip("Bloom dirt texture intensity at sanity = 0")]
[SerializeField, Min(0f)] private float _bloomDirtIntensityMin = 0f;
[Tooltip("Bloom dirt texture intensity at sanity = 1")]
[SerializeField, Min(0f)] private float _bloomDirtIntensityMax = 0f;
[Header("Word Shake")]
[Tooltip("Baseline shake multiplier at sanity = 0")]
[SerializeField] private float _shakeMultiplierAtZero = 1f;
[Header("Floating Label — Baseline Influence")]
[Tooltip("Labels within this radius of the player receive the sanity-driven baseline.")]
[SerializeField, Min(0f)] private float _labelInfluenceRadius = 12f;
[Tooltip("Max shake multiplier at sanity = 1")]
[SerializeField] private float _shakeMultiplierAtOne = 3f;
[Header("Floating Label — Shake")]
[Tooltip("Shake radius applied to labels at sanity = 0.")]
[SerializeField, Min(0f)] private float _labelShakeRadiusAtZero = 0f;
[SerializeField, Min(0f)] private float _labelShakeSpeedAtZero = 1.5f;
[SerializeField, Min(0f)] private float _labelShakeSmoothnessAtZero = 2f;
[Tooltip("Shake radius applied to labels at sanity = 1.")]
[SerializeField, Min(0f)] private float _labelShakeRadiusAtOne = 0.2f;
[SerializeField, Min(0f)] private float _labelShakeSpeedAtOne = 4f;
[SerializeField, Min(0f)] private float _labelShakeSmoothnessAtOne = 5f;
[Header("Floating Label — Ghost Trail")]
[SerializeField] private bool _ghostEnabledAtZero = false;
[SerializeField] private bool _ghostEnabledAtOne = true;
[SerializeField, Range(0f, 1f)] private float _ghostAlphaMin = 0.1f;
[SerializeField, Range(0f, 1f)] private float _ghostAlphaMax = 0.5f;
[Header("Word Shake (legacy — for other systems)")]
[SerializeField] private float _shakeMultiplierLegacyAtZero = 1f;
[SerializeField] private float _shakeMultiplierLegacyAtOne = 3f;
[Header("Debug")]
[SerializeField] private bool _debugMode;
// ─── State ─────────────────────────────────────────────────────────────────
// ─── State ─────────────────────────────────────────────────────────────
private float _currentSanity;
private float _displayedSanity; // lerped value used for visual effects
private float _currentSanity;
private float _displayedSanity;
private Coroutine _lerpCoroutine;
private bool _vignetteExternallyOverridden;
// External systems can suppress the hallucination vignette (e.g. diapason listening mode).
private bool _vignetteExternallyOverridden;
// Cached volume overrides
private ChromaticAberration _chromaticAberration;
private LensDistortion _lensDistortion;
private Vignette _vignette;
private FilmGrain _filmGrain;
private Bloom _bloom;
private LensDistortion _lensDistortion;
private Vignette _vignette;
private FilmGrain _filmGrain;
private Bloom _bloom;
// ─── Public API ────────────────────────────────────────────────────────────
private Transform _playerTransform;
private readonly List<FloatingLabel> _labelsInRange = new();
// ─── Public API ────────────────────────────────────────────────────────
/// <summary>Current logical sanity level in [0, 1]. 0 = sane, 1 = fully insane.</summary>
public float SanityLevel => _currentSanity;
/// <summary>
/// Word shake multiplier computed from the lerped display sanity (smooth).
/// </summary>
public float WordShakeMultiplier =>
Mathf.Lerp(_shakeMultiplierAtZero, _shakeMultiplierAtOne, _displayedSanity);
Mathf.Lerp(_shakeMultiplierLegacyAtZero, _shakeMultiplierLegacyAtOne, _displayedSanity);
/// <summary>Raised whenever the logical sanity level changes. Payload is the new value in [0, 1].</summary>
public event Action<float> OnSanityChanged;
/// <summary>Raised when a discrete hallucination event is triggered (e.g. ghost word appears).</summary>
public event Action<float> OnSanityChanged;
public event Action<HallucinationEvent> OnHallucinationTriggered;
// ─── Lifecycle ─────────────────────────────────────────────────────────────
// ─── Lifecycle ─────────────────────────────────────────────────────────
protected override void OnAwake()
{
_currentSanity = Mathf.Clamp(_initialSanity, MinSanity, MaxSanity);
_currentSanity = Mathf.Clamp(_initialSanity, MinSanity, MaxSanity);
_displayedSanity = _currentSanity;
CacheVolumeOverrides();
ApplyEffectsImmediate(_currentSanity);
ApplyPostProcessImmediate(_currentSanity);
}
private void Update()
{
if (_sanityRecoveryRate > 0f && _currentSanity > MinSanity)
SetSanity(_currentSanity - _sanityRecoveryRate * Time.deltaTime);
DriveFloatingLabelBaseline();
}
// ─── Public Methods ────────────────────────────────────────────────────────
// ─── Public Methods ────────────────────────────────────────────────────
/// <summary>
/// Increases the sanity level by <paramref name="amount"/> (clamped to [0, 1]).
/// Effects lerp smoothly to the new value.
/// </summary>
public void AddInsanity(float amount)
{
SetSanity(_currentSanity + amount);
}
public void AddInsanity(float amount) => SetSanity(_currentSanity + amount);
/// <summary>
/// Directly sets the logical sanity level. Effects lerp smoothly to the new value.
/// </summary>
public void SetSanity(float value)
{
float clamped = Mathf.Clamp(value, MinSanity, MaxSanity);
if (Mathf.Approximately(clamped, _currentSanity))
return;
if (Mathf.Approximately(clamped, _currentSanity)) return;
_currentSanity = clamped;
OnSanityChanged?.Invoke(_currentSanity);
if (_debugMode)
Debug.Log($"[HallucinationManager] Sanity → {_currentSanity:F2}", this);
if (_debugMode) Debug.Log($"[HallucinationManager] Sanity → {_currentSanity:F2}", this);
RestartLerp();
}
/// <summary>
/// Suppresses the hallucination vignette so an external system (e.g. diapason) can
/// take full control of vignette without additive blending artefacts.
/// Call with <c>false</c> when the external system is done.
/// </summary>
public void SetVignetteOverriddenExternally(bool overridden)
{
_vignetteExternallyOverridden = overridden;
// Apply immediately so the vignette drops to zero without waiting for the lerp coroutine
if (_vignette != null)
_vignette.intensity.value = overridden ? 0f : Mathf.Lerp(_vignetteMin, _vignetteMax, _displayedSanity);
_vignette.intensity.value = overridden
? 0f
: Mathf.Lerp(_vignetteMin, _vignetteMax, _displayedSanity);
}
/// <summary>Fires a discrete hallucination event (ghost word, vision flash, etc.).</summary>
/// <summary>
/// Fires a discrete hallucination event:
/// 1. Applies SanityCost.
/// 2. Dispatches per-label overrides defined in the event asset.
/// 3. Raises OnHallucinationTriggered.
/// </summary>
public void TriggerHallucinationEvent(HallucinationEvent hallucinationEvent)
{
if (hallucinationEvent == null)
{
Debug.LogError("[HallucinationManager] Attempted to trigger a null HallucinationEvent!", this);
Debug.LogError("[HallucinationManager] Null HallucinationEvent!", this);
return;
}
if (hallucinationEvent.SanityCost > 0f)
AddInsanity(hallucinationEvent.SanityCost);
hallucinationEvent.ApplyLabelOverrides();
if (_debugMode)
Debug.Log($"[HallucinationManager] Event: {hallucinationEvent.name}", this);
Debug.Log($"[HallucinationManager] Event: {hallucinationEvent.Label} " +
$"({hallucinationEvent.LabelOverrides.Count} label overrides)", this);
OnHallucinationTriggered?.Invoke(hallucinationEvent);
}
// ─── Lerp ──────────────────────────────────────────────────────────────────
// ─── Floating Label Baseline ───────────────────────────────────────────
private void DriveFloatingLabelBaseline()
{
EnsurePlayerTransform();
if (_playerTransform == null) return;
HallucinationLabelRegistry.GetLabelsInRadius(
_playerTransform.position, _labelInfluenceRadius, _labelsInRange);
float t = _displayedSanity;
float shakeRadius = Mathf.Lerp(_labelShakeRadiusAtZero, _labelShakeRadiusAtOne, t);
float shakeSpeed = Mathf.Lerp(_labelShakeSpeedAtZero, _labelShakeSpeedAtOne, t);
float shakeSmoothness = Mathf.Lerp(_labelShakeSmoothnessAtZero, _labelShakeSmoothnessAtOne, t);
bool ghostEnabled = t >= 0.5f ? _ghostEnabledAtOne : _ghostEnabledAtZero;
float ghostAlpha = Mathf.Lerp(_ghostAlphaMin, _ghostAlphaMax, t);
foreach (FloatingLabel label in _labelsInRange)
{
label.ApplyBaseline(shakeRadius, shakeSpeed, shakeSmoothness, ghostEnabled, ghostAlpha);
}
}
private void EnsurePlayerTransform()
{
if (_playerTransform != null) return;
if (Unheimlich.Features.Player.PlayerController.Instance != null)
_playerTransform = Unheimlich.Features.Player.PlayerController.Instance.transform;
else if (Camera.main != null)
_playerTransform = Camera.main.transform;
}
// ─── Lerp ──────────────────────────────────────────────────────────────
private void RestartLerp()
{
if (_lerpCoroutine != null)
StopCoroutine(_lerpCoroutine);
if (_lerpCoroutine != null) StopCoroutine(_lerpCoroutine);
_lerpCoroutine = StartCoroutine(LerpEffects());
}
@@ -214,22 +224,21 @@ namespace Unheimlich.Features.Hallucination
{
while (!Mathf.Approximately(_displayedSanity, _currentSanity))
{
_displayedSanity = Mathf.MoveTowards(_displayedSanity, _currentSanity, _effectLerpSpeed * Time.deltaTime);
ApplyEffectsImmediate(_displayedSanity);
_displayedSanity = Mathf.MoveTowards(
_displayedSanity, _currentSanity, _effectLerpSpeed * Time.deltaTime);
ApplyPostProcessImmediate(_displayedSanity);
yield return null;
}
_displayedSanity = _currentSanity;
ApplyEffectsImmediate(_displayedSanity);
ApplyPostProcessImmediate(_displayedSanity);
_lerpCoroutine = null;
}
// ─── Effects ───────────────────────────────────────────────────────────────
// ─── Post-Process Effects ──────────────────────────────────────────────
private void CacheVolumeOverrides()
{
if (_hallucinationVolume == null || _hallucinationVolume.profile == null)
return;
if (_hallucinationVolume == null || _hallucinationVolume.profile == null) return;
_hallucinationVolume.profile.TryGet(out _chromaticAberration);
_hallucinationVolume.profile.TryGet(out _lensDistortion);
@@ -237,20 +246,19 @@ namespace Unheimlich.Features.Hallucination
_hallucinationVolume.profile.TryGet(out _filmGrain);
_hallucinationVolume.profile.TryGet(out _bloom);
// Keep volume weight at 1 permanently — we write individual override values directly.
// The hallucination volume must be on its OWN dedicated VolumeProfile, separate from
// the dialogue blur volume, to avoid weight conflicts between the two systems.
_hallucinationVolume.weight = 1f;
_hallucinationVolume.weight = 1f;
_hallucinationVolume.enabled = true;
}
private void ApplyEffectsImmediate(float t)
private void ApplyPostProcessImmediate(float t)
{
if (_driveChromaticAberration && _chromaticAberration != null)
_chromaticAberration.intensity.value = Mathf.Lerp(_chromaticAberrationMin, _chromaticAberrationMax, t);
_chromaticAberration.intensity.value =
Mathf.Lerp(_chromaticAberrationMin, _chromaticAberrationMax, t);
if (_driveLensDistortion && _lensDistortion != null)
_lensDistortion.intensity.value = Mathf.Lerp(_lensDistortionMin, _lensDistortionMax, t);
_lensDistortion.intensity.value =
Mathf.Lerp(_lensDistortionMin, _lensDistortionMax, t);
if (_driveVignette && _vignette != null && !_vignetteExternallyOverridden)
_vignette.intensity.value = Mathf.Lerp(_vignetteMin, _vignetteMax, t);
@@ -260,13 +268,11 @@ namespace Unheimlich.Features.Hallucination
if (_driveBloom && _bloom != null)
{
// Drive all bloom parameters that can independently cause it to appear.
// intensity alone is not enough — threshold=0 or scatter>0 can bleed through.
_bloom.intensity.value = Mathf.Lerp(_bloomIntensityMin, _bloomIntensityMax, t);
_bloom.threshold.value = Mathf.Lerp(_bloomThresholdMin, _bloomThresholdMax, t);
_bloom.scatter.value = Mathf.Lerp(_bloomScatterMin, _bloomScatterMax, t);
_bloom.intensity.value = Mathf.Lerp(_bloomIntensityMin, _bloomIntensityMax, t);
_bloom.threshold.value = Mathf.Lerp(_bloomThresholdMin, _bloomThresholdMax, t);
_bloom.scatter.value = Mathf.Lerp(_bloomScatterMin, _bloomScatterMax, t);
_bloom.dirtIntensity.value = Mathf.Lerp(_bloomDirtIntensityMin, _bloomDirtIntensityMax, t);
}
}
}
}
}
@@ -5,24 +5,21 @@ namespace Unheimlich.Features.Hallucination
{
/// <summary>
/// Self-contained zone that triggers a hallucination effect when the player enters.
/// Handles the once-flag, optional delay, insanity increase, and a discrete HallucinationEvent
/// — no GameEventTrigger or HallucinationTrigger required alongside it.
/// Ghost-word spawn removed — words live on FloatingLabel components in the scene.
/// SetEvent() lets InfiniteStaircaseController inject the right event per slot at runtime.
/// </summary>
public class HallucinationTriggerZone : TriggerZoneBase
{
[Header("Zone Behaviour")]
[Tooltip("Allow the zone to fire again after the player exits and re-enters")]
[SerializeField] private bool _retriggerable = false;
[Tooltip("Delay in seconds before the hallucination fires after the player enters")]
[SerializeField] private float _delay = 0f;
[SerializeField] private bool _retriggerable = false;
[SerializeField] private float _delay = 0f;
[Header("Sanity")]
[Tooltip("Amount of insanity added when the zone fires (0 = no change)")]
[Tooltip("Insanity added when the zone fires, on top of any SanityCost on the event.")]
[SerializeField, Range(0f, 1f)] private float _insanityAmount = 0f;
[Header("Hallucination Event")]
[Tooltip("Optional discrete hallucination event (ghost word, vision flash, etc.)")]
[Tooltip("Overridable at runtime via SetEvent().")]
[SerializeField] private HallucinationEvent _hallucinationEvent;
[Header("Debug")]
@@ -32,39 +29,38 @@ namespace Unheimlich.Features.Hallucination
protected override void OnPlayerEntered(Collider playerCollider)
{
if (_delay > 0f)
Invoke(nameof(Fire), _delay);
else
Fire();
if (_delay > 0f) Invoke(nameof(Fire), _delay);
else Fire();
}
/// <summary>
/// Fires the hallucination effect. Can also be called from external scripts or UnityEvents.
/// </summary>
/// <summary>Overrides the event at runtime. Pass null to disable.</summary>
public void SetEvent(HallucinationEvent hallucinationEvent) =>
_hallucinationEvent = hallucinationEvent;
/// <summary>Fires the hallucination. Can be called from external scripts or UnityEvents.</summary>
public void Fire()
{
if (HallucinationManager.Instance == null)
{
Debug.LogError("[HallucinationTriggerZone] HallucinationManager not found in scene!", this);
Debug.LogError("[HallucinationTriggerZone] HallucinationManager not found!", this);
return;
}
if (_insanityAmount > 0f)
{
HallucinationManager.Instance.AddInsanity(_insanityAmount);
if (_debugMode)
Debug.Log($"[HallucinationTriggerZone] Added {_insanityAmount:F2} insanity on '{gameObject.name}'.", this);
if (_debugMode) Debug.Log($"[HallucinationTriggerZone] +{_insanityAmount:F2} insanity.", this);
}
if (_hallucinationEvent != null)
{
HallucinationManager.Instance.TriggerHallucinationEvent(_hallucinationEvent);
if (_debugMode)
Debug.Log($"[HallucinationTriggerZone] Fired event: {_hallucinationEvent.Label}", this);
if (_debugMode) Debug.Log($"[HallucinationTriggerZone] Event: {_hallucinationEvent.Label}", this);
}
else if (_debugMode)
{
Debug.Log($"[HallucinationTriggerZone] No event on '{gameObject.name}'.", this);
}
}
}
}
}
@@ -1,248 +1,26 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Unheimlich.Features.Dialogue.Data;
using Unheimlich.Features.Dialogue.UI;
using Unheimlich.Features.Player;
using Unheimlich.Core.Utils;
using RotationAxis = Unheimlich.Features.Dialogue.Data.RotationAxis;
using ChoiceSpawnMode = Unheimlich.Features.Dialogue.Data.ChoiceSpawnMode;
namespace Unheimlich.Features.Hallucination
{
/// <summary>
/// Listens to HallucinationManager.OnHallucinationTriggered and spawns ghost words
/// that float in world space and drift toward the player.
/// Reuses the existing ChoiceFocusHandler prefab and its organic shake system.
/// Add this component to the HallucinationManager GameObject or any persistent scene object.
/// DEPRECATED — Ghost word spawning has been removed from the hallucination system.
///
/// Words are now FloatingLabel components placed directly in the scene (on stair prefabs
/// or world props). Their behaviour (shake, ghost trail) is driven at runtime by
/// HallucinationManager (baseline, sanity-lerped) and HallucinationEvent (timed overrides).
///
/// This script is kept as an empty stub so existing scene references don't break.
/// It can safely be removed from any GameObject it was attached to.
/// </summary>
[DisallowMultipleComponent]
public class HallucinationWordSpawner : MonoBehaviour
{
private const float CanvasLocalScale = 0.01f;
[Header("References")]
[Tooltip("Prefab used to render each ghost word (ChoiceFocusHandler)")]
[SerializeField] private ChoiceFocusHandler _wordPrefab;
[Header("Ghost Word Behaviour")]
[Tooltip("Speed at which the ghost word drifts toward the player")]
[SerializeField] private float _driftSpeed = 0.4f;
[Tooltip("Distance from the player at which the ghost word stops drifting")]
[SerializeField] private float _stopDistance = 1.5f;
[Tooltip("Fade-in duration when a ghost word appears")]
[SerializeField] private float _fadeInDuration = 0.5f;
[Tooltip("Fade-out duration before the ghost word is destroyed")]
[SerializeField] private float _fadeOutDuration = 0.8f;
[Header("Shake Settings")]
[Tooltip("Shake radius applied to ghost words (world units)")]
[SerializeField] private float _shakeRadius = 15f;
[Tooltip("Shake speed")]
[SerializeField] private float _shakeSpeed = 2f;
[Tooltip("Shake smoothness")]
[SerializeField] private float _shakeSmoothness = 5f;
private readonly List<GhostWordInstance> _activeWords = new List<GhostWordInstance>();
// ─── Lifecycle ─────────────────────────────────────────────────────────────
private void OnEnable()
private void Awake()
{
if (HallucinationManager.Instance != null)
HallucinationManager.Instance.OnHallucinationTriggered += OnHallucinationTriggered;
}
private void OnDisable()
{
if (HallucinationManager.Instance != null)
HallucinationManager.Instance.OnHallucinationTriggered -= OnHallucinationTriggered;
}
private void Update()
{
for (int i = _activeWords.Count - 1; i >= 0; i--)
{
GhostWordInstance instance = _activeWords[i];
if (instance.Handler == null)
{
_activeWords.RemoveAt(i);
continue;
}
DriftTowardPlayer(instance);
}
}
// ─── Event Handler ─────────────────────────────────────────────────────────
private void OnHallucinationTriggered(HallucinationEvent hallucinationEvent)
{
if (!hallucinationEvent.SpawnGhostWord || _wordPrefab == null)
return;
SpawnGhostWord(hallucinationEvent);
}
// ─── Spawn ─────────────────────────────────────────────────────────────────
private void SpawnGhostWord(HallucinationEvent hallucinationEvent)
{
if (PlayerController.Instance == null)
{
Debug.LogWarning("[HallucinationWordSpawner] PlayerController not found, cannot spawn ghost word.", this);
return;
}
// World-space canvas container — mirrors the pattern in FloatingWordsSpawner
GameObject container = new GameObject($"GhostWord_{hallucinationEvent.Label}");
Canvas canvas = container.AddComponent<Canvas>();
canvas.renderMode = RenderMode.WorldSpace;
container.transform.localScale = Vector3.one * CanvasLocalScale;
// Position relative to player + event offset
Vector3 spawnPosition = PlayerController.Instance.transform.position
+ PlayerController.Instance.transform.TransformDirection(hallucinationEvent.GhostWordSpawnOffset);
container.transform.position = spawnPosition;
container.transform.LookAt(PlayerController.Instance.transform.position);
// Spawn the word handler
ChoiceFocusHandler handler = Instantiate(_wordPrefab, container.transform);
handler.transform.localPosition = Vector3.zero;
handler.transform.localRotation = Quaternion.identity;
handler.transform.localScale = Vector3.one;
// Build a ghost-only DialogueChoiceData (no NextNode, no localization key)
DialogueChoiceData ghostData = new DialogueChoiceData
{
ChoiceTextOverride = hallucinationEvent.GhostWordText,
NextNode = null
};
FloatingWordsSpawner.SpawnConfig config = BuildGhostConfig();
handler.Setup(ghostData, config, disableFloatingEffects: false);
handler.StartOrganicShake();
// Fade-in via CanvasGroup
CanvasGroup canvasGroup = handler.GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = handler.gameObject.AddComponent<CanvasGroup>();
canvasGroup.alpha = 0f;
TweenHelper.FadeCanvasGroup(canvasGroup, 1f, _fadeInDuration, null, LeanTweenType.easeOutQuad);
GhostWordInstance instance = new GhostWordInstance
{
Handler = handler,
Container = container,
CanvasGroup = canvasGroup,
Lifetime = hallucinationEvent.GhostWordLifetime,
ElapsedTime = 0f,
IsFadingOut = false
};
_activeWords.Add(instance);
StartCoroutine(LifetimeRoutine(instance));
}
// ─── Drift ─────────────────────────────────────────────────────────────────
private void DriftTowardPlayer(GhostWordInstance instance)
{
if (PlayerController.Instance == null || instance.IsFadingOut)
return;
Transform container = instance.Container.transform;
Vector3 playerPos = PlayerController.Instance.transform.position;
float distance = Vector3.Distance(container.position, playerPos);
if (distance > _stopDistance)
{
Vector3 direction = (playerPos - container.position).normalized;
container.position += direction * _driftSpeed * Time.deltaTime;
}
// Always face the player
container.LookAt(playerPos);
}
// ─── Lifetime ──────────────────────────────────────────────────────────────
private IEnumerator LifetimeRoutine(GhostWordInstance instance)
{
float aliveTime = Mathf.Max(0f, instance.Lifetime - _fadeOutDuration);
yield return new WaitForSeconds(aliveTime);
if (instance.Handler == null)
yield break;
instance.IsFadingOut = true;
instance.Handler.StopOrganicShake();
if (instance.CanvasGroup != null)
TweenHelper.FadeCanvasGroup(instance.CanvasGroup, 0f, _fadeOutDuration, null, LeanTweenType.easeInQuad);
yield return new WaitForSeconds(_fadeOutDuration);
_activeWords.Remove(instance);
if (instance.Container != null)
Destroy(instance.Container);
}
// ─── Config ────────────────────────────────────────────────────────────────
private FloatingWordsSpawner.SpawnConfig BuildGhostConfig()
{
float sanityMultiplier = HallucinationManager.Instance != null
? HallucinationManager.Instance.WordShakeMultiplier
: 1f;
return new FloatingWordsSpawner.SpawnConfig
{
SpawnRadius = 0f,
SpawnHeightOffset = 0f,
RotationAxis = RotationAxis.Up,
EnableOrganicShake = true,
ForwardOffset = 0f,
TiltAngle = 0f,
RotationSpeed = 0f,
EnableRotation = false,
SpawnMode = ChoiceSpawnMode.AtAnchorPosition,
EnableFloating = false,
MergeDuration = 0.3f,
MergeScalePulse = 1f,
EnableGhostTrail = true,
GhostTrailAlpha = 0.25f,
GhostTrailDelay = 0.08f,
ShakeRadius = _shakeRadius * sanityMultiplier,
ShakeSpeed = _shakeSpeed,
ShakeSmoothness = _shakeSmoothness,
MoveTowardPlayerOnFocus = false,
FocusDistanceFromPlayer = _stopDistance,
DisableFloatingEffects = false,
DefaultScaleMultiplier = 1f,
EnableScaleVariation = false,
MinScaleVariation = 1f,
MaxScaleVariation = 1f
};
}
// ─── Internal ──────────────────────────────────────────────────────────────
private class GhostWordInstance
{
public ChoiceFocusHandler Handler;
public GameObject Container;
public CanvasGroup CanvasGroup;
public float Lifetime;
public float ElapsedTime;
public bool IsFadingOut;
Debug.LogWarning(
"[HallucinationWordSpawner] This component is deprecated and does nothing. " +
"Remove it from the scene and use FloatingLabel + HallucinationEvent overrides instead.",
this);
}
}
}
}
@@ -1,54 +1,118 @@
using System.Collections.Generic;
using UnityEngine;
using Unheimlich.Features.Player;
using Unheimlich.Features.Hallucination;
namespace Unheimlich.World.Environment
{
// ─── Data ─────────────────────────────────────────────────────────────────────
/// <summary>
/// Configuration for a single stair slot.
/// Slot indices are relative: 0 = ground level, positive = up, negative = down.
/// </summary>
[System.Serializable]
public class StaircaseSlotData
{
[Tooltip("Slot index this data applies to. 0 = ground, positive = up, negative = down.")]
public int SlotIndex;
[Tooltip("Word displayed on the FloatingLabel of this segment.")]
public string Word;
[Tooltip("Optional hallucination event fired when the player enters this segment's zone.")]
public HallucinationEvent HallucinationEvent;
}
/// <summary>
/// ScriptableObject holding the full word/event sequence for one staircase.
/// Create via Assets > Create > Unheimlich > Hallucination > Staircase Sequence Data.
/// </summary>
[CreateAssetMenu(
fileName = "StaircaseSequenceData",
menuName = "Unheimlich/Hallucination/Staircase Sequence Data")]
public class StaircaseSequenceData : ScriptableObject
{
[Tooltip("Per-slot configuration. Slots not listed here get no word and no event.")]
public List<StaircaseSlotData> Slots = new();
}
// ─── Controller ───────────────────────────────────────────────────────────────
public class InfiniteStaircaseController : MonoBehaviour
{
// ─── Prefabs ─────────────────────────────────────────────────────────
[Header("Stair Prefabs")]
[Tooltip("Segment standard utilisé pour remplir la tour.")]
[Tooltip("Standard segment used to fill the tower.")]
[SerializeField] private GameObject _stairPrefab;
[Tooltip("Segment toujours placé tout en HAUT de la tour (slot +maxIterationsUp).")]
[Tooltip("Segment always placed at the very TOP of the tower (slot +maxIterationsUp).")]
[SerializeField] private GameObject _stairTopPrefab;
[Tooltip("Segment toujours placé tout en BAS de la tour (slot -maxIterationsDown).")]
[Tooltip("Segment always placed at the very BOTTOM of the tower (slot -maxIterationsDown).")]
[SerializeField] private GameObject _stairBottomPrefab;
[Tooltip("Si true, le premier enfant avec renderers est réutilisé comme slot 0.")]
[Tooltip("If true, the first child with renderers is reused as slot 0 instead of being instantiated from the prefab.")]
[SerializeField] private bool _useExistingChildAsBase = true;
// ─── Iterations ──────────────────────────────────────────────────────
[Header("Iterations")]
[Tooltip("Nombre de segments au-dessus du sol (montée).")]
[Tooltip("Number of segments above ground level (upward traversal).")]
[SerializeField] private int _maxIterationsUp = 4;
[Tooltip("Nombre de segments en-dessous du sol (descente).")]
[Tooltip("Number of segments below ground level (downward traversal).")]
[SerializeField] private int _maxIterationsDown = 4;
// ─── Segment Bounds ──────────────────────────────────────────────────
[Header("Segment Bounds — Auto-Detection")]
[Tooltip("Renderer of the central column mesh. When assigned, segment height is read from its world bounds.")]
[SerializeField] private Renderer _centralColumnRenderer;
[Tooltip("Fallback segment height (m) used when no central column renderer is assigned.")]
[SerializeField] private float _segmentHeight = 4.82f;
[Tooltip("Y offset added to the segment height for fine-tuning snapping.")]
[SerializeField] private float _segmentHeightOffset = 0f;
// ─── Scroll Control ───────────────────────────────────────────────────
[Header("Scroll Speed Control")]
[Tooltip("Proportional gain: scroll speed (m/s) per metre of player deviation from the trigger center.")]
[SerializeField] private float _correctionGain = 4f;
[Tooltip("Maximum tower scroll speed in m/s.")]
[SerializeField] private float _maxScrollSpeed = 8f;
[Tooltip("SmoothDamp time for scroll speed transitions — prevents sudden jolts.")]
[SerializeField] private float _scrollSmoothTime = 0.1f;
// ─── Rotation Offset ─────────────────────────────────────────────────
[Header("Rotation Offset")]
[Tooltip("Y rotation applied to every spawned segment around its geometric bounds center.")]
[SerializeField] private float _segmentRotationOffsetY = 0f;
// ─── Hallucination / Word Data ────────────────────────────────────────
[Header("Hallucination — Word & Event Data")]
[Tooltip("ScriptableObject holding word + event data per slot. " +
"Recommended: create a StaircaseSequenceData asset and assign it here.")]
[SerializeField] private StaircaseSequenceData _sequenceData;
[Space]
[Tooltip("When true, the word for each slot is picked randomly from _randomWordPool instead of from _sequenceData.")]
[SerializeField] private bool _useRandomWords = false;
[Tooltip("Pool of words to pick from when _useRandomWords is enabled.")]
[SerializeField] private List<string> _randomWordPool = new();
[Tooltip("HallucinationEvent applied to all slots when _useRandomWords is enabled " +
"(slot-specific events from _sequenceData are ignored in random mode).")]
[SerializeField] private HallucinationEvent _randomModeEvent;
// ─── Debug ───────────────────────────────────────────────────────────
[Header("Debug")]
@@ -60,10 +124,23 @@ namespace Unheimlich.World.Environment
private StairState _currentState = StairState.Idle;
private Transform _playerTransform;
/// <summary>Single parent moved to scroll the entire tower at once.</summary>
private Transform _towerRoot;
/// <summary>World Y of the trigger collider center, cached on Awake.</summary>
private float _triggerCenterWorldY;
/// <summary>True when the player entered the trigger from below (travelling upward).</summary>
private bool _enteredFromBelow;
/// <summary>
/// towerRoot.localPosition.y threshold signalling stock exhaustion.
/// Negative when going up, positive when going down.
/// </summary>
private float _limitLocalY;
/// <summary>Current scroll speed (signed). Positive means the tower moves downward.</summary>
private float _scrollSpeed;
private float _scrollSpeedVelocity;
@@ -71,9 +148,7 @@ namespace Unheimlich.World.Environment
// ─── Properties ──────────────────────────────────────────────────────
private float EffectiveSegmentHeight => _segmentHeight + _segmentHeightOffset;
/// <summary>Déplacement max dépend de la direction.</summary>
private float EffectiveSegmentHeight => _segmentHeight + _segmentHeightOffset;
private float MaxTowerDisplacementUp => _maxIterationsUp * EffectiveSegmentHeight;
private float MaxTowerDisplacementDown => _maxIterationsDown * EffectiveSegmentHeight;
@@ -105,6 +180,9 @@ namespace Unheimlich.World.Environment
// ─── Trigger Events ───────────────────────────────────────────────────
/// <summary>
/// Called by StaircaseTriggerZone when the player enters the collider.
/// </summary>
public void OnPlayerEnteredTrigger()
{
if (_currentState != StairState.Idle && _currentState != StairState.Done) return;
@@ -120,7 +198,41 @@ namespace Unheimlich.World.Environment
_currentState = StairState.Active;
}
public void OnPlayerExitedTrigger() { }
/// <summary>
/// Called by StaircaseTriggerZone when the player exits the collider.
/// </summary>
public void OnPlayerExitedTrigger()
{
if (_currentState != StairState.Active && _currentState != StairState.Stopping) return;
bool towerHardlyMoved = _towerRoot != null &&
Mathf.Abs(_towerRoot.localPosition.y) < EffectiveSegmentHeight * 0.5f;
if (towerHardlyMoved)
{
_segmentsBySlot.TryGetValue(0, out GameObject baseSegment);
if (baseSegment != null)
{
baseSegment.transform.SetParent(transform, true);
baseSegment.transform.position = transform.position;
}
DestroyTower();
if (baseSegment != null)
_segmentsBySlot[0] = baseSegment;
_scrollSpeed = 0f;
_scrollSpeedVelocity = 0f;
_playerTransform = null;
_currentState = StairState.Idle;
}
else
{
_currentState = StairState.Stopping;
}
}
// ─── Tower Construction ───────────────────────────────────────────────
@@ -136,7 +248,6 @@ namespace Unheimlich.World.Environment
if (_enteredFromBelow)
{
// Slot 0 → +maxIterationsUp
for (int i = 0; i <= _maxIterationsUp; i++)
SpawnSegmentAtSlot(i);
@@ -144,7 +255,6 @@ namespace Unheimlich.World.Environment
}
else
{
// Slot 0 → -maxIterationsDown
for (int i = 0; i >= -_maxIterationsDown; i--)
SpawnSegmentAtSlot(i);
@@ -162,21 +272,14 @@ namespace Unheimlich.World.Environment
_segmentsBySlot.Clear();
}
/// <summary>
/// Choisit le bon prefab selon le slot :
/// - slot == +maxIterationsUp → _stairTopPrefab
/// - slot == -maxIterationsDown → _stairBottomPrefab
/// - tout le reste → _stairPrefab
/// Le slot 0 peut aussi réutiliser l'enfant existant si l'option est activée.
/// </summary>
private void SpawnSegmentAtSlot(int slotIndex)
{
if (_segmentsBySlot.ContainsKey(slotIndex)) return;
float localY = slotIndex * EffectiveSegmentHeight;
float localY = slotIndex * EffectiveSegmentHeight;
GameObject segment;
// ── Slot 0 : réutilisation de l'enfant existant ──────────────────
// Slot 0 — attempt to reuse the existing scene child.
if (slotIndex == 0 && _useExistingChildAsBase)
{
Transform existing = FindExistingStairChild();
@@ -187,12 +290,12 @@ namespace Unheimlich.World.Environment
segment.transform.localPosition = new Vector3(0f, localY, 0f);
segment.transform.localRotation = Quaternion.identity;
ApplyRotationOffsetFromCenter(segment);
ConfigureSegment(segment, slotIndex);
_segmentsBySlot[slotIndex] = segment;
return;
}
}
// ── Choix du prefab ───────────────────────────────────────────────
GameObject prefabToUse = PickPrefabForSlot(slotIndex);
if (prefabToUse == null) return;
@@ -200,26 +303,66 @@ namespace Unheimlich.World.Environment
segment.transform.localPosition = new Vector3(0f, localY, 0f);
segment.transform.localRotation = Quaternion.identity;
ApplyRotationOffsetFromCenter(segment);
ConfigureSegment(segment, slotIndex);
_segmentsBySlot[slotIndex] = segment;
}
/// <summary>
/// Renvoie le prefab approprié pour un slot donné.
/// Top = slot +maxIterationsUp (sommet absolu de la tour montante)
/// Bottom = slot -maxIterationsDown (fond absolu de la tour descendante)
/// Sinon = prefab standard.
/// </summary>
private GameObject PickPrefabForSlot(int slotIndex)
{
if (slotIndex == _maxIterationsUp && _stairTopPrefab != null)
return _stairTopPrefab;
if (slotIndex == -_maxIterationsDown && _stairBottomPrefab != null)
return _stairBottomPrefab;
if (slotIndex == _maxIterationsUp && _stairTopPrefab != null) return _stairTopPrefab;
if (slotIndex == -_maxIterationsDown && _stairBottomPrefab != null) return _stairBottomPrefab;
return _stairPrefab;
}
// ─── Segment Configuration ────────────────────────────────────────────
/// <summary>
/// Resolves the word and event for this slot then calls StaircaseSegment.Configure().
/// If the segment has no StaircaseSegment component, this is a silent no-op.
/// </summary>
private void ConfigureSegment(GameObject segmentGO, int slotIndex)
{
StaircaseSegment segment = segmentGO.GetComponent<StaircaseSegment>();
if (segment == null) return;
string word = ResolveWord(slotIndex);
HallucinationEvent evt = ResolveEvent(slotIndex);
segment.Configure(word, evt);
}
private string ResolveWord(int slotIndex)
{
if (_useRandomWords)
{
if (_randomWordPool == null || _randomWordPool.Count == 0)
return null;
return _randomWordPool[Random.Range(0, _randomWordPool.Count)];
}
return FindSlotData(slotIndex)?.Word;
}
private HallucinationEvent ResolveEvent(int slotIndex)
{
if (_useRandomWords)
return _randomModeEvent;
return FindSlotData(slotIndex)?.HallucinationEvent;
}
/// <summary>Returns the StaircaseSlotData matching slotIndex, or null if not found.</summary>
private StaircaseSlotData FindSlotData(int slotIndex)
{
if (_sequenceData == null) return null;
foreach (StaircaseSlotData data in _sequenceData.Slots)
{
if (data.SlotIndex == slotIndex)
return data;
}
return null;
}
// ─── Scroll ───────────────────────────────────────────────────────────
private void UpdateScrollSpeed()
@@ -282,7 +425,6 @@ namespace Unheimlich.World.Environment
_currentState = StairState.Done;
if (_towerRoot == null) return;
// Le segment qui doit rester visible après la fin = l'extrémité atteinte
int keepSlot = _enteredFromBelow ? _maxIterationsUp : -_maxIterationsDown;
_segmentsBySlot.TryGetValue(keepSlot, out GameObject keepSegment);
@@ -367,27 +509,23 @@ namespace Unheimlich.World.Environment
{
if (!_drawGizmos) return;
float h = EffectiveSegmentHeight;
float h = EffectiveSegmentHeight;
Vector3 o = transform.position;
// Tour montante — vert
Gizmos.color = new Color(0f, 1f, 0.5f, 0.35f);
for (int i = 1; i <= _maxIterationsUp; i++)
Gizmos.DrawWireCube(new Vector3(o.x, o.y + i * h + h * 0.5f, o.z), new Vector3(1.8f, h * 0.95f, 1.8f));
// Tour descendante — orange
Gizmos.color = new Color(1f, 0.6f, 0f, 0.25f);
for (int i = 1; i <= _maxIterationsDown; i++)
Gizmos.DrawWireCube(new Vector3(o.x, o.y - i * h + h * 0.5f, o.z), new Vector3(1.8f, h * 0.95f, 1.8f));
// Ligne du centre du trigger — cyan
Gizmos.color = Color.cyan;
Gizmos.DrawLine(
new Vector3(o.x - 2f, _triggerCenterWorldY, o.z),
new Vector3(o.x + 2f, _triggerCenterWorldY, o.z)
);
// Slot top — magenta
if (_stairTopPrefab != null)
{
Gizmos.color = Color.magenta;
@@ -397,7 +535,6 @@ namespace Unheimlich.World.Environment
);
}
// Slot bottom — rouge
if (_stairBottomPrefab != null)
{
Gizmos.color = Color.red;
@@ -0,0 +1,53 @@
using UnityEngine;
using Unheimlich.Features.Hallucination;
using Unheimlich.Features.Dialogue.UI;
namespace Unheimlich.World.Environment
{
/// <summary>
/// Sits on each stair-segment prefab and acts as the single configuration point
/// for the InfiniteStaircaseController.
///
/// Responsibilities:
/// - Holds a reference to the segment's FloatingLabel (set in prefab).
/// - Holds a reference to the segment's HallucinationTriggerZone (set in prefab).
/// - Exposes Configure() so the controller can push the right word and event
/// at spawn time without any GetComponent chains on the controller side.
/// </summary>
public class StaircaseSegment : MonoBehaviour
{
[Header("References")]
[Tooltip("FloatingLabel present on this prefab. Assign in the prefab inspector.")]
[SerializeField] private FloatingLabel _floatingLabel;
[Tooltip("HallucinationTriggerZone present on this prefab. Assign in the prefab inspector.")]
[SerializeField] private HallucinationTriggerZone _triggerZone;
// ─── Public API ────────────────────────────────────────────────────────
/// <summary>
/// Called by InfiniteStaircaseController right after this segment is spawned.
/// Sets the word on the FloatingLabel and overrides the HallucinationEvent on the zone.
/// </summary>
/// <param name="word">Text to display. Null or empty = label keeps its prefab default.</param>
/// <param name="hallucinationEvent">Event to fire when the player enters the zone. Null = no event.</param>
public void Configure(string word, HallucinationEvent hallucinationEvent)
{
if (_floatingLabel != null && !string.IsNullOrEmpty(word))
_floatingLabel.SetText(word);
if (_triggerZone != null)
_triggerZone.SetEvent(hallucinationEvent);
}
// ─── Editor helpers ────────────────────────────────────────────────────
#if UNITY_EDITOR
private void Reset()
{
_floatingLabel = GetComponentInChildren<FloatingLabel>();
_triggerZone = GetComponentInChildren<HallucinationTriggerZone>();
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ba6fa2b368d1e4f4bb84bc6af9f777bc