diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 6f51421..9241097 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -60,6 +60,7 @@ + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 116fc9c..3ee2004 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -50,6 +50,7 @@ + @@ -82,6 +83,7 @@ + @@ -100,6 +102,7 @@ + diff --git a/Assets/Prefabs/Core.prefab b/Assets/Prefabs/Core.prefab index 67a400d..27c25e5 100644 --- a/Assets/Prefabs/Core.prefab +++ b/Assets/Prefabs/Core.prefab @@ -13,6 +13,7 @@ GameObject: - component: {fileID: 1287070985890992582} - component: {fileID: 2964705630284685173} - component: {fileID: 2236804103334722056} + - component: {fileID: -7963177287827765112} m_Layer: 7 m_Name: Core m_TagString: Untagged @@ -48,7 +49,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 3998537868 + GlobalObjectIdHash: 615747208 InScenePlacedSourceGlobalObjectIdHash: 615747208 DeferredDespawnTick: 0 Ownership: 1 @@ -87,6 +88,9 @@ MonoBehaviour: equipmentPrefab: {fileID: 0} attachOnStart: 1 detachOnEnd: 1 + keepEquipped: 0 + attachDelay: 0 + detachDelay: 0 depositEffectPrefab: {fileID: 0} effectSpawnPoint: {fileID: 0} --- !u!114 &2964705630284685173 @@ -136,6 +140,23 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 10, y: 10, z: 10} m_Center: {x: 0, y: 5, z: 0} +--- !u!114 &-7963177287827765112 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8124290768227340041} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &1237105051606736037 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Gate.prefab b/Assets/Prefabs/Gate.prefab index b8672eb..5161116 100644 --- a/Assets/Prefabs/Gate.prefab +++ b/Assets/Prefabs/Gate.prefab @@ -78,6 +78,7 @@ GameObject: - component: {fileID: 6336968390548483685} - component: {fileID: 1893682255695519596} - component: {fileID: 2622677457934171119} + - component: {fileID: 5472556851078681728} m_Layer: 9 m_Name: Gate m_TagString: Untagged @@ -152,7 +153,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 2819059600 + GlobalObjectIdHash: 1171432577 InScenePlacedSourceGlobalObjectIdHash: 1171432577 DeferredDespawnTick: 0 Ownership: 1 @@ -259,6 +260,23 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 8, y: 8, z: 1} m_Center: {x: 0, y: 0, z: 2} +--- !u!114 &5472556851078681728 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2998551506809628252} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &665699090875585891 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Obstacles/Rock1.prefab b/Assets/Prefabs/Obstacles/Rock1.prefab index 294f084..e1d764b 100644 --- a/Assets/Prefabs/Obstacles/Rock1.prefab +++ b/Assets/Prefabs/Obstacles/Rock1.prefab @@ -9,7 +9,8 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 6371576195603730939} - m_Layer: 0 + - component: {fileID: -3907047637289204963} + m_Layer: 10 m_Name: Rock1 m_TagString: Untagged m_Icon: {fileID: 0} @@ -32,6 +33,24 @@ Transform: - {fileID: 314330220483351248} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &-3907047637289204963 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7867287811520877109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + debugLogging: 1 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &276409350290535739 PrefabInstance: m_ObjectHideFlags: 0 @@ -84,13 +103,47 @@ PrefabInstance: propertyPath: m_Name value: Rock_1_K_Color1 objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} + propertyPath: m_Layer + value: 10 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} + insertIndex: -1 + addedObject: {fileID: 5391599427288743647} m_SourcePrefab: {fileID: 100100000, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} --- !u!4 &314330220483351248 stripped Transform: m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} m_PrefabInstance: {fileID: 276409350290535739} m_PrefabAsset: {fileID: 0} +--- !u!1 &1087453314165295210 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} + m_PrefabInstance: {fileID: 276409350290535739} + m_PrefabAsset: {fileID: 0} +--- !u!64 &5391599427288743647 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1087453314165295210} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 5 + m_Convex: 1 + m_CookingOptions: 30 + m_Mesh: {fileID: 7314371461370138683, guid: 084e4f5c77bba9b48becc0b4a57b6d07, type: 3} diff --git a/Assets/Prefabs/Obstacles/Rock2.prefab b/Assets/Prefabs/Obstacles/Rock2.prefab index 8c88718..01e27e3 100644 --- a/Assets/Prefabs/Obstacles/Rock2.prefab +++ b/Assets/Prefabs/Obstacles/Rock2.prefab @@ -9,7 +9,8 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 5791990943856352332} - m_Layer: 0 + - component: {fileID: 6386629597168169889} + m_Layer: 10 m_Name: Rock2 m_TagString: Untagged m_Icon: {fileID: 0} @@ -32,6 +33,24 @@ Transform: - {fileID: 1472743191925282593} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6386629597168169889 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7245241003860522441} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + debugLogging: 1 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &1439609661864653002 PrefabInstance: m_ObjectHideFlags: 0 @@ -84,13 +103,47 @@ PrefabInstance: propertyPath: m_Name value: Rock_1_E_Color1 objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: aba4f064ac8baf04580049a218a20437, type: 3} + propertyPath: m_Layer + value: 10 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: aba4f064ac8baf04580049a218a20437, type: 3} + insertIndex: -1 + addedObject: {fileID: 8876585294901404683} m_SourcePrefab: {fileID: 100100000, guid: aba4f064ac8baf04580049a218a20437, type: 3} --- !u!4 &1472743191925282593 stripped Transform: m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: aba4f064ac8baf04580049a218a20437, type: 3} m_PrefabInstance: {fileID: 1439609661864653002} m_PrefabAsset: {fileID: 0} +--- !u!1 &2250652532536020379 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: aba4f064ac8baf04580049a218a20437, type: 3} + m_PrefabInstance: {fileID: 1439609661864653002} + m_PrefabAsset: {fileID: 0} +--- !u!64 &8876585294901404683 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2250652532536020379} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 5 + m_Convex: 1 + m_CookingOptions: 30 + m_Mesh: {fileID: 7799962653386975686, guid: aba4f064ac8baf04580049a218a20437, type: 3} diff --git a/Assets/Prefabs/Obstacles/Rock3.prefab b/Assets/Prefabs/Obstacles/Rock3.prefab index bd87bcf..862448f 100644 --- a/Assets/Prefabs/Obstacles/Rock3.prefab +++ b/Assets/Prefabs/Obstacles/Rock3.prefab @@ -9,7 +9,8 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 5832127839780190644} - m_Layer: 0 + - component: {fileID: 6163423706184354979} + m_Layer: 10 m_Name: Rock3 m_TagString: Untagged m_Icon: {fileID: 0} @@ -32,6 +33,24 @@ Transform: - {fileID: 8122136182644622076} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6163423706184354979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7773749726967315046} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + debugLogging: 1 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &8592066193955497239 PrefabInstance: m_ObjectHideFlags: 0 @@ -84,13 +103,47 @@ PrefabInstance: propertyPath: m_Name value: Rock_1_M_Color1 objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} + propertyPath: m_Layer + value: 10 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} + insertIndex: -1 + addedObject: {fileID: 7064843664758881414} m_SourcePrefab: {fileID: 100100000, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} --- !u!4 &8122136182644622076 stripped Transform: m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} m_PrefabInstance: {fileID: 8592066193955497239} m_PrefabAsset: {fileID: 0} +--- !u!1 &8934103170449217606 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} + m_PrefabInstance: {fileID: 8592066193955497239} + m_PrefabAsset: {fileID: 0} +--- !u!64 &7064843664758881414 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8934103170449217606} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 5 + m_Convex: 1 + m_CookingOptions: 30 + m_Mesh: {fileID: -675721469606841765, guid: d6003d5fcbb3d9447ad32f79faa595ae, type: 3} diff --git a/Assets/Prefabs/Obstacles/Tree1.prefab b/Assets/Prefabs/Obstacles/Tree1.prefab index 310a375..f3263b4 100644 --- a/Assets/Prefabs/Obstacles/Tree1.prefab +++ b/Assets/Prefabs/Obstacles/Tree1.prefab @@ -9,7 +9,9 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 7011000049316995908} - m_Layer: 0 + - component: {fileID: 1948217933253124379} + - component: {fileID: 1861572095783484933} + m_Layer: 10 m_Name: Tree1 m_TagString: Untagged m_Icon: {fileID: 0} @@ -32,6 +34,45 @@ Transform: - {fileID: 6530377170908411445} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1948217933253124379 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1559926009631082787} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 0.5, y: 10, z: 0.5} + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &1861572095783484933 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1559926009631082787} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + debugLogging: 1 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &6713237626157896158 PrefabInstance: m_ObjectHideFlags: 0 @@ -84,6 +125,10 @@ PrefabInstance: propertyPath: m_Name value: Tree_2_A_Color1 objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: 308f3ac9346795e41acc026a7f417f0c, type: 3} + propertyPath: m_Layer + value: 10 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] diff --git a/Assets/Prefabs/Obstacles/Tree2.prefab b/Assets/Prefabs/Obstacles/Tree2.prefab index 70db16e..a814579 100644 --- a/Assets/Prefabs/Obstacles/Tree2.prefab +++ b/Assets/Prefabs/Obstacles/Tree2.prefab @@ -9,7 +9,9 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 2594114534543661658} - m_Layer: 0 + - component: {fileID: 6161783292885910878} + - component: {fileID: 5630203293812958152} + m_Layer: 10 m_Name: Tree2 m_TagString: Untagged m_Icon: {fileID: 0} @@ -32,6 +34,45 @@ Transform: - {fileID: 7851729353721699034} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &6161783292885910878 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4345146930867537194} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 0.6, y: 10, z: 0.6} + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &5630203293812958152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4345146930867537194} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + debugLogging: 1 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &7745148207212772657 PrefabInstance: m_ObjectHideFlags: 0 @@ -42,7 +83,7 @@ PrefabInstance: m_Modifications: - target: {fileID: -8679921383154817045, guid: f8d701cc811c2074dbddce4df7348e70, type: 3} propertyPath: m_LocalPosition.x - value: 1.17 + value: 0 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: f8d701cc811c2074dbddce4df7348e70, type: 3} propertyPath: m_LocalPosition.y @@ -84,6 +125,10 @@ PrefabInstance: propertyPath: m_Name value: Tree_2_D_Color1 objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: f8d701cc811c2074dbddce4df7348e70, type: 3} + propertyPath: m_Layer + value: 10 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] diff --git a/Assets/Prefabs/Wall.prefab b/Assets/Prefabs/Wall.prefab index 0977e95..3655c3f 100644 --- a/Assets/Prefabs/Wall.prefab +++ b/Assets/Prefabs/Wall.prefab @@ -13,6 +13,7 @@ GameObject: - component: {fileID: 2599592318476693256} - component: {fileID: 1907881863544148932} - component: {fileID: 3214893598090363914} + - component: {fileID: 9023294375343742146} m_Layer: 9 m_Name: Wall m_TagString: Untagged @@ -124,6 +125,23 @@ MonoBehaviour: effectSpawnPoint: {fileID: 0} showGridBounds: 1 gridBoundsColor: {r: 0, g: 1, b: 1, a: 1} +--- !u!114 &9023294375343742146 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 351020651857757465} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 1 + updateInterval: 0.2 + renderers: [] + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1001 &8926581783111832504 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/GameMain.unity b/Assets/Scenes/GameMain.unity index 679b3bf..b90d6a7 100644 --- a/Assets/Scenes/GameMain.unity +++ b/Assets/Scenes/GameMain.unity @@ -1504,6 +1504,15 @@ MonoBehaviour: cellSize: 1 worldOrigin: {x: -50, y: 0, z: -200} updateInterval: 0.2 + enableLineOfSight: 1 + visionBlockingLayers: + serializedVersion: 2 + m_Bits: 4294967295 + raycastAngularStep: 6 + useDetailedRaycasting: 0 + enableHeightBlocking: 1 + viewerEyeHeight: 1.5 + minBlockingHeight: 2 --- !u!4 &946527919 Transform: m_ObjectHideFlags: 0 @@ -1999,6 +2008,29 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1277246857 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3} + m_PrefabInstance: {fileID: 2264374033617737844} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1277246864 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1277246857} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 0 + updateInterval: 0.2 + renderers: [] + debugLogging: 0 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} --- !u!1 &1433142230 GameObject: m_ObjectHideFlags: 0 @@ -2418,7 +2450,7 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 896 collisionCheckRadius: 1 - spawnOnStart: 1 + spawnOnStart: 0 groupUnderParent: 1 --- !u!4 &1572384099 Transform: @@ -2849,6 +2881,63 @@ Transform: m_CorrespondingSourceObject: {fileID: 5749230937810543840, guid: 88f7f1e8a019b674498ab5fd494c1d34, type: 3} m_PrefabInstance: {fileID: 1862165056} m_PrefabAsset: {fileID: 0} +--- !u!1001 &1912551706 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalPosition.x + value: -8.854406 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalPosition.y + value: 1.0000119 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalPosition.z + value: -60.088272 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5791990943856352332, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7245241003860522441, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} + propertyPath: m_Name + value: Rock2 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 2c33c67d086286d4a929d533b4e26863, type: 3} --- !u!1001 &1975225896 PrefabInstance: m_ObjectHideFlags: 0 @@ -3122,7 +3211,10 @@ PrefabInstance: m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3} + insertIndex: -1 + addedObject: {fileID: 1277246864} m_SourcePrefab: {fileID: 100100000, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3} --- !u!1001 &2588157855179843872 PrefabInstance: @@ -3564,3 +3656,4 @@ SceneRoots: - {fileID: 1442785555} - {fileID: 1440648431994998967} - {fileID: 1061936651} + - {fileID: 1912551706} diff --git a/Assets/Scripts/BuildingManager.cs b/Assets/Scripts/BuildingManager.cs index d2f37fc..27d0072 100644 --- a/Assets/Scripts/BuildingManager.cs +++ b/Assets/Scripts/BuildingManager.cs @@ -205,6 +205,14 @@ namespace Northbound GameObject buildingObj = Instantiate(data.prefab, snappedPosition + data.placementOffset, Quaternion.Euler(0, rotation * 90f, 0)); NetworkObject netObj = buildingObj.GetComponent(); + // Add FogOfWarVisibility component to hide buildings in unexplored areas + if (buildingObj.GetComponent() == null) + { + var visibility = buildingObj.AddComponent(); + visibility.showInExploredAreas = true; // Buildings remain visible in explored areas + visibility.updateInterval = 0.2f; + } + if (netObj != null) { // 건물의 소유자를 설정 @@ -359,6 +367,14 @@ namespace Northbound GameObject foundationObj = Instantiate(foundationPrefab, snappedPosition + data.placementOffset, Quaternion.Euler(0, rotation * 90f, 0)); NetworkObject netObj = foundationObj.GetComponent(); + // Add FogOfWarVisibility component to hide foundations in unexplored areas + if (foundationObj.GetComponent() == null) + { + var visibility = foundationObj.AddComponent(); + visibility.showInExploredAreas = true; // Foundations remain visible in explored areas + visibility.updateInterval = 0.2f; + } + if (netObj != null) { netObj.SpawnWithOwnership(requestingClientId); @@ -425,6 +441,14 @@ namespace Northbound GameObject buildingObj = Instantiate(data.prefab, worldPosition + data.placementOffset, Quaternion.Euler(0, rotation * 90f, 0)); NetworkObject netObj = buildingObj.GetComponent(); + // Add FogOfWarVisibility component to hide buildings in unexplored areas + if (buildingObj.GetComponent() == null) + { + var visibility = buildingObj.AddComponent(); + visibility.showInExploredAreas = true; // Buildings remain visible in explored areas + visibility.updateInterval = 0.2f; + } + if (netObj != null) { netObj.SpawnWithOwnership(ownerId); diff --git a/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs b/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs new file mode 100644 index 0000000..958c580 --- /dev/null +++ b/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs @@ -0,0 +1,170 @@ +using UnityEngine; +using UnityEditor; + +namespace Northbound.Editor +{ + /// + /// Editor utility to add FogOfWarVisibility to all obstacles and buildings + /// + public static class FogOfWarVisibilitySetup + { + [MenuItem("Tools/Fog of War/Add Visibility to All Obstacles")] + public static void AddVisibilityToObstacles() + { + string[] obstaclePaths = new string[] + { + "Assets/Prefabs/Obstacles/Rock1.prefab", + "Assets/Prefabs/Obstacles/Rock2.prefab", + "Assets/Prefabs/Obstacles/Rock3.prefab", + "Assets/Prefabs/Obstacles/Tree1.prefab", + "Assets/Prefabs/Obstacles/Tree2.prefab" + }; + + int count = 0; + foreach (string path in obstaclePaths) + { + GameObject prefab = AssetDatabase.LoadAssetAtPath(path); + if (prefab != null) + { + // Check if already has component + if (prefab.GetComponent() == null) + { + // Add component + var visibility = prefab.AddComponent(); + visibility.showInExploredAreas = false; // Hide obstacles when not visible + visibility.updateInterval = 0.2f; + + EditorUtility.SetDirty(prefab); + count++; + Debug.Log($"Added FogOfWarVisibility to {prefab.name}"); + } + else + { + Debug.Log($"{prefab.name} already has FogOfWarVisibility"); + } + } + else + { + Debug.LogWarning($"Could not find prefab at {path}"); + } + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + Debug.Log($"FogOfWarVisibility added to {count} obstacle prefabs!"); + } + + [MenuItem("Tools/Fog of War/Add Visibility to All Buildings")] + public static void AddVisibilityToBuildings() + { + // Find all Building prefabs + string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Prefabs" }); + + int count = 0; + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + GameObject prefab = AssetDatabase.LoadAssetAtPath(path); + + if (prefab != null && prefab.GetComponent() != null) + { + // Check if already has component + if (prefab.GetComponent() == null) + { + var visibility = prefab.AddComponent(); + visibility.showInExploredAreas = true; // Show buildings in explored areas (greyed out) + visibility.updateInterval = 0.2f; + + EditorUtility.SetDirty(prefab); + count++; + Debug.Log($"Added FogOfWarVisibility to building: {prefab.name}"); + } + } + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + Debug.Log($"FogOfWarVisibility added to {count} building prefabs!"); + } + + [MenuItem("Tools/Fog of War/Add Visibility to Scene Obstacles")] + public static void AddVisibilityToSceneObstacles() + { + GameObject[] allObjects = GameObject.FindObjectsOfType(); + int count = 0; + + foreach (GameObject obj in allObjects) + { + // Skip if it's a prefab instance - those will be handled by prefab updates + if (PrefabUtility.IsPartOfPrefabInstance(obj)) + continue; + + // Check if it has renderers but no FogOfWarVisibility + if (obj.GetComponent() != null && obj.GetComponent() == null) + { + // Check if it's an obstacle (has MeshCollider and no other components) + if (obj.name.Contains("Rock") || obj.name.Contains("Tree") || obj.name.Contains("Obstacle")) + { + var visibility = obj.AddComponent(); + visibility.showInExploredAreas = false; + visibility.updateInterval = 0.2f; + + EditorUtility.SetDirty(obj); + count++; + Debug.Log($"Added FogOfWarVisibility to scene object: {obj.name}"); + } + } + } + + Debug.Log($"FogOfWarVisibility added to {count} scene objects!"); + } + + [MenuItem("Tools/Fog of War/Remove Visibility from All")] + public static void RemoveVisibilityFromAll() + { + if (!EditorUtility.DisplayDialog("Remove FogOfWarVisibility", + "This will remove FogOfWarVisibility from all prefabs and scene objects. Continue?", + "Yes", "Cancel")) + { + return; + } + + // Remove from prefabs + string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Prefabs" }); + int prefabCount = 0; + + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + GameObject prefab = AssetDatabase.LoadAssetAtPath(path); + + if (prefab != null) + { + var visibility = prefab.GetComponent(); + if (visibility != null) + { + Object.DestroyImmediate(visibility, true); + EditorUtility.SetDirty(prefab); + prefabCount++; + } + } + } + + // Remove from scene objects + FogOfWarVisibility[] sceneComponents = GameObject.FindObjectsOfType(); + int sceneCount = sceneComponents.Length; + + foreach (var comp in sceneComponents) + { + Object.DestroyImmediate(comp); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + Debug.Log($"Removed FogOfWarVisibility from {prefabCount} prefabs and {sceneCount} scene objects"); + } + } +} diff --git a/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs.meta b/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs.meta new file mode 100644 index 0000000..8726b21 --- /dev/null +++ b/Assets/Scripts/Editor/FogOfWarVisibilitySetup.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5d15a430ea206c447ad60e74293d5dc1 \ No newline at end of file diff --git a/Assets/Scripts/EnemyPortal.cs b/Assets/Scripts/EnemyPortal.cs index 4f9e72d..acf6d70 100644 --- a/Assets/Scripts/EnemyPortal.cs +++ b/Assets/Scripts/EnemyPortal.cs @@ -22,6 +22,15 @@ public class EnemyPortal : MonoBehaviour foreach (GameObject obj in Enemies) { GameObject enemy = Instantiate(obj, transform); + + // Add FogOfWarVisibility component to hide enemies in unexplored areas + if (enemy.GetComponent() == null) + { + var visibility = enemy.AddComponent(); + visibility.showInExploredAreas = false; // Enemies hidden when not visible + visibility.updateInterval = 0.2f; + } + enemy.GetComponent().Spawn(); Debug.Log(enemy); } diff --git a/Assets/Scripts/EnemyUnit.cs b/Assets/Scripts/EnemyUnit.cs index 7ddb67e..1319744 100644 --- a/Assets/Scripts/EnemyUnit.cs +++ b/Assets/Scripts/EnemyUnit.cs @@ -7,7 +7,7 @@ namespace Northbound /// 적대 유닛 (적대세력 또는 몬스터) /// [RequireComponent(typeof(Collider))] - public class EnemyUnit : NetworkBehaviour, IDamageable, ITeamMember, IVisionProvider + public class EnemyUnit : NetworkBehaviour, IDamageable, ITeamMember { [Header("Team Settings")] [Tooltip("이 유닛의 팀 (Hostile = 적대세력, Monster = 몬스터)")] @@ -15,7 +15,6 @@ namespace Northbound [Header("Combat")] public int maxHealth = 100; - public float visionRange = 10f; [Header("Visual")] public GameObject damageEffectPrefab; @@ -41,20 +40,12 @@ namespace Northbound { _currentHealth.Value = maxHealth; _team.Value = enemyTeam; - - // FogOfWar 시스템에 등록 - FogOfWarSystem.Instance?.RegisterVisionProvider(this); } } public override void OnNetworkDespawn() { base.OnNetworkDespawn(); - - if (IsServer) - { - FogOfWarSystem.Instance?.UnregisterVisionProvider(this); - } } #region IDamageable Implementation @@ -97,9 +88,6 @@ namespace Northbound // 파괴 이펙트 ShowDestroyEffectClientRpc(); - // FogOfWar 시스템에서 제거 - FogOfWarSystem.Instance?.UnregisterVisionProvider(this); - // 네트워크 오브젝트 파괴 Invoke(nameof(DespawnUnit), 0.5f); } @@ -146,28 +134,8 @@ namespace Northbound #endregion - #region IVisionProvider Implementation - - public ulong GetOwnerId() => OwnerClientId; - - public float GetVisionRange() => visionRange; - - public Transform GetTransform() => transform; - - public bool IsActive() => IsSpawned && _currentHealth.Value > 0; - - #endregion - private void OnDrawGizmosSelected() { - // 팀 색상으로 시야 범위 표시 - Color teamColor = Application.isPlaying - ? TeamManager.GetTeamColor(_team.Value) - : TeamManager.GetTeamColor(enemyTeam); - - Gizmos.color = new Color(teamColor.r, teamColor.g, teamColor.b, 0.3f); - Gizmos.DrawWireSphere(transform.position, visionRange); - #if UNITY_EDITOR if (Application.isPlaying) { diff --git a/Assets/Scripts/FogOfWarRenderer.cs b/Assets/Scripts/FogOfWarRenderer.cs index b642550..56a9002 100644 --- a/Assets/Scripts/FogOfWarRenderer.cs +++ b/Assets/Scripts/FogOfWarRenderer.cs @@ -14,6 +14,14 @@ namespace Northbound public float updateInterval = 0.1f; public float fogHeight = 5f; // 안개 높이 (지형보다 약간 위) + [Header("Smoothing")] + [Tooltip("Enable smooth circular vision edges")] + public bool enableSmoothing = true; + + [Tooltip("Smoothing strength (higher = smoother but more blurry)")] + [Range(1, 5)] + public int smoothingPasses = 2; + [Header("Colors")] public Color unexploredColor = new Color(0, 0, 0, 1f); // 완전히 어두움 public Color exploredColor = new Color(0, 0, 0, 0.6f); // 반투명 @@ -51,11 +59,12 @@ namespace Northbound return; } - // 텍스처 생성 + // 텍스처 생성 (Bilinear filtering for smooth edges) _fogTexture = new Texture2D(fogSystem.gridWidth, fogSystem.gridHeight) { filterMode = FilterMode.Bilinear, - wrapMode = TextureWrapMode.Clamp + wrapMode = TextureWrapMode.Clamp, + anisoLevel = 0 // Disable anisotropic filtering for fog overlay }; _colors = new Color[fogSystem.gridWidth * fogSystem.gridHeight]; @@ -133,10 +142,66 @@ namespace Northbound } } + // Apply smoothing if enabled + if (enableSmoothing) + { + SmoothFogTexture(fogSystem.gridWidth, fogSystem.gridHeight); + } + _fogTexture.SetPixels(_colors); _fogTexture.Apply(); } + /// + /// Apply box blur smoothing to create smooth circular vision edges + /// + private void SmoothFogTexture(int width, int height) + { + Color[] smoothed = new Color[_colors.Length]; + + for (int pass = 0; pass < smoothingPasses; pass++) + { + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + int index = y * width + x; + + // Box blur: average with neighbors + float r = 0, g = 0, b = 0, a = 0; + int samples = 0; + + // Sample 3x3 kernel + for (int dy = -1; dy <= 1; dy++) + { + for (int dx = -1; dx <= 1; dx++) + { + int nx = x + dx; + int ny = y + dy; + + if (nx >= 0 && nx < width && ny >= 0 && ny < height) + { + int nIndex = ny * width + nx; + Color c = _colors[nIndex]; + r += c.r; + g += c.g; + b += c.b; + a += c.a; + samples++; + } + } + } + + // Average + smoothed[index] = new Color(r / samples, g / samples, b / samples, a / samples); + } + } + + // Copy smoothed back to colors for next pass + System.Array.Copy(smoothed, _colors, _colors.Length); + } + } + private void CreatePlaneMesh(FogOfWarSystem fogSystem) { MeshFilter meshFilter = GetComponent(); diff --git a/Assets/Scripts/FogOfWarSystem.cs b/Assets/Scripts/FogOfWarSystem.cs index 826859d..15d9d48 100644 --- a/Assets/Scripts/FogOfWarSystem.cs +++ b/Assets/Scripts/FogOfWarSystem.cs @@ -4,6 +4,179 @@ using UnityEngine; namespace Northbound { + /// + /// Helper class for efficient line-of-sight calculations using sector-based raycasting + /// + public class LineOfSightCalculator + { + private struct SectorData + { + public float angle; // Angle in degrees (0-360) + public float blockedDistance; // Distance where vision is blocked (float.MaxValue if clear) + public bool hasObstacle; // True if this sector has an obstacle + public float obstacleHeight; // Height of blocking obstacle + public Vector3 obstaclePosition; // World position of obstacle hit point + } + + private FogOfWarSystem _fogSystem; + private SectorData[] _sectors; + private int _sectorCount; + + public LineOfSightCalculator(FogOfWarSystem fogSystem) + { + _fogSystem = fogSystem; + RecalculateSectors(); + } + + /// + /// Recalculate sector count based on angular step + /// + public void RecalculateSectors() + { + _sectorCount = Mathf.CeilToInt(360f / _fogSystem.raycastAngularStep); + _sectors = new SectorData[_sectorCount]; + + for (int i = 0; i < _sectorCount; i++) + { + _sectors[i].angle = i * _fogSystem.raycastAngularStep; + _sectors[i].blockedDistance = float.MaxValue; + _sectors[i].hasObstacle = false; + _sectors[i].obstacleHeight = 0f; + _sectors[i].obstaclePosition = Vector3.zero; + } + } + + /// + /// Perform raycasting to determine blocked sectors with height awareness + /// + public void CalculateVisibleSectors(Vector3 viewerPosition, float visionRange) + { + // Reset sectors + for (int i = 0; i < _sectorCount; i++) + { + _sectors[i].blockedDistance = float.MaxValue; + _sectors[i].hasObstacle = false; + _sectors[i].obstacleHeight = 0f; + _sectors[i].obstaclePosition = Vector3.zero; + } + + // Raycast origin at viewer eye height + Vector3 rayOrigin = viewerPosition + Vector3.up * _fogSystem.viewerEyeHeight; + + for (int i = 0; i < _sectorCount; i++) + { + float angleRad = _sectors[i].angle * Mathf.Deg2Rad; + Vector3 direction = new Vector3(Mathf.Cos(angleRad), 0, Mathf.Sin(angleRad)); + + if (Physics.Raycast(rayOrigin, direction, out RaycastHit hit, visionRange, _fogSystem.visionBlockingLayers)) + { + _sectors[i].blockedDistance = hit.distance; + _sectors[i].hasObstacle = true; + _sectors[i].obstaclePosition = hit.point; + + // Determine obstacle height + if (_fogSystem.enableHeightBlocking) + { + _sectors[i].obstacleHeight = GetObstacleHeight(hit.collider); + } + } + } + } + + /// + /// Get the height of an obstacle for vision blocking calculations + /// + private float GetObstacleHeight(Collider obstacle) + { + // Check if it's a building + Building building = obstacle.GetComponent(); + if (building != null && building.buildingData != null) + { + return building.buildingData.height; + } + + // For non-buildings (rocks, trees, terrain), use collider bounds + return obstacle.bounds.size.y; + } + + /// + /// Check if a grid cell is visible from viewer position (with height awareness) + /// + public bool IsCellVisible(Vector3 viewerPosition, Vector2Int cellGridPos, float visionRange) + { + Vector3 cellWorldPos = _fogSystem.GridToWorld(cellGridPos.x, cellGridPos.y); + + Vector3 viewerEye = viewerPosition + Vector3.up * _fogSystem.viewerEyeHeight; + Vector3 toCell = cellWorldPos - viewerPosition; + float horizontalDistance = new Vector2(toCell.x, toCell.z).magnitude; + + // Outside vision range + if (horizontalDistance > visionRange) + return false; + + // Calculate angle to cell + float angle = Mathf.Atan2(toCell.z, toCell.x) * Mathf.Rad2Deg; + if (angle < 0) angle += 360f; + + // Find corresponding sector + int sectorIndex = Mathf.FloorToInt(angle / _fogSystem.raycastAngularStep) % _sectorCount; + + // Check if blocked by obstacle in this sector + if (_sectors[sectorIndex].hasObstacle) + { + // Dynamic tolerance to handle large mesh colliders + // Large rocks can be hit several units before their center + // Use cell size + generous buffer for very large obstacles + float distanceTolerance = _fogSystem.cellSize * 5.0f + 3.0f; + + // Height-based blocking check + if (_fogSystem.enableHeightBlocking && _sectors[sectorIndex].obstacleHeight >= _fogSystem.minBlockingHeight) + { + float obstacleDistance = _sectors[sectorIndex].blockedDistance; + + // If cell is beyond obstacle (with tolerance), check if obstacle blocks the sight line + if (horizontalDistance > obstacleDistance + distanceTolerance) + { + // Calculate sight line angle to cell + float verticalAngleToCell = Mathf.Atan2(cellWorldPos.y - viewerEye.y, horizontalDistance); + + // Calculate obstacle top height + float obstacleTopHeight = _sectors[sectorIndex].obstaclePosition.y + _sectors[sectorIndex].obstacleHeight; + + // Calculate angle to obstacle top + float verticalAngleToObstacleTop = Mathf.Atan2(obstacleTopHeight - viewerEye.y, obstacleDistance); + + // If sight line passes below obstacle top, it's blocked + if (verticalAngleToCell <= verticalAngleToObstacleTop) + return false; + } + } + else + { + // Simple distance-based blocking (no height consideration) + // Use tolerance to allow objects at the obstacle position to be visible + if (horizontalDistance > _sectors[sectorIndex].blockedDistance + distanceTolerance) + return false; + } + } + + // Detailed raycasting for edge cases + if (_fogSystem.useDetailedRaycasting) + { + float distanceTolerance = _fogSystem.cellSize * 3.0f + 2.0f; + int prevSector = (sectorIndex - 1 + _sectorCount) % _sectorCount; + int nextSector = (sectorIndex + 1) % _sectorCount; + + if (_sectors[prevSector].hasObstacle && horizontalDistance > _sectors[prevSector].blockedDistance + distanceTolerance) + return false; + if (_sectors[nextSector].hasObstacle && horizontalDistance > _sectors[nextSector].blockedDistance + distanceTolerance) + return false; + } + + return true; + } + } + /// /// 전장의 안개 시스템 - 플레이어별 시야 관리 /// @@ -19,7 +192,31 @@ namespace Northbound [Header("Visibility Settings")] public float updateInterval = 0.2f; - + + [Header("Line of Sight Settings")] + [Tooltip("Enable line-of-sight blocking by obstacles")] + public bool enableLineOfSight = true; + + [Tooltip("Layers that block vision (buildings, obstacles, terrain)")] + public LayerMask visionBlockingLayers = ~0; + + [Tooltip("Angular resolution for raycasting (degrees). Lower = more accurate, higher = better performance")] + [Range(1f, 15f)] + public float raycastAngularStep = 6f; + + [Tooltip("Use detailed raycasting (more accurate but slower)")] + public bool useDetailedRaycasting = false; + + [Header("Height-Based Visibility")] + [Tooltip("Enable height-based vision blocking (tall obstacles block vision)")] + public bool enableHeightBlocking = true; + + [Tooltip("Viewer eye height for line-of-sight calculations")] + public float viewerEyeHeight = 1.5f; + + [Tooltip("Minimum obstacle height to block vision")] + public float minBlockingHeight = 2.0f; + // 서버: 각 플레이어별 가시성 맵 private Dictionary _serverFogData = new Dictionary(); @@ -28,6 +225,7 @@ namespace Northbound private List _visionProviders = new List(); private float _updateTimer; + private LineOfSightCalculator _losCalculator; private void Awake() { @@ -37,12 +235,19 @@ namespace Northbound return; } Instance = this; + _losCalculator = new LineOfSightCalculator(this); } public override void OnNetworkSpawn() { base.OnNetworkSpawn(); - + + if (IsServer) + { + // Server: Register client connected callback to initialize fog data + NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected; + } + if (IsClient && !IsServer) { // 클라이언트는 로컬 데이터 초기화 @@ -51,6 +256,28 @@ namespace Northbound } } + private void OnClientConnected(ulong clientId) + { + if (!IsServer) return; + + // Ensure fog data exists for this client + if (!_serverFogData.ContainsKey(clientId)) + { + _serverFogData[clientId] = new FogOfWarData(gridWidth, gridHeight); + Debug.Log($"[FogOfWar] 클라이언트 {clientId} 안개 데이터 초기화"); + } + } + + public override void OnNetworkDespawn() + { + base.OnNetworkDespawn(); + + if (IsServer && NetworkManager.Singleton != null) + { + NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected; + } + } + private void Update() { if (!IsServer) return; @@ -167,7 +394,7 @@ namespace Northbound } /// - /// 특정 영역을 밝힘 (서버만) + /// 특정 영역을 밝힘 (서버만) - Line-of-Sight 지원 /// private void RevealArea(ulong clientId, Vector3 worldPosition, float radius) { @@ -176,11 +403,19 @@ namespace Northbound int cellRadius = Mathf.CeilToInt(radius / cellSize); + // Line-of-sight raycasting if enabled + if (enableLineOfSight) + { + _losCalculator.CalculateVisibleSectors(worldPosition, radius); + } + for (int x = -cellRadius; x <= cellRadius; x++) { for (int y = -cellRadius; y <= cellRadius; y++) { - if (x * x + y * y > cellRadius * cellRadius) continue; + // Basic circular range check + if (x * x + y * y > cellRadius * cellRadius) + continue; int gridX = gridPos.x + x; int gridY = gridPos.y + y; @@ -188,6 +423,14 @@ namespace Northbound if (gridX < 0 || gridX >= gridWidth || gridY < 0 || gridY >= gridHeight) continue; + // Line-of-sight check + if (enableLineOfSight) + { + Vector2Int cellPos = new Vector2Int(gridX, gridY); + if (!_losCalculator.IsCellVisible(worldPosition, cellPos, radius)) + continue; + } + // 현재 시야에 표시 + 방문한 적 있음으로 기록 fogData.SetVisible(gridX, gridY, true); fogData.SetExplored(gridX, gridY, true); diff --git a/Assets/Scripts/FogOfWarVisibility.cs b/Assets/Scripts/FogOfWarVisibility.cs new file mode 100644 index 0000000..f2054a8 --- /dev/null +++ b/Assets/Scripts/FogOfWarVisibility.cs @@ -0,0 +1,349 @@ +using Unity.Netcode; +using UnityEngine; + +namespace Northbound +{ + /// + /// Controls object visibility based on fog of war state + /// Attach to buildings, obstacles, enemies, or any object that should be hidden in fog + /// + public class FogOfWarVisibility : MonoBehaviour + { + [Header("Visibility Settings")] + [Tooltip("Show this object in explored areas (greyed out) or only when visible")] + public bool showInExploredAreas = false; + + [Tooltip("Update frequency for checking fog state (seconds)")] + public float updateInterval = 0.2f; + + [Tooltip("Renderers to show/hide (auto-detected if empty)")] + public Renderer[] renderers; + + [Tooltip("Enable debug logging for this object")] + public bool debugLogging = false; + + [Header("Height-Based Distant Visibility")] + [Tooltip("Enable visibility from farther away based on object height")] + public bool enableDistantVisibility = true; + + [Tooltip("Visibility range multiplier per unit of height (default: 2x vision per 1m height)")] + public float heightVisibilityMultiplier = 2.0f; + + [Tooltip("Minimum height to get extended visibility (meters)")] + public float minHeightForDistantVisibility = 3.0f; + + [Header("Explored State Visual (Optional)")] + [Tooltip("Apply grey/desaturated material when in explored state")] + public bool useExploredMaterial = false; + + [Tooltip("Material to use in explored state (optional)")] + public Material exploredMaterial; + + private Material[] _originalMaterials; + private bool _isVisible = false; + private float _updateTimer; + private ulong _localClientId; + private bool _isInitialized = false; + private float _objectHeight = 0f; + + private void Start() + { + // Auto-detect renderers if not set + if (renderers == null || renderers.Length == 0) + { + renderers = GetComponentsInChildren(); + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Auto-detected {renderers.Length} renderers"); + } + } + + if (renderers == null || renderers.Length == 0) + { + Debug.LogWarning($"[FogOfWarVisibility] {gameObject.name}: No renderers found! Component will not work."); + return; + } + + // Store original materials for explored state + if (useExploredMaterial && renderers != null && renderers.Length > 0) + { + _originalMaterials = new Material[renderers.Length]; + for (int i = 0; i < renderers.Length; i++) + { + if (renderers[i] != null) + { + _originalMaterials[i] = renderers[i].sharedMaterial; + } + } + } + + // Calculate object height for distant visibility + _objectHeight = CalculateObjectHeight(); + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Object height = {_objectHeight}m"); + } + + // CRITICAL: Start hidden and stay hidden until fog system confirms visibility + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: START - Setting all {renderers.Length} renderers to HIDDEN"); + } + + // Force initial hide - don't use SetVisible because _isVisible defaults to false + // which would cause early return + _isVisible = true; // Set to true first so SetVisible(false) actually runs + SetVisible(false); + } + + /// + /// Calculate the height of this object for distant visibility + /// + private float CalculateObjectHeight() + { + // Try to get height from Building component + var building = GetComponent(); + if (building != null && building.buildingData != null) + { + return building.buildingData.height; + } + + // Fallback: Use renderer bounds + if (renderers != null && renderers.Length > 0) + { + float maxHeight = 0f; + foreach (var renderer in renderers) + { + if (renderer != null) + { + maxHeight = Mathf.Max(maxHeight, renderer.bounds.size.y); + } + } + return maxHeight; + } + + // Last resort: Use collider bounds + var collider = GetComponent(); + if (collider != null) + { + return collider.bounds.size.y; + } + + return 0f; + } + + private void Update() + { + // Only run on clients, not on dedicated server + if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsClient) + { + // Dedicated server - don't process visibility + return; + } + + // Initialize when network is ready + if (!_isInitialized) + { + if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsClient) + { + _localClientId = NetworkManager.Singleton.LocalClientId; + _isInitialized = true; + + // Force immediate visibility update on initialization + UpdateVisibility(); + } + else + { + // Network not ready - stay hidden + SetVisible(false); + return; + } + } + + _updateTimer += Time.deltaTime; + if (_updateTimer >= updateInterval) + { + _updateTimer = 0f; + UpdateVisibility(); + } + } + + private void UpdateVisibility() + { + var fogSystem = FogOfWarSystem.Instance; + if (fogSystem == null) + { + // No fog system - stay hidden for safety + SetVisible(false); + return; + } + + // Wait for fog data to be initialized + var fogData = fogSystem.GetPlayerFogData(_localClientId); + if (fogData == null) + { + // Fog data not ready yet - stay hidden + SetVisible(false); + return; + } + + FogOfWarState fogState = fogSystem.GetVisibilityState(_localClientId, transform.position); + + // Check for distant visibility based on height + bool isDistantVisible = false; + if (enableDistantVisibility && _objectHeight >= minHeightForDistantVisibility) + { + isDistantVisible = CheckDistantVisibility(fogSystem); + } + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name} at {transform.position}: State={fogState}, DistantVisible={isDistantVisible}, Height={_objectHeight}m"); + } + + switch (fogState) + { + case FogOfWarState.Visible: + // Currently visible - show with original materials + if (debugLogging) Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Setting VISIBLE"); + SetVisible(true); + SetExploredVisual(false); + break; + + case FogOfWarState.Explored: + // Previously seen but not currently visible + // BUT: Tall objects can be seen from farther away + if (showInExploredAreas || isDistantVisible) + { + if (debugLogging) Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Setting EXPLORED (visible) - distantVisible={isDistantVisible}"); + SetVisible(true); + SetExploredVisual(true); + } + else + { + if (debugLogging) Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Setting EXPLORED (hidden)"); + SetVisible(false); + } + break; + + case FogOfWarState.Unexplored: + // Never seen - hide unless tall enough to see from distance + if (isDistantVisible) + { + if (debugLogging) Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Setting UNEXPLORED but DISTANT VISIBLE"); + SetVisible(true); + SetExploredVisual(true); // Show as explored/distant + } + else + { + if (debugLogging) Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Setting UNEXPLORED (hidden)"); + SetVisible(false); + } + break; + + default: + // Unknown state - hide completely + SetVisible(false); + break; + } + } + + /// + /// Check if this object should be visible from a distance based on its height + /// + private bool CheckDistantVisibility(FogOfWarSystem fogSystem) + { + // Find the closest vision provider (player) + if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsClient) + return false; + + // Get local player object + var localPlayer = NetworkManager.Singleton.LocalClient?.PlayerObject; + if (localPlayer == null) + return false; + + // Calculate distance to player + float distanceToPlayer = Vector3.Distance(transform.position, localPlayer.transform.position); + + // Calculate extended visibility range based on height + // Taller objects can be seen from farther away + // Formula: Base range + (height - minHeight) * multiplier + float extendedRange = (_objectHeight - minHeightForDistantVisibility) * heightVisibilityMultiplier; + + // Get player's vision range (assume average vision provider has ~15 unit range) + float baseVisionRange = 15f; // You can make this configurable + float totalRange = baseVisionRange + extendedRange; + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Distance={distanceToPlayer:F1}m, ExtendedRange={totalRange:F1}m (height bonus: +{extendedRange:F1}m)"); + } + + return distanceToPlayer <= totalRange; + } + + private void SetVisible(bool visible) + { + if (_isVisible == visible) return; + + _isVisible = visible; + + if (renderers == null || renderers.Length == 0) + { + if (debugLogging) + { + Debug.LogWarning($"[FogOfWarVisibility] {gameObject.name}: SetVisible({visible}) called but no renderers!"); + } + return; + } + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: SetVisible({visible}) - updating {renderers.Length} renderers"); + } + + foreach (var renderer in renderers) + { + if (renderer != null) + { + renderer.enabled = visible; + + if (debugLogging) + { + Debug.Log($"[FogOfWarVisibility] {gameObject.name}: Renderer '{renderer.name}' enabled = {visible}"); + } + } + } + } + + private void SetExploredVisual(bool explored) + { + if (!useExploredMaterial || renderers == null || exploredMaterial == null) + return; + + for (int i = 0; i < renderers.Length; i++) + { + if (renderers[i] != null) + { + if (explored) + { + renderers[i].material = exploredMaterial; + } + else if (_originalMaterials != null && i < _originalMaterials.Length) + { + renderers[i].material = _originalMaterials[i]; + } + } + } + } + + private void OnDrawGizmosSelected() + { + // Visualize fog state check position + Gizmos.color = _isVisible ? Color.green : Color.red; + Gizmos.DrawWireSphere(transform.position, 0.5f); + } + } +} diff --git a/Assets/Scripts/FogOfWarVisibility.cs.meta b/Assets/Scripts/FogOfWarVisibility.cs.meta new file mode 100644 index 0000000..df0492d --- /dev/null +++ b/Assets/Scripts/FogOfWarVisibility.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 760137a2fd0da7f458ac4b0ee7f485d6 \ No newline at end of file diff --git a/Assets/Scripts/ObstacleSpawner.cs b/Assets/Scripts/ObstacleSpawner.cs index aff3e8d..d5d55aa 100644 --- a/Assets/Scripts/ObstacleSpawner.cs +++ b/Assets/Scripts/ObstacleSpawner.cs @@ -254,6 +254,14 @@ namespace Northbound obstacle.transform.localScale *= scale; } + // Add FogOfWarVisibility component to hide obstacles in unexplored areas + if (obstacle.GetComponent() == null) + { + var visibility = obstacle.AddComponent(); + visibility.showInExploredAreas = false; // Obstacles hidden when not visible + visibility.updateInterval = 0.2f; + } + _spawnedPositions.Add(randomPos); Debug.Log($"[Spawn] 장애물 배치 성공: {obstacleEntry.prefab.name} at {randomPos}"); return true; diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 16ecd3b..af265bf 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -15,9 +15,9 @@ TagManager: - Interactable - Enemy - Player - - - - - - + - Obstacle + - + - - - -