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
+ -
+ -
-
-
-