diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj
index 39a2197..de4d5c1 100644
--- a/Assembly-CSharp.csproj
+++ b/Assembly-CSharp.csproj
@@ -58,6 +58,7 @@
+
diff --git a/Assets/Scenes/GameMain.unity b/Assets/Scenes/GameMain.unity
index b71e09c..58aa196 100644
--- a/Assets/Scenes/GameMain.unity
+++ b/Assets/Scenes/GameMain.unity
@@ -143,15 +143,20 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 61373298}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 16.14601, y: -0.99998, z: -532.7231}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 519420032}
- {fileID: 1290143990}
- m_Father: {fileID: 0}
+ m_Father: {fileID: 576429380}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!4 &109813795 stripped
+Transform:
+ m_CorrespondingSourceObject: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
+ m_PrefabInstance: {fileID: 1061936651}
+ m_PrefabAsset: {fileID: 0}
--- !u!1 &306979656
GameObject:
m_ObjectHideFlags: 0
@@ -329,8 +334,8 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 447015514}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -10, y: 1, z: -80}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 6.1460094, y: 0.00002002716, z: -612.7231}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
@@ -338,7 +343,7 @@ Transform:
- {fileID: 1536695130}
- {fileID: 629469724}
- {fileID: 2098115308}
- m_Father: {fileID: 0}
+ m_Father: {fileID: 576429380}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &457600242
GameObject:
@@ -661,6 +666,45 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
CustomBlends: {fileID: 0}
+--- !u!1 &576429379
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 576429380}
+ m_Layer: 0
+ m_Name: Defaults
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &576429380
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 576429379}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: -16.14601, y: 0.99998, z: 532.7231}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 61373299}
+ - {fileID: 1135136907}
+ - {fileID: 782070683}
+ - {fileID: 8940572951313384071}
+ - {fileID: 447015515}
+ - {fileID: 1138174508}
+ - {fileID: 109813795}
+ - {fileID: 639696858}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &629469723
PrefabInstance:
m_ObjectHideFlags: 0
@@ -735,6 +779,173 @@ Transform:
m_CorrespondingSourceObject: {fileID: 922888705413710451, guid: 5662d0b0d0eb5f54290edd8dd0980b57, type: 3}
m_PrefabInstance: {fileID: 629469723}
m_PrefabAsset: {fileID: 0}
+--- !u!4 &639696858 stripped
+Transform:
+ m_CorrespondingSourceObject: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
+ m_PrefabInstance: {fileID: 463088717151812744}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1 &640318136
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 640318137}
+ m_Layer: 0
+ m_Name: System
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &640318137
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 640318136}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: -16.14601, y: 0.99998, z: 532.7231}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1442785555}
+ - {fileID: 672563223}
+ - {fileID: 1142746334}
+ - {fileID: 1199559224}
+ - {fileID: 955933985}
+ - {fileID: 946527919}
+ - {fileID: 1701756768}
+ - {fileID: 1166878644}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &672563220
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 672563223}
+ - component: {fileID: 672563221}
+ - component: {fileID: 672563222}
+ m_Layer: 0
+ m_Name: MapGenerator
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &672563221
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 672563220}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
+ GlobalObjectIdHash: 3027998365
+ InScenePlacedSourceGlobalObjectIdHash: 0
+ DeferredDespawnTick: 0
+ Ownership: 1
+ AlwaysReplicateAsRoot: 0
+ SynchronizeTransform: 1
+ ActiveSceneSynchronization: 0
+ SceneMigrationSynchronization: 0
+ SpawnWithObservers: 1
+ DontDestroyWithOwner: 0
+ AutoObjectParentSync: 1
+ SyncOwnerTransformWhenParented: 1
+ AllowOwnerToParent: 0
+--- !u!114 &672563222
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 672563220}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f0dde802bf94bf6448eb7d4838d1c42a, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::Northbound.MapGenerator
+ ShowTopMostFoldoutHeaderGroup: 1
+ generateOnSpawn: 1
+ groupUnderParent: 1
+ playableAreaWidth: 80
+ startZ: -75
+ endZ: 700
+ resourcePrefab: {fileID: 5585059388146411250, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
+ minResourceCount: 8
+ maxResourceCount: 12
+ minDistanceBetweenResources: 80
+ minDistanceFromCore: 50
+ minDistanceFromBarracks: 50
+ initialResourceProduction: 50
+ additionalResourceBaseProduction: 25
+ targetTotalProduction: 300
+ targetProductionTolerance: 0.05
+ minQualityModifier: -30
+ maxQualityModifier: 30
+ maxResourceGenerationAttempts: 10
+ obstacles:
+ - prefab: {fileID: 7867287811520877109, guid: 915c4daebc2463840b83193366491ba1, type: 3}
+ spawnWeight: 5
+ minCount: 0
+ maxCount: 99999
+ - prefab: {fileID: 7245241003860522441, guid: 2c33c67d086286d4a929d533b4e26863, type: 3}
+ spawnWeight: 20
+ minCount: 0
+ maxCount: 99999
+ - prefab: {fileID: 7773749726967315046, guid: b49d9f4b44d4c7d4b92498e95c847667, type: 3}
+ spawnWeight: 5
+ minCount: 0
+ maxCount: 99999
+ - prefab: {fileID: 1559926009631082787, guid: 4ade932e47f340647ac833f7188a6dd0, type: 3}
+ spawnWeight: 30
+ minCount: 0
+ maxCount: 99999
+ - prefab: {fileID: 4345146930867537194, guid: d754e5f1f9047ce428c55a0ae1975b4e, type: 3}
+ spawnWeight: 30
+ minCount: 0
+ maxCount: 99999
+ obstacleDensity: 0.01
+ maxTotalObstacles: 10000
+ minDistanceBetweenObstacles: 2
+ checkCollision: 1
+ collisionLayers:
+ serializedVersion: 2
+ m_Bits: 1152
+ collisionCheckRadius: 1
+ alignToTerrain: 1
+ randomRotation: 1
+ scaleVariation: 0.2
+ maxObstacleSpawnAttempts: 50
+ generateResourcesFirst: 1
+--- !u!4 &672563223
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 672563220}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 16.14601, y: -0.99998, z: -532.7231}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 640318137}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &768754084
GameObject:
m_ObjectHideFlags: 0
@@ -932,11 +1143,11 @@ Transform:
m_GameObject: {fileID: 782070680}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
- m_LocalPosition: {x: -0.76944, y: 1, z: 7.59836}
+ m_LocalPosition: {x: 15.37657, y: 0.00002002716, z: -525.1247}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 576429380}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &908127335
GameObject:
@@ -1154,12 +1365,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 946527916}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 100, z: -50}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 16.14601, y: 99.00002, z: -582.7231}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &955933983
GameObject:
@@ -1199,12 +1410,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 955933983}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -29.48045, y: -0, z: -38.91273}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: -13.33444, y: -0.99998, z: -571.6358}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &985764481 stripped
GameObject:
@@ -1348,19 +1559,19 @@ PrefabInstance:
serializedVersion: 2
m_Modification:
serializedVersion: 3
- m_TransformParent: {fileID: 0}
+ m_TransformParent: {fileID: 576429380}
m_Modifications:
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.x
- value: 20
+ value: 36.14601
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.y
- value: 1
+ value: 0.00002002716
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.z
- value: 650
+ value: 117.27692
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.w
@@ -1368,15 +1579,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.x
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.y
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.z
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -1431,6 +1642,16 @@ PrefabInstance:
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
+--- !u!4 &1135136907 stripped
+Transform:
+ m_CorrespondingSourceObject: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
+ m_PrefabInstance: {fileID: 4875211098963642791}
+ m_PrefabAsset: {fileID: 0}
+--- !u!4 &1138174508 stripped
+Transform:
+ m_CorrespondingSourceObject: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
+ m_PrefabInstance: {fileID: 1440648431994998967}
+ m_PrefabAsset: {fileID: 0}
--- !u!1 &1142746332
GameObject:
m_ObjectHideFlags: 0
@@ -1468,12 +1689,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1142746332}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0.64446, y: 5.17816, z: -1.23575}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 16.79047, y: 4.17818, z: -533.95886}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1166878641
GameObject:
@@ -1547,12 +1768,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1166878641}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 16.14601, y: -0.99998, z: -532.7231}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1199559221
GameObject:
@@ -1626,12 +1847,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1199559221}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -0.48349, y: 1, z: 0.31137}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 15.662519, y: 0.00002002716, z: -532.41174}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1290143989
GameObject:
@@ -1828,7 +2049,7 @@ MonoBehaviour:
m_DisconnectTimeoutMS: 30000
ConnectionData:
Address: 127.0.0.1
- Port: 7843
+ Port: 7914
ServerListenAddress: 127.0.0.1
ClientBindPort: 0
DebugSimulator:
@@ -1919,12 +2140,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1442785552}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -20.15257, y: 1.00001, z: 4.73882}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: -4.0065613, y: 0.000030040741, z: -527.98425}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &1536695129
PrefabInstance:
@@ -2000,115 +2221,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 922888705413710451, guid: 5662d0b0d0eb5f54290edd8dd0980b57, type: 3}
m_PrefabInstance: {fileID: 1536695129}
m_PrefabAsset: {fileID: 0}
---- !u!1 &1572384097
-GameObject:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- serializedVersion: 6
- m_Component:
- - component: {fileID: 1572384099}
- - component: {fileID: 1572384100}
- - component: {fileID: 1572384098}
- m_Layer: 0
- m_Name: ObstacleSpawner
- m_TagString: Untagged
- m_Icon: {fileID: 0}
- m_NavMeshLayer: 0
- m_StaticEditorFlags: 0
- m_IsActive: 1
---- !u!114 &1572384098
-MonoBehaviour:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1572384097}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: a889d8fab7aeaa24dbbffaee2f02ba54, type: 3}
- m_Name:
- m_EditorClassIdentifier: Assembly-CSharp::Northbound.ObstacleSpawner
- ShowTopMostFoldoutHeaderGroup: 1
- spawnCenter: {fileID: 0}
- spawnAreaSize: {x: 80, y: 725}
- areaShape: 0
- obstacles:
- - prefab: {fileID: 1559926009631082787, guid: 4ade932e47f340647ac833f7188a6dd0, type: 3}
- spawnWeight: 40
- minCount: 0
- maxCount: 290
- - prefab: {fileID: 4345146930867537194, guid: d754e5f1f9047ce428c55a0ae1975b4e, type: 3}
- spawnWeight: 40
- minCount: 0
- maxCount: 307
- - prefab: {fileID: 7867287811520877109, guid: 915c4daebc2463840b83193366491ba1, type: 3}
- spawnWeight: 5
- minCount: 0
- maxCount: 247
- - prefab: {fileID: 7245241003860522441, guid: 2c33c67d086286d4a929d533b4e26863, type: 3}
- spawnWeight: 30
- minCount: 0
- maxCount: 274
- - prefab: {fileID: 7773749726967315046, guid: b49d9f4b44d4c7d4b92498e95c847667, type: 3}
- spawnWeight: 10
- minCount: 0
- maxCount: 228
- density: 0.02
- maxTotalObstacles: 6400
- minDistanceBetweenObstacles: 4
- alignToTerrain: 1
- randomRotation: 1
- scaleVariation: 0.197
- maxAttempts: 50
- checkCollision: 1
- collisionLayers:
- serializedVersion: 2
- m_Bits: 896
- collisionCheckRadius: 1
- spawnOnStart: 1
- groupUnderParent: 1
---- !u!4 &1572384099
-Transform:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1572384097}
- serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 1, z: 290}
- m_LocalScale: {x: 1, y: 1, z: 1}
- m_ConstrainProportionsScale: 0
- m_Children: []
- m_Father: {fileID: 0}
- m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!114 &1572384100
-MonoBehaviour:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1572384097}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
- m_Name:
- m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
- GlobalObjectIdHash: 2866586184
- InScenePlacedSourceGlobalObjectIdHash: 0
- DeferredDespawnTick: 0
- Ownership: 1
- AlwaysReplicateAsRoot: 0
- SynchronizeTransform: 1
- ActiveSceneSynchronization: 0
- SceneMigrationSynchronization: 0
- SpawnWithObservers: 1
- DontDestroyWithOwner: 0
- AutoObjectParentSync: 1
- SyncOwnerTransformWhenParented: 1
- AllowOwnerToParent: 0
--- !u!1 &1701756764
GameObject:
m_ObjectHideFlags: 0
@@ -2213,12 +2325,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1701756764}
serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -0.16227, y: 1.00001, z: -48.21116}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 15.98374, y: 0.000030040741, z: -580.93427}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
- m_Father: {fileID: 0}
+ m_Father: {fileID: 640318137}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1859567749
GameObject:
@@ -2445,7 +2557,7 @@ PrefabInstance:
serializedVersion: 2
m_Modification:
serializedVersion: 3
- m_TransformParent: {fileID: 0}
+ m_TransformParent: {fileID: 576429380}
m_Modifications:
- target: {fileID: 2255421732537623704, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_Name
@@ -2457,15 +2569,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalPosition.x
- value: 10
+ value: 26.14601
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalPosition.y
- value: 1
+ value: 0.00002002716
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalPosition.z
- value: -90
+ value: -622.7231
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalRotation.w
@@ -2473,7 +2585,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalRotation.x
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalRotation.y
@@ -2481,7 +2593,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalRotation.z
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -2506,19 +2618,19 @@ PrefabInstance:
serializedVersion: 2
m_Modification:
serializedVersion: 3
- m_TransformParent: {fileID: 0}
+ m_TransformParent: {fileID: 576429380}
m_Modifications:
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.x
- value: -20
+ value: -3.8539906
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.y
- value: 1
+ value: 0.00002002716
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalPosition.z
- value: 650
+ value: 117.27692
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.w
@@ -2526,15 +2638,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.x
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.y
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalRotation.z
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 228462577495887354, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -2660,7 +2772,7 @@ PrefabInstance:
serializedVersion: 2
m_Modification:
serializedVersion: 3
- m_TransformParent: {fileID: 0}
+ m_TransformParent: {fileID: 576429380}
m_Modifications:
- target: {fileID: 1287070985890992582, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: equipmentData.socketName
@@ -2700,15 +2812,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalPosition.x
- value: 0
+ value: 16.14601
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalPosition.y
- value: 0
+ value: -0.99998
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalPosition.z
- value: -90
+ value: -622.7231
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalRotation.w
@@ -2716,15 +2828,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalRotation.x
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalRotation.y
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalRotation.z
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -2753,19 +2865,19 @@ PrefabInstance:
serializedVersion: 2
m_Modification:
serializedVersion: 3
- m_TransformParent: {fileID: 0}
+ m_TransformParent: {fileID: 576429380}
m_Modifications:
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalPosition.x
- value: -30
+ value: -13.853991
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalPosition.y
- value: 1
+ value: 0.00002002716
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalPosition.z
- value: -90
+ value: -622.7231
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalRotation.w
@@ -2773,7 +2885,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalRotation.x
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalRotation.y
@@ -2781,7 +2893,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalRotation.z
- value: 0
+ value: -0
objectReference: {fileID: 0}
- target: {fileID: 3247786716306397435, guid: f395fcc064a3a834ba957327f1387c19, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -2819,26 +2931,17 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7c94274e2af2c8d4f827fe52b26c4410, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Northbound.Core
+--- !u!4 &8940572951313384071 stripped
+Transform:
+ m_CorrespondingSourceObject: {fileID: 8064559726283331702, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
+ m_PrefabInstance: {fileID: 4786254629656932894}
+ m_PrefabAsset: {fileID: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1975225896}
- {fileID: 1433142232}
- - {fileID: 61373299}
- - {fileID: 1142746334}
- - {fileID: 1199559224}
- - {fileID: 4875211098963642791}
- - {fileID: 782070683}
- - {fileID: 4786254629656932894}
- - {fileID: 447015515}
- - {fileID: 955933985}
- {fileID: 457600247}
- - {fileID: 1166878644}
- - {fileID: 946527919}
- - {fileID: 1701756768}
- - {fileID: 1572384099}
- - {fileID: 1442785555}
- - {fileID: 1440648431994998967}
- - {fileID: 1061936651}
- - {fileID: 463088717151812744}
+ - {fileID: 640318137}
+ - {fileID: 576429380}
diff --git a/Assets/Scripts/MapGenerator.cs b/Assets/Scripts/MapGenerator.cs
new file mode 100644
index 0000000..71c7596
--- /dev/null
+++ b/Assets/Scripts/MapGenerator.cs
@@ -0,0 +1,774 @@
+using Unity.Netcode;
+using UnityEngine;
+using System.Collections.Generic;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace Northbound
+{
+ public class MapGenerator : NetworkBehaviour
+ {
+ public static MapGenerator Instance { get; private set; }
+
+ [Header("Common Settings")]
+ [Tooltip("맵 생성 시작 시 자동 생성")]
+ [SerializeField] private bool generateOnSpawn = true;
+ [Tooltip("생성된 오브젝트를 부모로 그룹화")]
+ [SerializeField] private bool groupUnderParent = true;
+
+ [Header("Map Boundaries")]
+ [Tooltip("X 범위 (-width/2 ~ +width/2)")]
+ public float playableAreaWidth = 200f;
+ [Tooltip("Z 시작 위치")]
+ public float startZ = 25f;
+ [Tooltip("Z 끝 위치")]
+ public float endZ = 700f;
+
+ private Vector2 _initialResourcePosition;
+ private Vector2 _corePosition;
+ private Vector2 _barracksPosition;
+
+ [Header("Resource Generation")]
+ [Tooltip("자원 프리팹")]
+ public GameObject resourcePrefab;
+ [Tooltip("최소 자원 개수 (초기 자원 제외)")]
+ [Range(8, 12)]
+ public int minResourceCount = 8;
+ [Tooltip("최대 자원 개수 (초기 자원 제외)")]
+ [Range(8, 12)]
+ public int maxResourceCount = 12;
+ [Tooltip("자원 간 최소 거리")]
+ public float minDistanceBetweenResources = 80f;
+ [Tooltip("코어와의 최소 거리")]
+ public float minDistanceFromCore = 50f;
+ [Tooltip("막사와의 최소 거리")]
+ public float minDistanceFromBarracks = 50f;
+ [Tooltip("초기 자원 생산량 (분당)")]
+ public float initialResourceProduction = 50f;
+ [Tooltip("추가 자원 기본 생산량 (분당)")]
+ public float additionalResourceBaseProduction = 25f;
+ [Tooltip("목표 총 생산량 (분당)")]
+ public float targetTotalProduction = 300f;
+ [Tooltip("생산량 허용 오차")]
+ [Range(0f, 0.2f)]
+ public float targetProductionTolerance = 0.05f;
+ [Tooltip("최소 품질 보정")]
+ public float minQualityModifier = -30f;
+ [Tooltip("최대 품질 보정")]
+ public float maxQualityModifier = 30f;
+ [Tooltip("최대 생성 시도 횟수")]
+ public int maxResourceGenerationAttempts = 10;
+
+ [Header("Obstacle Settings")]
+ [Tooltip("배치할 장애물 목록")]
+ [SerializeField] private List obstacles = new List();
+ [Tooltip("장애물 밀도")]
+ [Range(0f, 1f)]
+ [SerializeField] private float obstacleDensity = 0.5f;
+ [Tooltip("최대 장애물 개수")]
+ [SerializeField] private int maxTotalObstacles = 100;
+ [Tooltip("장애물 간 최소 거리")]
+ [SerializeField] private float minDistanceBetweenObstacles = 2f;
+ [Tooltip("배치 전 충돌 체크")]
+ [SerializeField] private bool checkCollision = true;
+ [Tooltip("충돌 체크 레이어")]
+ [SerializeField] private LayerMask collisionLayers = -1;
+ [Tooltip("충돌 체크 반경")]
+ [SerializeField] private float collisionCheckRadius = 1f;
+ [Tooltip("지형에 맞춰 배치")]
+ [SerializeField] private bool alignToTerrain = true;
+ [Tooltip("Y축 랜덤 회전 적용")]
+ [SerializeField] private bool randomRotation = true;
+ [Tooltip("크기 랜덤 변화 범위")]
+ [Range(0f, 0.5f)]
+ [SerializeField] private float scaleVariation = 0.1f;
+ [Tooltip("배치 시도 최대 횟수")]
+ [SerializeField] private int maxObstacleSpawnAttempts = 50;
+
+ [Header("Generation Order")]
+ [Tooltip("자원 먼저 생성 후 장애물 생성 (true) 또는 그 반대 (false)")]
+ [SerializeField] private bool generateResourcesFirst = true;
+
+ private ResourceData[] _generatedResources;
+ private float _globalProductionMultiplier = 1f;
+ private List _spawnedPositions = new List();
+ private Transform _objectsParent;
+
+ [System.Serializable]
+ public class ObstacleEntry
+ {
+ [Tooltip("배치할 장애물 프리팹")]
+ public GameObject prefab;
+
+ [Tooltip("이 장애물의 스폰 가중치")]
+ [Range(1, 100)]
+ public int spawnWeight = 50;
+
+ [Tooltip("최소 스폰 개수")]
+ public int minCount = 0;
+
+ [Tooltip("최대 스폰 개수")]
+ public int maxCount = 10;
+ }
+
+ public override void OnNetworkSpawn()
+ {
+ if (IsServer && generateOnSpawn)
+ {
+ Instance = this;
+ FindImportantPositions();
+ GenerateMap();
+ }
+ }
+
+ private void FindImportantPositions()
+ {
+ Core core = FindObjectOfType();
+ if (core != null)
+ {
+ _corePosition = new Vector2(core.transform.position.x, core.transform.position.z);
+ Debug.Log($"[MapGenerator] Found Core at {_corePosition}");
+ }
+ else
+ {
+ Debug.LogWarning("[MapGenerator] Core not found in scene!");
+ _corePosition = Vector2.zero;
+ }
+
+ Resource[] resources = FindObjectsOfType();
+ if (resources.Length > 0)
+ {
+ _initialResourcePosition = new Vector2(resources[0].transform.position.x, resources[0].transform.position.z);
+ Debug.Log($"[MapGenerator] Found initial Resource at {_initialResourcePosition}");
+ }
+ else
+ {
+ Debug.LogWarning("[MapGenerator] No Resource found in scene!");
+ _initialResourcePosition = Vector2.zero;
+ }
+
+ GameObject barracks = GameObject.Find("Worker Hall");
+ if (barracks != null)
+ {
+ _barracksPosition = new Vector2(barracks.transform.position.x, barracks.transform.position.z);
+ Debug.Log($"[MapGenerator] Found Worker Hall at {_barracksPosition}");
+ }
+ else
+ {
+ Debug.LogWarning("[MapGenerator] Worker Hall not found in scene!");
+ _barracksPosition = Vector2.zero;
+ }
+ }
+
+ private void GenerateMap()
+ {
+ if (groupUnderParent)
+ {
+ _objectsParent = new GameObject("Generated Map Objects").transform;
+ _objectsParent.SetParent(transform);
+
+ NetworkObject parentNetworkObj = _objectsParent.gameObject.GetComponent();
+ if (parentNetworkObj == null)
+ {
+ parentNetworkObj = _objectsParent.gameObject.AddComponent();
+ }
+ parentNetworkObj.Spawn();
+ }
+
+ _spawnedPositions.Clear();
+
+ if (generateResourcesFirst)
+ {
+ GenerateResources();
+ GenerateObstacles();
+ }
+ else
+ {
+ GenerateObstacles();
+ GenerateResources();
+ }
+
+ Debug.Log($"[MapGenerator] Map generation complete!");
+ }
+
+ #region Resource Generation
+
+ private void GenerateResources()
+ {
+ if (resourcePrefab == null)
+ {
+ Debug.LogError("[MapGenerator] Resource prefab not assigned!");
+ return;
+ }
+
+ bool success = false;
+
+ for (int attempt = 0; attempt < maxResourceGenerationAttempts; attempt++)
+ {
+ if (TryGenerateResources(out var resources))
+ {
+ _generatedResources = resources;
+ success = true;
+ Debug.Log($"[MapGenerator] Successfully generated resources on attempt {attempt + 1}");
+ break;
+ }
+ else
+ {
+ Debug.LogWarning($"[MapGenerator] Resource generation attempt {attempt + 1} failed validation");
+ }
+ }
+
+ if (!success)
+ {
+ Debug.LogWarning("[MapGenerator] All resource generation attempts failed, using fallback layout");
+ GenerateResourceFallbackLayout();
+ }
+
+ SpawnResources();
+ }
+
+ private bool TryGenerateResources(out ResourceData[] resources)
+ {
+ resources = null;
+ int additionalResourceCount = Random.Range(minResourceCount, maxResourceCount + 1);
+ ResourceData[] tempResources = new ResourceData[additionalResourceCount];
+
+ for (int i = 0; i < additionalResourceCount; i++)
+ {
+ Vector2 position;
+ float qualityModifier;
+
+ if (!TryFindValidResourcePosition(tempResources, i, out position))
+ {
+ return false;
+ }
+
+ qualityModifier = Random.Range(minQualityModifier, maxQualityModifier);
+ float qualityMultiplier = 1f + (qualityModifier / 100f);
+ float finalProduction = additionalResourceBaseProduction * qualityMultiplier;
+
+ tempResources[i] = new ResourceData
+ {
+ position = position,
+ baseProduction = additionalResourceBaseProduction,
+ qualityModifier = qualityModifier,
+ finalProduction = finalProduction
+ };
+ }
+
+ if (!ValidateProductionRate(tempResources, out float globalMultiplier))
+ {
+ return false;
+ }
+
+ _globalProductionMultiplier = globalMultiplier;
+
+ for (int i = 0; i < tempResources.Length; i++)
+ {
+ tempResources[i].finalProduction *= _globalProductionMultiplier;
+ }
+
+ resources = tempResources;
+ return true;
+ }
+
+ private bool TryFindValidResourcePosition(ResourceData[] existingResources, int currentIndex, out Vector2 position)
+ {
+ position = Vector2.zero;
+ int maxAttempts = 100;
+
+ for (int attempt = 0; attempt < maxAttempts; attempt++)
+ {
+ float x = Random.Range(-playableAreaWidth / 2f, playableAreaWidth / 2f);
+ float y = Random.Range(startZ, endZ);
+ Vector2 candidatePosition = new Vector2(x, y);
+
+ if (IsValidResourcePosition(candidatePosition, existingResources, currentIndex))
+ {
+ position = candidatePosition;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private bool IsValidResourcePosition(Vector2 position, ResourceData[] existingResources, int currentIndex)
+ {
+ if (Vector2.Distance(position, _initialResourcePosition) < minDistanceBetweenResources)
+ {
+ return false;
+ }
+
+ if (Vector2.Distance(position, _corePosition) < minDistanceFromCore)
+ {
+ return false;
+ }
+
+ if (Vector2.Distance(position, _barracksPosition) < minDistanceFromBarracks)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < currentIndex; i++)
+ {
+ if (Vector2.Distance(position, existingResources[i].position) < minDistanceBetweenResources)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private bool ValidateProductionRate(ResourceData[] additionalResources, out float globalMultiplier)
+ {
+ globalMultiplier = 1f;
+ float totalProduction = initialResourceProduction;
+
+ for (int i = 0; i < additionalResources.Length; i++)
+ {
+ totalProduction += additionalResources[i].finalProduction;
+ }
+
+ float minTarget = targetTotalProduction * (1f - targetProductionTolerance);
+ float maxTarget = targetTotalProduction * (1f + targetProductionTolerance);
+
+ if (totalProduction >= minTarget && totalProduction <= maxTarget)
+ {
+ globalMultiplier = 1f;
+ return true;
+ }
+
+ globalMultiplier = targetTotalProduction / totalProduction;
+ float adjustedTotal = totalProduction * globalMultiplier;
+
+ if (adjustedTotal >= minTarget && adjustedTotal <= maxTarget)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void GenerateResourceFallbackLayout()
+ {
+ _generatedResources = new ResourceData[]
+ {
+ new ResourceData { position = new Vector2(30, 100), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(50, 200), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(20, 300), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(60, 400), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(35, 500), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(55, 600), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(25, 700), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(45, 150), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction },
+ new ResourceData { position = new Vector2(65, 250), baseProduction = additionalResourceBaseProduction, qualityModifier = 0f, finalProduction = additionalResourceBaseProduction }
+ };
+
+ float totalProduction = initialResourceProduction;
+ for (int i = 0; i < _generatedResources.Length; i++)
+ {
+ totalProduction += _generatedResources[i].finalProduction;
+ }
+
+ _globalProductionMultiplier = targetTotalProduction / totalProduction;
+ for (int i = 0; i < _generatedResources.Length; i++)
+ {
+ _generatedResources[i].finalProduction *= _globalProductionMultiplier;
+ }
+
+ Debug.Log($"[MapGenerator] Resource fallback layout generated. Global multiplier: {_globalProductionMultiplier:F2}");
+ }
+
+ private void SpawnResources()
+ {
+ float totalProduction = initialResourceProduction;
+
+ for (int i = 0; i < _generatedResources.Length; i++)
+ {
+ GameObject resourceObj = Instantiate(resourcePrefab, new Vector3(_generatedResources[i].position.x, 1f, _generatedResources[i].position.y), Quaternion.identity);
+
+ Resource resource = resourceObj.GetComponent();
+ if (resource == null)
+ {
+ Debug.LogError($"[MapGenerator] Resource prefab at index {i} doesn't have Resource component!");
+ Destroy(resourceObj);
+ continue;
+ }
+
+ resource.InitializeQuality(_generatedResources[i].qualityModifier);
+ Debug.Log($"[MapGenerator] Spawned resource at {_generatedResources[i].position} with quality: {_generatedResources[i].qualityModifier:F1}% (Actual Max: {resource.ActualMaxResources}, Actual Recharge: {resource.ActualRechargeAmount})");
+
+ NetworkObject networkObj = resourceObj.GetComponent();
+ if (networkObj != null)
+ {
+ networkObj.Spawn();
+ if (groupUnderParent && _objectsParent != null)
+ {
+ resourceObj.transform.SetParent(_objectsParent);
+ }
+ }
+ else
+ {
+ Debug.LogError($"[MapGenerator] Resource prefab at index {i} doesn't have NetworkObject component!");
+ Destroy(resourceObj);
+ }
+
+ _spawnedPositions.Add(new Vector3(_generatedResources[i].position.x, 1f, _generatedResources[i].position.y));
+ totalProduction += _generatedResources[i].finalProduction;
+ }
+
+ Debug.Log($"[MapGenerator] Spawned {_generatedResources.Length} additional resources (plus initial at {_initialResourcePosition}). Total production: {totalProduction:F2} mana/min. Global multiplier: {_globalProductionMultiplier:F2}");
+ }
+
+ #endregion
+
+ #region Obstacle Generation
+
+ private void GenerateObstacles()
+ {
+ if (obstacles.Count == 0)
+ {
+ Debug.Log("[MapGenerator] No obstacles configured, skipping obstacle generation.");
+ return;
+ }
+
+ int totalSpawned = 0;
+ int targetCount = Mathf.RoundToInt(maxTotalObstacles * obstacleDensity);
+
+ Debug.Log($"[MapGenerator] Starting obstacle generation. Target: {targetCount}, Density: {obstacleDensity}");
+
+ foreach (var obstacle in obstacles)
+ {
+ if (obstacle.prefab == null)
+ {
+ Debug.LogWarning($"[MapGenerator] Obstacle prefab is null!");
+ continue;
+ }
+
+ int minRequired = obstacle.minCount;
+ for (int i = 0; i < minRequired && totalSpawned < maxTotalObstacles; i++)
+ {
+ if (TrySpawnObstacle(obstacle))
+ {
+ totalSpawned++;
+ Debug.Log($"[MapGenerator] Spawned min required obstacle: {obstacle.prefab.name}");
+ }
+ }
+ }
+
+ int consecutiveFailures = 0;
+ int maxConsecutiveFailures = 50;
+
+ while (totalSpawned < targetCount && consecutiveFailures < maxConsecutiveFailures)
+ {
+ ObstacleEntry selectedObstacle = SelectRandomObstacle();
+ if (selectedObstacle == null || selectedObstacle.prefab == null)
+ {
+ consecutiveFailures++;
+ continue;
+ }
+
+ int currentCount = CountObstacleType(selectedObstacle.prefab);
+ if (currentCount >= selectedObstacle.maxCount)
+ {
+ consecutiveFailures++;
+ if (AllObstaclesAtMax())
+ {
+ break;
+ }
+ continue;
+ }
+
+ if (TrySpawnObstacle(selectedObstacle))
+ {
+ totalSpawned++;
+ consecutiveFailures = 0;
+ }
+ else
+ {
+ consecutiveFailures++;
+ }
+ }
+
+ Debug.Log($"[MapGenerator] Spawned {totalSpawned} obstacles (target: {targetCount}). Consecutive failures: {consecutiveFailures}");
+ }
+
+ private bool TrySpawnObstacle(ObstacleEntry obstacleEntry)
+ {
+ for (int attempt = 0; attempt < maxObstacleSpawnAttempts; attempt++)
+ {
+ Vector3 randomPos = GetRandomPositionInPlayableArea();
+
+ if (!IsValidObstaclePosition(randomPos))
+ {
+ continue;
+ }
+
+ if (checkCollision && Physics.CheckSphere(randomPos, collisionCheckRadius, collisionLayers))
+ {
+ continue;
+ }
+
+ if (alignToTerrain)
+ {
+ if (Physics.Raycast(randomPos + Vector3.up * 100f, Vector3.down, out RaycastHit hit, 200f))
+ {
+ randomPos = hit.point;
+ }
+ }
+
+ randomPos.y = 1f;
+
+ Quaternion rotation = randomRotation
+ ? Quaternion.Euler(0, Random.Range(0f, 360f), 0)
+ : Quaternion.identity;
+
+ GameObject obstacle = Instantiate(obstacleEntry.prefab, randomPos, rotation);
+
+ if (scaleVariation > 0)
+ {
+ float scale = 1f + Random.Range(-scaleVariation, scaleVariation);
+ obstacle.transform.localScale *= scale;
+ }
+
+ NetworkObject networkObj = obstacle.GetComponent();
+ if (networkObj == null)
+ {
+ networkObj = obstacle.AddComponent();
+ }
+
+ networkObj.Spawn();
+
+ if (groupUnderParent && _objectsParent != null)
+ {
+ obstacle.transform.SetParent(_objectsParent);
+ }
+
+ if (obstacle.GetComponent() == null)
+ {
+ var visibility = obstacle.AddComponent();
+ visibility.showInExploredAreas = false;
+ visibility.updateInterval = 0.2f;
+ }
+
+ _spawnedPositions.Add(randomPos);
+ return true;
+ }
+
+ return false;
+ }
+
+ private Vector3 GetRandomPositionInPlayableArea()
+ {
+ Vector3 center = transform.position;
+ float x = Random.Range(-playableAreaWidth / 2f, playableAreaWidth / 2f);
+ float z = Random.Range(startZ, endZ);
+
+ return new Vector3(x, center.y, z);
+ }
+
+ private bool IsValidObstaclePosition(Vector3 position)
+ {
+ foreach (var spawnedPos in _spawnedPositions)
+ {
+ if (Vector3.Distance(position, spawnedPos) < minDistanceBetweenObstacles)
+ {
+ return false;
+ }
+ }
+
+ if (Vector2.Distance(new Vector2(position.x, position.z), _corePosition) < minDistanceFromCore)
+ {
+ return false;
+ }
+
+ if (Vector2.Distance(new Vector2(position.x, position.z), _barracksPosition) < minDistanceFromBarracks)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private ObstacleEntry SelectRandomObstacle()
+ {
+ if (obstacles.Count == 0) return null;
+
+ int totalWeight = 0;
+ foreach (var obstacle in obstacles)
+ {
+ if (obstacle.prefab != null)
+ {
+ totalWeight += obstacle.spawnWeight;
+ }
+ }
+
+ if (totalWeight == 0) return null;
+
+ int randomValue = Random.Range(0, totalWeight);
+ int currentWeight = 0;
+
+ foreach (var obstacle in obstacles)
+ {
+ if (obstacle.prefab == null) continue;
+
+ currentWeight += obstacle.spawnWeight;
+ if (randomValue < currentWeight)
+ {
+ return obstacle;
+ }
+ }
+
+ return obstacles[0];
+ }
+
+ private bool AllObstaclesAtMax()
+ {
+ foreach (var obstacle in obstacles)
+ {
+ if (obstacle.prefab == null) continue;
+
+ int currentCount = CountObstacleType(obstacle.prefab);
+ if (currentCount < obstacle.maxCount)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private int CountObstacleType(GameObject prefab)
+ {
+ int count = 0;
+ if (_objectsParent != null)
+ {
+ foreach (Transform child in _objectsParent)
+ {
+ if (child.name.StartsWith(prefab.name))
+ {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public float GetTotalProduction()
+ {
+ if (_generatedResources == null)
+ return initialResourceProduction;
+
+ float total = initialResourceProduction;
+ for (int i = 0; i < _generatedResources.Length; i++)
+ {
+ total += _generatedResources[i].finalProduction;
+ }
+ return total;
+ }
+
+ public void ClearGeneratedObjects()
+ {
+ if (_objectsParent != null)
+ {
+ NetworkObject parentNetworkObj = _objectsParent.GetComponent();
+ if (parentNetworkObj != null && parentNetworkObj.IsSpawned)
+ {
+ parentNetworkObj.Despawn(true);
+ }
+
+ foreach (Transform child in _objectsParent)
+ {
+ NetworkObject networkObj = child.GetComponent();
+ if (networkObj != null && networkObj.IsSpawned)
+ {
+ networkObj.Despawn(true);
+ }
+ }
+
+ if (Application.isPlaying)
+ {
+ Destroy(_objectsParent.gameObject);
+ }
+ else
+ {
+ DestroyImmediate(_objectsParent.gameObject);
+ }
+ _objectsParent = null;
+ }
+
+ _spawnedPositions.Clear();
+ }
+
+ public void RegenerateMap()
+ {
+ ClearGeneratedObjects();
+ GenerateMap();
+ }
+
+ #endregion
+
+ #region Editor
+
+ private void OnDrawGizmos()
+ {
+ Vector3 center = transform.position;
+ center.x = 0f;
+ center.z = (startZ + endZ) / 2f;
+ float height = endZ - startZ;
+
+ Gizmos.color = new Color(0, 1, 0, 0.3f);
+ Gizmos.DrawCube(center, new Vector3(playableAreaWidth, 0.1f, height));
+
+ Gizmos.color = Color.green;
+ Gizmos.DrawWireCube(center, new Vector3(playableAreaWidth, 0.1f, height));
+
+ Gizmos.color = Color.cyan;
+ Gizmos.DrawWireSphere(new Vector3(_corePosition.x, 0, _corePosition.y), minDistanceFromCore);
+ Gizmos.color = Color.magenta;
+ Gizmos.DrawWireSphere(new Vector3(_barracksPosition.x, 0, _barracksPosition.y), minDistanceFromBarracks);
+ }
+
+ private void OnDrawGizmosSelected()
+ {
+ #if UNITY_EDITOR
+ Gizmos.color = Color.yellow;
+ foreach (var pos in _spawnedPositions)
+ {
+ Gizmos.DrawWireSphere(pos, minDistanceBetweenObstacles / 2f);
+ }
+
+ if (_generatedResources != null)
+ {
+ Gizmos.color = Color.blue;
+ foreach (var resource in _generatedResources)
+ {
+ Gizmos.DrawWireSphere(new Vector3(resource.position.x, 0, resource.position.y), 5f);
+ }
+ }
+
+ if (resourcePrefab != null)
+ {
+ Gizmos.color = Color.blue;
+ Gizmos.DrawWireSphere(new Vector3(_initialResourcePosition.x, 0, _initialResourcePosition.y), 5f);
+ }
+ #endif
+ }
+
+ #endregion
+ }
+
+ public struct ResourceData
+ {
+ public Vector2 position;
+ public float baseProduction;
+ public float qualityModifier;
+ public float finalProduction;
+ }
+}
diff --git a/Assets/Scripts/MapGenerator.cs.meta b/Assets/Scripts/MapGenerator.cs.meta
new file mode 100644
index 0000000..6008966
--- /dev/null
+++ b/Assets/Scripts/MapGenerator.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f0dde802bf94bf6448eb7d4838d1c42a
\ No newline at end of file
diff --git a/Assets/Scripts/Resource.cs b/Assets/Scripts/Resource.cs
index 83ccfe3..390e9e3 100644
--- a/Assets/Scripts/Resource.cs
+++ b/Assets/Scripts/Resource.cs
@@ -19,6 +19,24 @@ namespace Northbound
public float rechargeInterval = 5f; // 충전 주기 (초)
public int rechargeAmount = 10; // 주기당 충전량
+ [Header("Quality (Runtime)")]
+ [SerializeField] private NetworkVariable _qualityPercentage = new NetworkVariable(
+ 0f,
+ NetworkVariableReadPermission.Everyone,
+ NetworkVariableWritePermission.Server
+ );
+
+ [Tooltip("품질 보정율 (-30% ~ +30%)")]
+ [SerializeField] private float _displayQuality = 0f;
+
+ [Tooltip("품질 적용 후 최대 자원량")]
+ [SerializeField] private int _displayMaxResources = 100;
+
+ [Tooltip("품질 적용 후 충전량")]
+ [SerializeField] private int _displayRechargeAmount = 10;
+
+ private bool _isQualityInitialized = false;
+
[Header("Animation")]
public string interactionAnimationTrigger = "Mining"; // 플레이어 애니메이션 트리거
@@ -107,13 +125,83 @@ namespace Northbound
private float _lastGatheringTime;
private float _lastRechargeTime;
+ public float QualityPercentage => _qualityPercentage.Value;
+
+ public int ActualMaxResources
+ {
+ get
+ {
+ float multiplier = 1f + (_qualityPercentage.Value / 100f);
+ return Mathf.RoundToInt(maxResources * multiplier);
+ }
+ }
+
+ public int ActualRechargeAmount
+ {
+ get
+ {
+ float multiplier = 1f + (_qualityPercentage.Value / 100f);
+ return Mathf.RoundToInt(rechargeAmount * multiplier);
+ }
+ }
+
public override void OnNetworkSpawn()
+ {
+ _qualityPercentage.OnValueChanged += OnQualityChanged;
+
+ if (IsServer)
+ {
+ if (!_isQualityInitialized)
+ {
+ _qualityPercentage.Value = Random.Range(-30f, 30f);
+ }
+
+ _currentResources.Value = ActualMaxResources;
+ _lastRechargeTime = Time.time;
+ _lastGatheringTime = Time.time - gatheringCooldown;
+ }
+
+ _displayQuality = _qualityPercentage.Value;
+ UpdateDisplayValues();
+ }
+
+ public void InitializeQuality(float qualityPercentage)
{
if (IsServer)
{
- _currentResources.Value = maxResources;
- _lastRechargeTime = Time.time;
- _lastGatheringTime = Time.time - gatheringCooldown;
+ _qualityPercentage.Value = qualityPercentage;
+ _displayQuality = qualityPercentage;
+ _isQualityInitialized = true;
+ }
+ else if (IsClient)
+ {
+ _displayQuality = qualityPercentage;
+ UpdateDisplayValues();
+ }
+ }
+
+ public override void OnNetworkDespawn()
+ {
+ _qualityPercentage.OnValueChanged -= OnQualityChanged;
+ }
+
+ private void OnQualityChanged(float previous, float current)
+ {
+ _displayQuality = current;
+ UpdateDisplayValues();
+ }
+
+ private void UpdateDisplayValues()
+ {
+ if (IsClient || IsServer)
+ {
+ _displayMaxResources = ActualMaxResources;
+ _displayRechargeAmount = ActualRechargeAmount;
+ }
+ else
+ {
+ _displayMaxResources = maxResources;
+ _displayRechargeAmount = rechargeAmount;
}
}
@@ -125,12 +213,12 @@ namespace Northbound
// 자원 충전 로직
if (Time.time - _lastRechargeTime >= rechargeInterval)
{
- if (_currentResources.Value < maxResources)
+ if (_currentResources.Value < ActualMaxResources)
{
- int rechargeAmountToAdd = Mathf.Min(rechargeAmount, maxResources - _currentResources.Value);
+ int rechargeAmountToAdd = Mathf.Min(ActualRechargeAmount, ActualMaxResources - _currentResources.Value);
_currentResources.Value += rechargeAmountToAdd;
- // Debug.Log($"{resourceName} {rechargeAmountToAdd} 충전됨. 현재: {_currentResources.Value}/{maxResources}");
+ // Debug.Log($"{resourceName} {rechargeAmountToAdd} 충전됨. 현재: {_currentResources.Value}/{ActualMaxResources}");
}
_lastRechargeTime = Time.time;
@@ -266,7 +354,7 @@ namespace Northbound
if (_currentResources.Value <= 0)
return "자원 충전 중...";
- return $"[E] {resourceName} 채집 ({_currentResources.Value}/{maxResources})";
+ return $"[E] {resourceName} 채집 ({_currentResources.Value}/{ActualMaxResources})";
}
public string GetInteractionAnimation()