From cc475bce3efa888f626ff00ef2d2bb5b5af94572 Mon Sep 17 00:00:00 2001 From: dal4segno Date: Mon, 23 Feb 2026 00:21:44 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9E=85=EB=A0=A5=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 캐릭터 스탯을 PlayerStats 컴포넌트에서 모아서 관리하도록 변경 코드에서도 마찬가지 --- Assembly-CSharp-Editor.csproj | 1 + Assembly-CSharp.csproj | 3 + Assets/Data/ScriptableObjects/Upgrade.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade1.asset | 27 ++ .../Upgrade/Upgrade1.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade10.asset | 27 ++ .../Upgrade/Upgrade10.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade11.asset | 27 ++ .../Upgrade/Upgrade11.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade12.asset | 27 ++ .../Upgrade/Upgrade12.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade13.asset | 27 ++ .../Upgrade/Upgrade13.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade14.asset | 27 ++ .../Upgrade/Upgrade14.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade15.asset | 27 ++ .../Upgrade/Upgrade15.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade2.asset | 27 ++ .../Upgrade/Upgrade2.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade3.asset | 27 ++ .../Upgrade/Upgrade3.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade4.asset | 27 ++ .../Upgrade/Upgrade4.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade5.asset | 27 ++ .../Upgrade/Upgrade5.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade6.asset | 27 ++ .../Upgrade/Upgrade6.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade7.asset | 27 ++ .../Upgrade/Upgrade7.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade8.asset | 27 ++ .../Upgrade/Upgrade8.asset.meta | 8 + .../ScriptableObjects/Upgrade/Upgrade9.asset | 27 ++ .../Upgrade/Upgrade9.asset.meta | 8 + Assets/Prefabs/Player/Player.prefab | 41 ++- Assets/Scenes/GameMain.unity | 46 +++ Assets/ScriptableObjects/Upgrade.meta | 8 + Assets/Scripts/AttackAction.cs | 17 +- Assets/Scripts/Editor/CSVToSOImporter.cs | 68 ++++- Assets/Scripts/Editor/PlayerPrefabSetup.cs | 58 ++-- Assets/Scripts/Editor/UpgradePrefabSetup.cs | 23 ++ .../Scripts/Editor/UpgradePrefabSetup.cs.meta | 2 + Assets/Scripts/NetworkPlayerController.cs | 25 +- Assets/Scripts/PlayerInteraction.cs | 7 +- Assets/Scripts/PlayerResourceInventory.cs | 10 +- Assets/Scripts/PlayerStats.cs | 144 ++++++++++ Assets/Scripts/PlayerStats.cs.meta | 2 + Assets/Scripts/PlayerUpgradeManager.cs | 269 ++++++++++++++++++ Assets/Scripts/PlayerUpgradeManager.cs.meta | 2 + Assets/Scripts/PlayerVisionProvider.cs | 10 +- Assets/Scripts/Resource.cs | 32 ++- Assets/Scripts/UpgradeDatabase.cs | 177 ++++++++++++ Assets/Scripts/UpgradeDatabase.cs.meta | 2 + GameData/Monster.csv | 4 +- GameData/Tower.csv | 16 +- 54 files changed, 1402 insertions(+), 98 deletions(-) create mode 100644 Assets/Data/ScriptableObjects/Upgrade.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset.meta create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset create mode 100644 Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset.meta create mode 100644 Assets/ScriptableObjects/Upgrade.meta create mode 100644 Assets/Scripts/Editor/UpgradePrefabSetup.cs create mode 100644 Assets/Scripts/Editor/UpgradePrefabSetup.cs.meta create mode 100644 Assets/Scripts/PlayerStats.cs create mode 100644 Assets/Scripts/PlayerStats.cs.meta create mode 100644 Assets/Scripts/PlayerUpgradeManager.cs create mode 100644 Assets/Scripts/PlayerUpgradeManager.cs.meta create mode 100644 Assets/Scripts/UpgradeDatabase.cs create mode 100644 Assets/Scripts/UpgradeDatabase.cs.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 6147ddb..86eedbf 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -70,6 +70,7 @@ + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 92d00f3..35fea36 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -79,9 +79,11 @@ + + @@ -125,6 +127,7 @@ + diff --git a/Assets/Data/ScriptableObjects/Upgrade.meta b/Assets/Data/ScriptableObjects/Upgrade.meta new file mode 100644 index 0000000..f605a03 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc09279707549e041ae0219468b0a4a2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset new file mode 100644 index 0000000..c011f19 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade1 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 1 + memo: "\uCCB4\uB825 \uC99D\uAC00 Lv.1" + upgradeCategory: combat + upgradeTarget: person + mana: 200 + requireUpgradeId: + effectStatList: + - player_max_hp + effectOpList: + - add + effectValueList: + - 50 + sortOrder: 1 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset.meta new file mode 100644 index 0000000..657be42 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9e46f00da341b24ab07b314c89b7fd9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset new file mode 100644 index 0000000..3b8bc18 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade10 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 10 + memo: "\uB178\uB3D9\uB825 \uC99D\uAC00 Lv.1" + upgradeCategory: harvest + upgradeTarget: person + mana: 200 + requireUpgradeId: + effectStatList: + - player_manpower + effectOpList: + - add + effectValueList: + - 5 + sortOrder: 10 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset.meta new file mode 100644 index 0000000..04eaf3a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade10.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c665e2cbdd230c04fb6d3e9fac091a65 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset new file mode 100644 index 0000000..b4ad9e7 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade11 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 11 + memo: "\uB178\uB3D9\uB825 \uC99D\uAC00 Lv.2" + upgradeCategory: harvest + upgradeTarget: person + mana: 300 + requireUpgradeId: 0a000000 + effectStatList: + - player_manpower + effectOpList: + - add + effectValueList: + - 10 + sortOrder: 11 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset.meta new file mode 100644 index 0000000..2265349 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade11.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5ad1c8a4ecf84a43b7c609c58592295 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset new file mode 100644 index 0000000..f395916 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade12 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 12 + memo: "\uB178\uB3D9\uB825 \uC99D\uAC00 Lv.3" + upgradeCategory: harvest + upgradeTarget: person + mana: 400 + requireUpgradeId: 070000000a000000 + effectStatList: + - player_manpower + effectOpList: + - add + effectValueList: + - 20 + sortOrder: 12 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset.meta new file mode 100644 index 0000000..727620e --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade12.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 555ef1e6ff58ee442953d075e417c091 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset new file mode 100644 index 0000000..55adf2c --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade13 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 13 + memo: "\uC774\uB3D9\uC18D\uB3C4 \uC99D\uAC00 Lv.1" + upgradeCategory: scout + upgradeTarget: person + mana: 200 + requireUpgradeId: + effectStatList: + - player_move_speed + effectOpList: + - mul + effectValueList: + - 1.1 + sortOrder: 13 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset.meta new file mode 100644 index 0000000..55e0134 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade13.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa2a6eecb804c3948a4fa7e75bacfca6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset new file mode 100644 index 0000000..82869a7 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade14 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 14 + memo: "\uC774\uB3D9\uC18D\uB3C4 \uC99D\uAC00 Lv.2" + upgradeCategory: scout + upgradeTarget: person + mana: 300 + requireUpgradeId: 0d000000 + effectStatList: + - player_move_speed + effectOpList: + - mul + effectValueList: + - 1.2 + sortOrder: 14 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset.meta new file mode 100644 index 0000000..afedec6 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade14.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3216444533dfdc14891741f0b1c5a30a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset new file mode 100644 index 0000000..c8cd64a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade15 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 15 + memo: "\uC774\uB3D9\uC18D\uB3C4 \uC99D\uAC00 Lv.3" + upgradeCategory: scout + upgradeTarget: person + mana: 400 + requireUpgradeId: 0e000000 + effectStatList: + - player_move_speed + effectOpList: + - mul + effectValueList: + - 1.3 + sortOrder: 15 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset.meta new file mode 100644 index 0000000..643d61e --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade15.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 227e825691ca7c9498e4af4cbb592faa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset new file mode 100644 index 0000000..588194a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade2 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 2 + memo: "\uCCB4\uB825 \uC99D\uAC00 Lv.2" + upgradeCategory: combat + upgradeTarget: person + mana: 300 + requireUpgradeId: 01000000 + effectStatList: + - player_max_hp + effectOpList: + - add + effectValueList: + - 100 + sortOrder: 2 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset.meta new file mode 100644 index 0000000..9eaa181 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade2.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d989011e0aeec9a4b9ed3d9e49488c8a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset new file mode 100644 index 0000000..05c2369 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade3 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 3 + memo: "\uCCB4\uB825 \uC99D\uAC00 Lv.3" + upgradeCategory: combat + upgradeTarget: person + mana: 400 + requireUpgradeId: 0200000005000000 + effectStatList: + - player_max_hp + effectOpList: + - add + effectValueList: + - 150 + sortOrder: 3 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset.meta new file mode 100644 index 0000000..15ca44b --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade3.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29b2206b90bc89c4183c6fb0a1bb699e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset new file mode 100644 index 0000000..cba912e --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade4 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 4 + memo: "\uACF5\uACA9\uB825 \uC99D\uAC00 Lv.1" + upgradeCategory: combat + upgradeTarget: person + mana: 200 + requireUpgradeId: + effectStatList: + - player_atk_damage + effectOpList: + - add + effectValueList: + - 5 + sortOrder: 4 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset.meta new file mode 100644 index 0000000..109b960 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade4.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c370fa5d360b034b977fa923d14f60b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset new file mode 100644 index 0000000..724c4a8 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade5 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 5 + memo: "\uACF5\uACA9\uB825 \uC99D\uAC00 Lv.2" + upgradeCategory: combat + upgradeTarget: person + mana: 300 + requireUpgradeId: 04000000 + effectStatList: + - player_atk_damage + effectOpList: + - add + effectValueList: + - 10 + sortOrder: 5 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset.meta new file mode 100644 index 0000000..311fd20 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade5.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49e9bbb379a103741bca937c322db0cb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset new file mode 100644 index 0000000..d4c158b --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade6 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 6 + memo: "\uACF5\uACA9\uB825 \uC99D\uAC00 Lv.3" + upgradeCategory: combat + upgradeTarget: person + mana: 400 + requireUpgradeId: 0200000005000000 + effectStatList: + - player_atk_damage + effectOpList: + - add + effectValueList: + - 15 + sortOrder: 6 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset.meta new file mode 100644 index 0000000..09e038a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade6.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6178f649bd6ad141888fb39c653bda9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset new file mode 100644 index 0000000..906e07a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade7 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 7 + memo: "\uC790\uC6D0 \uCD5C\uB300 \uC6A9\uB7C9 \uC99D\uAC00 Lv.1" + upgradeCategory: harvest + upgradeTarget: person + mana: 200 + requireUpgradeId: + effectStatList: + - player_capacity + effectOpList: + - add + effectValueList: + - 20 + sortOrder: 7 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset.meta new file mode 100644 index 0000000..b206815 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade7.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36cdb899e627bd54092fa9e4458ff6d2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset new file mode 100644 index 0000000..95284dd --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade8 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 8 + memo: "\uC790\uC6D0 \uCD5C\uB300 \uC6A9\uB7C9 \uC99D\uAC00 Lv.2" + upgradeCategory: harvest + upgradeTarget: person + mana: 300 + requireUpgradeId: 07000000 + effectStatList: + - player_capacity + effectOpList: + - add + effectValueList: + - 50 + sortOrder: 8 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset.meta new file mode 100644 index 0000000..e7d2d52 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade8.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e8418449515bb142b06d88d7a0ac4e1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset b/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset new file mode 100644 index 0000000..6062d88 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f134815569ad014e9ccc81ddc443c4c, type: 3} + m_Name: Upgrade9 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.UpgradeData + id: 9 + memo: "\uC790\uC6D0 \uCD5C\uB300 \uC6A9\uB7C9 \uC99D\uAC00 Lv.3" + upgradeCategory: harvest + upgradeTarget: person + mana: 400 + requireUpgradeId: 070000000a000000 + effectStatList: + - player_capacity + effectOpList: + - add + effectValueList: + - 100 + sortOrder: 9 diff --git a/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset.meta b/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset.meta new file mode 100644 index 0000000..36fb99c --- /dev/null +++ b/Assets/Data/ScriptableObjects/Upgrade/Upgrade9.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eca8a6e3f11a84f44aa061493293e791 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Player/Player.prefab b/Assets/Prefabs/Player/Player.prefab index c66c8b6..2a78b4a 100644 --- a/Assets/Prefabs/Player/Player.prefab +++ b/Assets/Prefabs/Player/Player.prefab @@ -23,6 +23,8 @@ GameObject: - component: {fileID: -4348726977448206869} - component: {fileID: 7148704114816793672} - component: {fileID: 6581787771557727003} + - component: {fileID: 8704851935123448388} + - component: {fileID: 2146720647481692606} m_Layer: 9 m_Name: Player m_TagString: Untagged @@ -85,10 +87,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::NetworkPlayerController ShowTopMostFoldoutHeaderGroup: 1 - moveSpeed: 5 rotationSpeed: 10 initialTeam: 1 - maxHealth: 100 damageEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0} resourcePickupPrefab: {fileID: 1627676033990080135, guid: 8c45964a69bf8fa4ba461ed217bc052f, type: 3} @@ -158,7 +158,6 @@ MonoBehaviour: interactableLayer: serializedVersion: 2 m_Bits: 128 - workPower: 1 rayOrigin: {fileID: 0} useForwardDirection: 1 playAnimations: 1 @@ -196,8 +195,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::Northbound.AttackAction ShowTopMostFoldoutHeaderGroup: 1 - attackRange: 3 - attackDamage: 100 attackCooldown: 1 attackableLayer: serializedVersion: 2 @@ -249,7 +246,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::Northbound.PlayerResourceInventory ShowTopMostFoldoutHeaderGroup: 1 - maxResourceCapacity: 50 --- !u!114 &2148255267416253297 MonoBehaviour: m_ObjectHideFlags: 0 @@ -263,7 +259,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::Northbound.PlayerVisionProvider ShowTopMostFoldoutHeaderGroup: 1 - visionRange: 10 --- !u!95 &1698609800605343773 Animator: serializedVersion: 7 @@ -393,6 +388,38 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::Northbound.InteractableModalManager interactableModal: {fileID: 7317980967521758771} playerInteraction: {fileID: 8729870597719024730} +--- !u!114 &8704851935123448388 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1314983689436087486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c2399ad44b71131439123eaec84abb08, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.PlayerUpgradeManager + ShowTopMostFoldoutHeaderGroup: 1 +--- !u!114 &2146720647481692606 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1314983689436087486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6aa26fe48ebdaae438d465df7c6a3bef, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.PlayerStats + baseMaxHp: 100 + baseDamage: 10 + baseCapacity: 100 + baseManpower: 10 + baseMoveSpeed: 5 + baseSight: 10 + baseAttackRange: 2 --- !u!1 &1862223349553492570 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/GameMain.unity b/Assets/Scenes/GameMain.unity index fd06c4d..a8d30b3 100644 --- a/Assets/Scenes/GameMain.unity +++ b/Assets/Scenes/GameMain.unity @@ -920,6 +920,7 @@ Transform: - {fileID: 946527919} - {fileID: 1701756768} - {fileID: 1166878644} + - {fileID: 1247940084} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &672563220 @@ -2024,6 +2025,51 @@ Transform: m_Children: [] m_Father: {fileID: 640318137} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1247940083 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1247940084} + - component: {fileID: 1247940085} + m_Layer: 0 + m_Name: UpgradeDatabase + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1247940084 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1247940083} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 640318137} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1247940085 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1247940083} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 12780dc9ee390c742b6cbd405e59a916, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.UpgradeDatabase + _upgradeDataList: [] --- !u!224 &1282800775 stripped RectTransform: m_CorrespondingSourceObject: {fileID: 8873176760615364646, guid: a470599cc0481164ab487ecf39b1ebd0, type: 3} diff --git a/Assets/ScriptableObjects/Upgrade.meta b/Assets/ScriptableObjects/Upgrade.meta new file mode 100644 index 0000000..c0a073b --- /dev/null +++ b/Assets/ScriptableObjects/Upgrade.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba53e8dca24fd4346a54d32e8358a2bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/AttackAction.cs b/Assets/Scripts/AttackAction.cs index 6c8f5fd..db9ac1b 100644 --- a/Assets/Scripts/AttackAction.cs +++ b/Assets/Scripts/AttackAction.cs @@ -9,8 +9,6 @@ namespace Northbound public class AttackAction : NetworkBehaviour, IAction { [Header("Attack Settings")] - public float attackRange = 2f; - public int attackDamage = 10; public float attackCooldown = 0.5f; public LayerMask attackableLayer = ~0; @@ -33,12 +31,14 @@ namespace Northbound private EquipmentSocket _equipmentSocket; private bool _isAttacking = false; private bool _isWeaponEquipped = false; + private PlayerStats _playerStats; private void Awake() { _animator = GetComponent(); _teamMember = GetComponent(); _equipmentSocket = GetComponent(); + _playerStats = GetComponent(); } public bool CanExecute(ulong playerId) @@ -80,7 +80,7 @@ namespace Northbound private void PerformAttack() { Vector3 attackOrigin = attackPoint != null ? attackPoint.position : transform.position; - Collider[] hits = Physics.OverlapSphere(attackOrigin, attackRange, attackableLayer); + Collider[] hits = Physics.OverlapSphere(attackOrigin, GetAttackRange(), attackableLayer); foreach (Collider hit in hits) { @@ -115,7 +115,7 @@ namespace Northbound if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(targetNetworkId, out NetworkObject targetObj)) { var damageable = targetObj.GetComponent(); - damageable?.TakeDamage(attackDamage, attackerNetworkId); + damageable?.TakeDamage(_playerStats?.GetDamage() ?? 10, attackerNetworkId); } } @@ -248,7 +248,7 @@ namespace Northbound { Vector3 attackOrigin = attackPoint != null ? attackPoint.position : transform.position; Gizmos.color = Color.red; - Gizmos.DrawWireSphere(attackOrigin, attackRange); + Gizmos.DrawWireSphere(attackOrigin, GetAttackRange()); } public override void OnDestroy() @@ -263,5 +263,10 @@ namespace Northbound } public bool IsAttacking => _isAttacking; + + /// + /// 공격 범위 반환 (PlayerStats 우선) + /// + public float GetAttackRange() => _playerStats?.GetAttackRange() ?? 2f; } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Editor/CSVToSOImporter.cs b/Assets/Scripts/Editor/CSVToSOImporter.cs index e3b2e05..42de3c6 100644 --- a/Assets/Scripts/Editor/CSVToSOImporter.cs +++ b/Assets/Scripts/Editor/CSVToSOImporter.cs @@ -1,3 +1,4 @@ +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -45,12 +46,12 @@ namespace Northbound.Editor } Debug.Log($"[CSVToSOImporter] Import complete: {successCount} succeeded, {failCount} failed"); - + if (towerImported) { AutoConfigureBuildingManager(); } - + AssetDatabase.Refresh(); } @@ -61,7 +62,8 @@ namespace Northbound.Editor { "Monster", new MonsterPrefabSetup() }, { "Creep", new CreepPrefabSetup() }, { "Tower", new TowerPrefabSetup() }, - { "Player", new PlayerPrefabSetup() } + { "Player", new PlayerPrefabSetup() }, + { "Upgrade", new UpgradePrefabSetup() } }; } @@ -82,14 +84,19 @@ namespace Northbound.Editor } IPrefabSetup prefabSetup = prefabSetups[typeName]; - string templateName = prefabSetup.GetTemplateName(); - string templatePath = $"Assets/Data/Templates/{templateName}.prefab"; - GameObject template = AssetDatabase.LoadAssetAtPath(templatePath); - if (template == null) + // Upgrade는 템플릿이 필요 없음 + GameObject template = null; + if (typeName != "Upgrade") { - Debug.LogError($"[CSVToSOImporter] Template not found: {templatePath}"); - return false; + string templateName = prefabSetup.GetTemplateName(); + string templatePath = $"Assets/Data/Templates/{templateName}.prefab"; + template = AssetDatabase.LoadAssetAtPath(templatePath); + if (template == null) + { + Debug.LogError($"[CSVToSOImporter] Template not found: {templatePath}"); + return false; + } } string[] csvLines = File.ReadAllLines(csvPath); @@ -123,7 +130,6 @@ namespace Northbound.Editor Debug.Log($"[CSVToSOImporter] {typeName}: {successCount} prefabs created/updated"); } - // If towers were imported, auto-configure BuildingManager if (typeName == "Tower") { Debug.Log($"[CSVToSOImporter] Tower import complete!"); @@ -134,8 +140,19 @@ namespace Northbound.Editor private static bool CreatePrefabFromRow(string typeName, string[] headers, string[] values, GameObject template, IPrefabSetup prefabSetup) { - string soPath = $"Assets/Data/ScriptableObjects/{typeName}"; - Directory.CreateDirectory(Path.Combine(Application.dataPath, $"ScriptableObjects/{typeName}")); + string soPath; + if (typeName == "Upgrade") + { + // Upgrade는 Resources 폴더에 저장 (런타임 자동 로드용) + soPath = "Assets/Resources/Data/ScriptableObjects/Upgrade"; + Directory.CreateDirectory(Path.Combine(Application.dataPath, "Resources/Data/ScriptableObjects/Upgrade")); + } + else + { + soPath = $"Assets/Data/ScriptableObjects/{typeName}"; + Directory.CreateDirectory(Path.Combine(Application.dataPath, $"ScriptableObjects/{typeName}")); + } + int id = 0; for (int i = 0; i < headers.Length && i < values.Length; i++) @@ -188,6 +205,11 @@ namespace Northbound.Editor PlayerPrefabSetup.UpdatePlayerPrefab((PlayerData)data); prefabObj = null; } + else if (typeName == "Upgrade") + { + // Upgrade는 프리팹이 필요 없음 + prefabObj = null; + } else { string prefabPath = $"Assets/Prefabs/{typeName}/{typeName}{id}.prefab"; @@ -219,7 +241,6 @@ namespace Northbound.Editor EditorUtility.SetDirty(data); } - // Force save assets to disk AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); @@ -236,7 +257,6 @@ namespace Northbound.Editor return; } - // Load TowerData string[] towerDataGuids = AssetDatabase.FindAssets("t:TowerData", new[] { "Assets/Data/ScriptableObjects" }); List allTowers = new List(); @@ -302,6 +322,26 @@ namespace Northbound.Editor return type.IsValueType ? System.Activator.CreateInstance(type) : null; } + // List 타입 처리 (세미콜론 구분) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + { + System.Type elementType = type.GetGenericArguments()[0]; + var elements = value.Split(';').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList(); + + IList list = (IList)System.Activator.CreateInstance(type); + + foreach (string element in elements) + { + object elementValue = ParseValue(element, elementType); + if (elementValue != null) + { + list.Add(elementValue); + } + } + + return list; + } + if (type == typeof(int)) { int result; diff --git a/Assets/Scripts/Editor/PlayerPrefabSetup.cs b/Assets/Scripts/Editor/PlayerPrefabSetup.cs index d1965a6..65a6631 100644 --- a/Assets/Scripts/Editor/PlayerPrefabSetup.cs +++ b/Assets/Scripts/Editor/PlayerPrefabSetup.cs @@ -45,52 +45,38 @@ namespace Northbound.Editor private static void SetupPrefabComponents(GameObject prefab, PlayerData playerData) { - var networkController = prefab.GetComponent(); - if (networkController != null) + // PlayerStats에 모든 스탯 설정 + var playerStats = prefab.GetComponent(); + if (playerStats != null) { - SerializedObject so = new SerializedObject(networkController); - so.FindProperty("moveSpeed").floatValue = playerData.moveSpeed; - so.FindProperty("maxHealth").intValue = playerData.maxHp; + SerializedObject so = new SerializedObject(playerStats); + so.FindProperty("baseMaxHp").intValue = playerData.maxHp; + so.FindProperty("baseDamage").intValue = playerData.atkDamage; + so.FindProperty("baseCapacity").intValue = playerData.capacity; + so.FindProperty("baseManpower").floatValue = playerData.manpower; + so.FindProperty("baseMoveSpeed").floatValue = playerData.moveSpeed; + so.FindProperty("baseSight").floatValue = playerData.sight; + so.FindProperty("baseAttackRange").floatValue = playerData.atkRange; so.ApplyModifiedProperties(); - Debug.Log($"[PlayerPrefabSetup] Updated NetworkPlayerController: moveSpeed={playerData.moveSpeed}, maxHealth={playerData.maxHp}"); + Debug.Log($"[PlayerPrefabSetup] Updated PlayerStats: " + + $"maxHp={playerData.maxHp}, damage={playerData.atkDamage}, " + + $"capacity={playerData.capacity}, manpower={playerData.manpower}, " + + $"moveSpeed={playerData.moveSpeed}, sight={playerData.sight}, " + + $"attackRange={playerData.atkRange}"); + } + else + { + Debug.LogWarning($"[PlayerPrefabSetup] PlayerStats component not found on prefab!"); } + // AttackAction의 attackCooldown은 별도 설정 (스탯이 아님) var attackAction = prefab.GetComponent(); if (attackAction != null) { SerializedObject so = new SerializedObject(attackAction); - so.FindProperty("attackRange").intValue = playerData.atkRange; - so.FindProperty("attackDamage").intValue = playerData.atkDamage; so.FindProperty("attackCooldown").floatValue = playerData.atkIntervalSec; so.ApplyModifiedProperties(); - Debug.Log($"[PlayerPrefabSetup] Updated AttackAction: attackRange={playerData.atkRange}, attackDamage={playerData.atkDamage}, attackCooldown={playerData.atkIntervalSec}"); - } - - var visionProvider = prefab.GetComponent(); - if (visionProvider != null) - { - SerializedObject so = new SerializedObject(visionProvider); - so.FindProperty("visionRange").floatValue = playerData.sight; - so.ApplyModifiedProperties(); - Debug.Log($"[PlayerPrefabSetup] Updated PlayerVisionProvider: visionRange={playerData.sight}"); - } - - var resourceInventory = prefab.GetComponent(); - if (resourceInventory != null) - { - SerializedObject so = new SerializedObject(resourceInventory); - so.FindProperty("maxResourceCapacity").intValue = playerData.capacity; - so.ApplyModifiedProperties(); - Debug.Log($"[PlayerPrefabSetup] Updated PlayerResourceInventory: maxResourceCapacity={playerData.capacity}"); - } - - var playerInteraction = prefab.GetComponent(); - if (playerInteraction != null) - { - SerializedObject so = new SerializedObject(playerInteraction); - so.FindProperty("workPower").floatValue = playerData.manpower; - so.ApplyModifiedProperties(); - Debug.Log($"[PlayerPrefabSetup] Updated PlayerInteraction: workPower={playerData.manpower}"); + Debug.Log($"[PlayerPrefabSetup] Updated AttackAction: attackCooldown={playerData.atkIntervalSec}"); } EditorUtility.SetDirty(prefab); diff --git a/Assets/Scripts/Editor/UpgradePrefabSetup.cs b/Assets/Scripts/Editor/UpgradePrefabSetup.cs new file mode 100644 index 0000000..ee5f39e --- /dev/null +++ b/Assets/Scripts/Editor/UpgradePrefabSetup.cs @@ -0,0 +1,23 @@ +using Northbound.Data; +using UnityEditor; +using UnityEngine; + +namespace Northbound.Editor +{ + /// + /// Upgrade 타입은 프리팹이 필요 없으므로 빈 구현 + /// + public class UpgradePrefabSetup : IPrefabSetup + { + public string GetTemplateName() + { + return ""; // 템플릿 필요 없음 + } + + public void SetupPrefab(GameObject prefab, ScriptableObject data) + { + // Upgrade는 프리팹이 필요 없음 + Debug.LogWarning($"[UpgradePrefabSetup] Upgrade 타입은 프리팹이 필요하지 않습니다."); + } + } +} diff --git a/Assets/Scripts/Editor/UpgradePrefabSetup.cs.meta b/Assets/Scripts/Editor/UpgradePrefabSetup.cs.meta new file mode 100644 index 0000000..d6e05fe --- /dev/null +++ b/Assets/Scripts/Editor/UpgradePrefabSetup.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f33f085cffff92c489c74fc11a89fa49 \ No newline at end of file diff --git a/Assets/Scripts/NetworkPlayerController.cs b/Assets/Scripts/NetworkPlayerController.cs index 4413146..c68e4c6 100644 --- a/Assets/Scripts/NetworkPlayerController.cs +++ b/Assets/Scripts/NetworkPlayerController.cs @@ -9,15 +9,11 @@ using Northbound; public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageable { [Header("Movement Settings")] - public float moveSpeed = 5f; public float rotationSpeed = 10f; [Header("Team Settings")] [SerializeField] private TeamType initialTeam = TeamType.Player; - [Header("Health Settings")] - [SerializeField] private int maxHealth = 100; - [Header("Visual Effects")] [SerializeField] private GameObject damageEffectPrefab; [SerializeField] private GameObject deathEffectPrefab; @@ -50,8 +46,11 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl private PlayerInputActions _inputActions; private Animator _animator; private NetworkAnimator _networkAnimator; + private PlayerStats _playerStats; // 이 플레이어가 로컬 플레이어인지 확인 + + public bool IsLocalPlayer => _ownerPlayerId.Value == NetworkManager.Singleton.LocalClientId; public ulong OwnerPlayerId => _ownerPlayerId.Value; @@ -64,6 +63,7 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl _controller = GetComponent(); _animator = GetComponent(); _networkAnimator = GetComponent(); + _playerStats = GetComponent(); } public override void OnNetworkSpawn() @@ -80,7 +80,7 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl if (_currentHealth.Value == 0) { - _currentHealth.Value = maxHealth; + _currentHealth.Value = GetMaxHealth(); } } @@ -189,7 +189,7 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl if (_controller != null) { - _controller.Move(move * moveSpeed * Time.deltaTime); + _controller.Move(move * (_playerStats?.GetMoveSpeed() ?? 5f) * Time.deltaTime); } } } @@ -376,7 +376,7 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl if (!IsServer) return; // 체력 회복 - _currentHealth.Value = maxHealth; + _currentHealth.Value = GetMaxHealth(); // 스폰 포인트로 이동 var spawnPoints = FindObjectsByType(FindObjectsSortMode.None); @@ -423,11 +423,12 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl public int GetCurrentHealth() => _currentHealth.Value; - public int GetMaxHealth() => maxHealth; + public int GetMaxHealth() => _playerStats?.GetMaxHp() ?? 100; public float GetHealthPercentage() { - return maxHealth > 0 ? (float)_currentHealth.Value / maxHealth : 0f; + int max = GetMaxHealth(); + return max > 0 ? (float)_currentHealth.Value / max : 0f; } public bool IsDead() => _currentHealth.Value <= 0; @@ -436,7 +437,7 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl { if (!IsServer) return; - int healAmount = Mathf.Min(amount, maxHealth - _currentHealth.Value); + int healAmount = Mathf.Min(amount, GetMaxHealth() - _currentHealth.Value); _currentHealth.Value += healAmount; } @@ -459,13 +460,13 @@ public class NetworkPlayerController : NetworkBehaviour, ITeamMember, IDamageabl { string teamName = TeamManager.GetTeamName(_team.Value); UnityEditor.Handles.Label(transform.position + Vector3.up * 3f, - $"Player: {gameObject.name}\nTeam: {teamName}\nHP: {_currentHealth.Value}/{maxHealth}"); + $"Player: {gameObject.name}\nTeam: {teamName}\nHP: {_currentHealth.Value}/{GetMaxHealth()}"); } else { string teamName = TeamManager.GetTeamName(initialTeam); UnityEditor.Handles.Label(transform.position + Vector3.up * 3f, - $"Player: {gameObject.name}\nTeam: {teamName}\nHP: {maxHealth}/{maxHealth}"); + $"Player: {gameObject.name}\nTeam: {teamName}"); } #endif } diff --git a/Assets/Scripts/PlayerInteraction.cs b/Assets/Scripts/PlayerInteraction.cs index fcca994..d77a748 100644 --- a/Assets/Scripts/PlayerInteraction.cs +++ b/Assets/Scripts/PlayerInteraction.cs @@ -13,7 +13,7 @@ namespace Northbound [Header("Interaction Settings")] public float interactionRange = 3f; public LayerMask interactableLayer = ~0; - public float workPower = 10f; + [Header("Detection")] public Transform rayOrigin; @@ -47,9 +47,10 @@ namespace Northbound private Coroutine _interactionTimeoutCoroutine; private NetworkPlayerController _networkPlayerController; + private PlayerStats _playerStats; public bool IsInteracting => _isInteracting; - public float WorkPower => workPower; + public float WorkPower => _playerStats?.GetManpower() ?? 10f; public IInteractable CurrentUnavailableInteractable => _unavailableInteractable; // 로컬 플레이어인지 확인 @@ -60,6 +61,8 @@ namespace Northbound { _networkPlayerController = GetComponent(); _networkAnimator = GetComponent(); + _playerStats = GetComponent(); + } public override void OnNetworkSpawn() diff --git a/Assets/Scripts/PlayerResourceInventory.cs b/Assets/Scripts/PlayerResourceInventory.cs index bfef347..454fca6 100644 --- a/Assets/Scripts/PlayerResourceInventory.cs +++ b/Assets/Scripts/PlayerResourceInventory.cs @@ -5,13 +5,13 @@ namespace Northbound { public class PlayerResourceInventory : NetworkBehaviour { - public int maxResourceCapacity = 100; private int _displayAmount = 0; public int CurrentResourceAmount => _displayAmount; - public int MaxResourceCapacity => maxResourceCapacity; + public int MaxResourceCapacity => _playerStats?.GetCapacity() ?? 100; private NetworkPlayerController _networkPlayerController; + private PlayerStats _playerStats; private bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer; private ulong LocalPlayerId => _networkPlayerController != null ? _networkPlayerController.OwnerPlayerId : OwnerClientId; @@ -19,6 +19,7 @@ namespace Northbound private void Awake() { _networkPlayerController = GetComponent(); + _playerStats = GetComponent(); } [Rpc(SendTo.Server)] @@ -33,7 +34,6 @@ namespace Northbound public override void OnNetworkSpawn() { - // _ownerPlayerId 변경 이벤트 구독 if (_networkPlayerController != null) { _networkPlayerController.OnOwnerChanged += OnOwnerPlayerIdChanged; @@ -50,8 +50,8 @@ namespace Northbound private void TryInitialize() { if (!IsLocalPlayer) return; - - SetMaxCapacityServerRpc(maxResourceCapacity, LocalPlayerId); + + SetMaxCapacityServerRpc(MaxResourceCapacity, LocalPlayerId); RequestResourceUpdateServerRpc(LocalPlayerId); } diff --git a/Assets/Scripts/PlayerStats.cs b/Assets/Scripts/PlayerStats.cs new file mode 100644 index 0000000..9b4b358 --- /dev/null +++ b/Assets/Scripts/PlayerStats.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using UnityEngine; +using Northbound.Data; + +namespace Northbound +{ + /// + /// 플레이어 스탯 계산 컴포넌트 + /// 기본 스탯 + 업그레이드 보너스를 계산하여 반환 + /// + public class PlayerStats : MonoBehaviour + { + [Header("Base Stats")] + [SerializeField] private int baseMaxHp = 100; + [SerializeField] private int baseDamage = 10; + [SerializeField] private int baseCapacity = 100; + [SerializeField] private float baseManpower = 10f; + [SerializeField] private float baseMoveSpeed = 5f; + [SerializeField] private float baseSight = 10f; + [SerializeField] private float baseAttackRange = 2f; + + private PlayerUpgradeManager _upgradeManager; + + private void Awake() + { + _upgradeManager = GetComponent(); + } + + /// + /// 특정 스탯에 대한 업그레이드 보너스 계산 (ADD만 지원) + /// + private float CalculateStatBonus(string statName) + { + float bonus = 0f; + + if (_upgradeManager == null) + return bonus; + + var ownedUpgrades = _upgradeManager.GetOwnedUpgradeData(); + + foreach (var upgrade in ownedUpgrades) + { + if (upgrade == null) continue; + + // effectStatList에서 해당 스탯 찾기 + for (int i = 0; i < upgrade.effectStatList.Count; i++) + { + if (i >= upgrade.effectOpList.Count || i >= upgrade.effectValueList.Count) + continue; + + if (upgrade.effectStatList[i] == statName) + { + string op = upgrade.effectOpList[i]; + float value = upgrade.effectValueList[i]; + + // ADD 연산만 지원 + if (op == "add") + { + bonus += value; + } + } + } + } + + return bonus; + } + + /// + /// 최대 체력 반환 + /// + public int GetMaxHp() + { + float bonus = CalculateStatBonus("player_max_hp"); + return baseMaxHp + (int)bonus; + } + + /// + /// 공격력 반환 + /// + public int GetDamage() + { + float bonus = CalculateStatBonus("player_atk_damage"); + return baseDamage + (int)bonus; + } + + /// + /// 자원 용량 반환 + /// + public int GetCapacity() + { + float bonus = CalculateStatBonus("player_capacity"); + return baseCapacity + (int)bonus; + } + + /// + /// 노동력(건설/채굴 작업량) 반환 + /// + public float GetManpower() + { + float bonus = CalculateStatBonus("player_manpower"); + return baseManpower + bonus; + } + + /// + /// 이동 속도 반환 + /// + public float GetMoveSpeed() + { + float bonus = CalculateStatBonus("player_move_speed"); + // move_speed는 mul 연산이지만, 우선 ADD만 지원하므로 add로 처리 + return baseMoveSpeed + bonus; + } + + /// + /// 시야 범위 반환 + /// + public float GetSight() + { + float bonus = CalculateStatBonus("player_sight"); + return baseSight + bonus; + } + + /// + /// 공격 범위 반환 + /// + public float GetAttackRange() + { + float bonus = CalculateStatBonus("player_atk_range"); + return baseAttackRange + bonus; + } + + #region Base Stat Setters (에디터/초기화용) + + public void SetBaseMaxHp(int value) => baseMaxHp = value; + public void SetBaseDamage(int value) => baseDamage = value; + public void SetBaseCapacity(int value) => baseCapacity = value; + public void SetBaseManpower(float value) => baseManpower = value; + public void SetBaseMoveSpeed(float value) => baseMoveSpeed = value; + public void SetBaseSight(float value) => baseSight = value; + public void SetBaseAttackRange(float value) => baseAttackRange = value; + + #endregion + } +} diff --git a/Assets/Scripts/PlayerStats.cs.meta b/Assets/Scripts/PlayerStats.cs.meta new file mode 100644 index 0000000..c6a29f5 --- /dev/null +++ b/Assets/Scripts/PlayerStats.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6aa26fe48ebdaae438d465df7c6a3bef \ No newline at end of file diff --git a/Assets/Scripts/PlayerUpgradeManager.cs b/Assets/Scripts/PlayerUpgradeManager.cs new file mode 100644 index 0000000..df42eee --- /dev/null +++ b/Assets/Scripts/PlayerUpgradeManager.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using Unity.Netcode; +using UnityEngine; +using Northbound.Data; + +namespace Northbound +{ + /// + /// 플레이어별 업그레이드 보유 상태를 관리하는 컴포넌트 + /// + public class PlayerUpgradeManager : NetworkBehaviour + { + // 보유한 업그레이드 ID 목록 (네트워크 동기화) + private NetworkList _ownedUpgradeIds; + + // 이벤트 + public event Action OnUpgradePurchased; // upgradeId + + private NetworkPlayerController _networkPlayerController; + + public new bool IsLocalPlayer => _networkPlayerController != null && _networkPlayerController.IsLocalPlayer; + public ulong OwnerPlayerId => _networkPlayerController != null ? _networkPlayerController.OwnerPlayerId : OwnerClientId; + + private void Awake() + { + _ownedUpgradeIds = new NetworkList(); + _networkPlayerController = GetComponent(); + } + + public override void OnNetworkSpawn() + { + base.OnNetworkSpawn(); + + if (_networkPlayerController != null) + { + _networkPlayerController.OnOwnerChanged += OnOwnerChanged; + } + } + + public override void OnNetworkDespawn() + { + base.OnNetworkDespawn(); + + if (_networkPlayerController != null) + { + _networkPlayerController.OnOwnerChanged -= OnOwnerChanged; + } + + _ownedUpgradeIds.Dispose(); + } + + private void OnOwnerChanged(ulong newOwnerId) + { + // 소유자 변경 시 필요한 처리 + } + + /// + /// 보유한 업그레이드 ID 목록 (복사본 반환) + /// + public List GetOwnedUpgradeIdList() + { + var list = new List(); + foreach (int id in _ownedUpgradeIds) + { + list.Add(id); + } + return list; + } + + + + + /// + /// 특정 업그레이드를 보유하고 있는지 확인 + /// + public bool HasUpgrade(int upgradeId) + { + foreach (int id in _ownedUpgradeIds) + { + if (id == upgradeId) + return true; + } + return false; + } + + /// + /// 보유한 업그레이드 ID를 HashSet으로 반환 + /// + public HashSet GetOwnedUpgradeIdSet() + { + var set = new HashSet(); + foreach (int id in _ownedUpgradeIds) + { + set.Add(id); + } + return set; + } + + /// + /// 업그레이드 구매 요청 (클라이언트에서 호출) + /// + public void RequestPurchaseUpgrade(int upgradeId) + { + PurchaseUpgradeServerRpc(upgradeId); + } + + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] + private void PurchaseUpgradeServerRpc(int upgradeId) + { + if (!CanPurchaseUpgrade(upgradeId, out string failReason)) + { + Debug.LogWarning($"[PlayerUpgradeManager] 업그레이드 구매 실패: {failReason}"); + return; + } + + // 업그레이드 데이터 가져오기 + var upgrade = UpgradeDatabase.Instance?.GetUpgradeById(upgradeId); + if (upgrade == null) + { + Debug.LogError($"[PlayerUpgradeManager] 업그레이드 ID {upgradeId}를 찾을 수 없습니다."); + return; + } + + // 비용 차감 + var core = CoreResourceManager.Instance?.mainCore; + if (core == null) + { + Debug.LogError("[PlayerUpgradeManager] 코어를 찾을 수 없습니다."); + return; + } + + if (!core.CanConsumeResource(upgrade.mana)) + { + Debug.LogWarning($"[PlayerUpgradeManager] 자원이 부족합니다. 필요: {upgrade.mana}"); + return; + } + + core.ConsumeResourceServerRpc(upgrade.mana); + + // 업그레이드 추가 + _ownedUpgradeIds.Add(upgradeId); + + Debug.Log($"[PlayerUpgradeManager] 업그레이드 '{upgrade.memo}' 구매 완료! (ID: {upgradeId})"); + + // 이벤트 발생 + OnUpgradePurchased?.Invoke(upgradeId); + } + + /// + /// 업그레이드 구매 가능 여부 확인 + /// + private bool CanPurchaseUpgrade(int upgradeId, out string failReason) + { + failReason = string.Empty; + + var upgradeDatabase = UpgradeDatabase.Instance; + if (upgradeDatabase == null) + { + failReason = "UpgradeDatabase가 초기화되지 않았습니다."; + return false; + } + + var upgrade = upgradeDatabase.GetUpgradeById(upgradeId); + if (upgrade == null) + { + failReason = $"업그레이드 ID {upgradeId}를 찾을 수 없습니다."; + return false; + } + + // 이미 보유 중인지 확인 + if (HasUpgrade(upgradeId)) + { + failReason = "이미 보유한 업그레이드입니다."; + return false; + } + + // 선행 조건 확인 + if (!upgradeDatabase.ArePrerequisitesMet(upgradeId, GetOwnedUpgradeIdSet())) + { + failReason = "선행 업그레이드 조건을 충족하지 않았습니다."; + return false; + } + + // 비용 확인 + var core = CoreResourceManager.Instance?.mainCore; + if (core == null) + { + failReason = "코어를 찾을 수 없습니다."; + return false; + } + + if (!core.CanConsumeResource(upgrade.mana)) + { + failReason = $"자원이 부족합니다. 필요: {upgrade.mana}, 보유: {core.TotalResources}"; + return false; + } + + // 개인 업그레이드인지 확인 + if (upgrade.upgradeTarget != "person") + { + failReason = "팀 업그레이드는 개인이 구매할 수 없습니다."; + return false; + } + + return true; + } + + /// + /// 업그레이드 구매 가능 여부 (외부용) + /// + public bool CanPurchase(int upgradeId) + { + return CanPurchaseUpgrade(upgradeId, out _); + } + + /// + /// 구매 가능한 업그레이드 목록 반환 + /// + public List GetPurchasableUpgrades() + { + var result = new List(); + var upgradeDatabase = UpgradeDatabase.Instance; + + if (upgradeDatabase == null) return result; + + var personalUpgrades = upgradeDatabase.GetPersonalUpgrades(); + var ownedIds = GetOwnedUpgradeIdSet(); + + foreach (var upgrade in personalUpgrades) + { + if (upgrade == null) continue; + + // 이미 보유하면 제외 + if (ownedIds.Contains(upgrade.id)) continue; + + // 선행 조건 충족 시 구매 가능 + if (upgradeDatabase.ArePrerequisitesMet(upgrade.id, ownedIds)) + { + result.Add(upgrade); + } + } + + return result; + } + + /// + /// 보유한 업그레이드 데이터 목록 반환 + /// + public List GetOwnedUpgradeData() + { + var result = new List(); + var upgradeDatabase = UpgradeDatabase.Instance; + + if (upgradeDatabase == null) return result; + + foreach (int id in _ownedUpgradeIds) + { + var upgrade = upgradeDatabase.GetUpgradeById(id); + if (upgrade != null) + { + result.Add(upgrade); + } + } + + return result; + } + } +} diff --git a/Assets/Scripts/PlayerUpgradeManager.cs.meta b/Assets/Scripts/PlayerUpgradeManager.cs.meta new file mode 100644 index 0000000..064ed0f --- /dev/null +++ b/Assets/Scripts/PlayerUpgradeManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c2399ad44b71131439123eaec84abb08 \ No newline at end of file diff --git a/Assets/Scripts/PlayerVisionProvider.cs b/Assets/Scripts/PlayerVisionProvider.cs index 72f5cdb..46f9799 100644 --- a/Assets/Scripts/PlayerVisionProvider.cs +++ b/Assets/Scripts/PlayerVisionProvider.cs @@ -8,11 +8,11 @@ namespace Northbound /// public class PlayerVisionProvider : NetworkBehaviour, IVisionProvider { - [Header("Vision Settings")] - public float visionRange = 10f; + private PlayerStats _playerStats; public override void OnNetworkSpawn() { + _playerStats = GetComponent(); if (IsServer) { FogOfWarSystem.Instance?.RegisterVisionProvider(this); @@ -28,14 +28,14 @@ namespace Northbound } public ulong GetOwnerId() => OwnerClientId; - public float GetVisionRange() => visionRange; + public float GetVisionRange() => _playerStats?.GetSight() ?? 10f; public Transform GetTransform() => transform; public bool IsActive() => IsSpawned; private void OnDrawGizmosSelected() { Gizmos.color = Color.yellow; - Gizmos.DrawWireSphere(transform.position, visionRange); + Gizmos.DrawWireSphere(transform.position, GetVisionRange()); } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Resource.cs b/Assets/Scripts/Resource.cs index 32b788c..dbf9cfb 100644 --- a/Assets/Scripts/Resource.cs +++ b/Assets/Scripts/Resource.cs @@ -334,13 +334,21 @@ namespace Northbound return; int playerAvailableSpace = resourceManager.GetAvailableSpace(playerId); + // 플레이어의 작업량 가져오기 + float playerWorkPower = GetPlayerWorkPower(playerId); int gatheredAmount = Mathf.Min( - resourcesPerGathering, + (int)playerWorkPower, _currentResources.Value, playerAvailableSpace ); + + + + + + if (gatheredAmount <= 0) { return; @@ -411,8 +419,30 @@ namespace Northbound { return transform; } + /// + /// 플레이어의 작업량 가져오기 (PlayerInteraction.WorkPower) + /// + private float GetPlayerWorkPower(ulong playerId) + { + // PlayerInteraction 컴포넌트에서 workPower 가져오기 + if (NetworkManager.Singleton != null && NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client)) + { + if (client.PlayerObject != null) + { + var playerInteraction = client.PlayerObject.GetComponent(); + if (playerInteraction != null) + { + return playerInteraction.WorkPower; + } + } + } + + // 기본값: 10 + return 10f; + } private Worker FindWorkerForPlayer(ulong playerId) + { if (NetworkManager.Singleton == null || NetworkManager.Singleton.SpawnManager == null) { diff --git a/Assets/Scripts/UpgradeDatabase.cs b/Assets/Scripts/UpgradeDatabase.cs new file mode 100644 index 0000000..acb1c33 --- /dev/null +++ b/Assets/Scripts/UpgradeDatabase.cs @@ -0,0 +1,177 @@ +using System.Collections.Generic; +using UnityEngine; +using Northbound.Data; + +namespace Northbound +{ + /// + /// 업그레이드 데이터를 자동으로 로드하고 관리하는 싱글톤 + /// Resources 폴더에서 모든 UpgradeData를 자동으로 로드 + /// + public class UpgradeDatabase : MonoBehaviour + { + private static UpgradeDatabase _instance; + public static UpgradeDatabase Instance => _instance; + + // Resources에서 자동 로드된 데이터 + private List _upgradeDataList = new List(); + + // 조회용 딕셔너리 + private Dictionary _upgradeById = new Dictionary(); + private Dictionary> _upgradesByCategory = new Dictionary>(); + + // Resources 경로 + private const string UPGRADE_RESOURCES_PATH = "Data/ScriptableObjects/Upgrade"; + + private void Awake() + { + if (_instance != null && _instance != this) + { + Destroy(gameObject); + return; + } + + _instance = this; + LoadUpgradeData(); + BuildLookupTables(); + } + + /// + /// Resources에서 모든 UpgradeData 자동 로드 + /// + private void LoadUpgradeData() + { + _upgradeDataList.Clear(); + + var upgrades = Resources.LoadAll(UPGRADE_RESOURCES_PATH); + _upgradeDataList.AddRange(upgrades); + + Debug.Log($"[UpgradeDatabase] {_upgradeDataList.Count}개의 업그레이드 데이터를 로드했습니다."); + } + + /// + /// 조회용 테이블 구축 + /// + private void BuildLookupTables() + { + _upgradeById.Clear(); + _upgradesByCategory.Clear(); + + foreach (var upgrade in _upgradeDataList) + { + if (upgrade == null) continue; + + // ID로 조회 + if (!_upgradeById.ContainsKey(upgrade.id)) + { + _upgradeById[upgrade.id] = upgrade; + } + + // 카테고리로 조회 + string category = upgrade.upgradeCategory; + if (!_upgradesByCategory.ContainsKey(category)) + { + _upgradesByCategory[category] = new List(); + } + _upgradesByCategory[category].Add(upgrade); + } + } + + /// + /// 데이터 다시 로드 (에디터에서 데이터 변경 시 호출) + /// + public void ReloadData() + { + LoadUpgradeData(); + BuildLookupTables(); + } + + #region Getters + + /// + /// ID로 업그레이드 데이터 조회 + /// + public UpgradeData GetUpgradeById(int id) + { + if (_upgradeById.TryGetValue(id, out var upgrade)) + { + return upgrade; + } + Debug.LogWarning($"[UpgradeDatabase] ID {id}에 해당하는 업그레이드를 찾을 수 없습니다."); + return null; + } + + /// + /// 카테고리로 업그레이드 목록 조회 + /// + public List GetUpgradesByCategory(string category) + { + if (_upgradesByCategory.TryGetValue(category, out var upgrades)) + { + return new List(upgrades); + } + return new List(); + } + + /// + /// 개인 업그레이드 목록 조회 + /// + public List GetPersonalUpgrades() + { + var result = new List(); + foreach (var upgrade in _upgradeDataList) + { + if (upgrade != null && upgrade.upgradeTarget == "person") + { + result.Add(upgrade); + } + } + return result; + } + + /// + /// 팀 업그레이드 목록 조회 + /// + public List GetTeamUpgrades() + { + var result = new List(); + foreach (var upgrade in _upgradeDataList) + { + if (upgrade != null && upgrade.upgradeTarget == "share") + { + result.Add(upgrade); + } + } + return result; + } + + /// + /// 모든 업그레이드 데이터 반환 + /// + public List GetAllUpgrades() + { + return new List(_upgradeDataList); + } + + /// + /// 선행 업그레이드 조건 충족 여부 확인 + /// + public bool ArePrerequisitesMet(int upgradeId, HashSet ownedUpgradeIds) + { + var upgrade = GetUpgradeById(upgradeId); + if (upgrade == null) return false; + + foreach (int requiredId in upgrade.requireUpgradeId) + { + if (!ownedUpgradeIds.Contains(requiredId)) + { + return false; + } + } + + return true; + } + + #endregion + } +} diff --git a/Assets/Scripts/UpgradeDatabase.cs.meta b/Assets/Scripts/UpgradeDatabase.cs.meta new file mode 100644 index 0000000..ba41b19 --- /dev/null +++ b/Assets/Scripts/UpgradeDatabase.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 12780dc9ee390c742b6cbd405e59a916 \ No newline at end of file diff --git a/GameData/Monster.csv b/GameData/Monster.csv index 8c803bd..d6baf39 100644 --- a/GameData/Monster.csv +++ b/GameData/Monster.csv @@ -1,6 +1,6 @@ id,memo,move_speed,max_hp,sight,atk_range,atk_damage,atk_interval_sec,cost,weight,model_path,animation_controller_path,wave_min,wave_max -101,Grunt(기본),6.7,75,6,1,3,1.2,3,1,Assets/Models/Skeleton_Minion.fbx,Assets/Animations/MonsterAnimationController.controller,1,10 +101,Grunt(기본),6.7,75,6,1,3,1.2,3,1.0,Assets/Models/Skeleton_Minion.fbx,Assets/Animations/MonsterAnimationController.controller,1,10 102,Tank(느림/단단),3.3,125,6,1,4,1.5,5,0.5,Assets/Models/Druid.fbx,Assets/Animations/MonsterAnimationController.controller,3,15 103,Ranged(원거리/약함),5.3,65,6,5,2,1.4,3,0.2,Assets/Models/Skeleton_Warrior.fbx,Assets/Animations/MonsterAnimationController.controller,3,20 -104,Fast(빠름/약함),8.6,45,6,1,2,1,3,0.333,Assets/Models/Skeleton_Rogue.fbx,Assets/Animations/MonsterAnimationController.controller,3,20 +104,Fast(빠름/약함),8.6,45,6,1,2,1.0,3,0.333,Assets/Models/Skeleton_Rogue.fbx,Assets/Animations/MonsterAnimationController.controller,3,20 105,Elite(소수 정예),6.6,100,6,1,7,1.3,6,0.1,Assets/Models/Barbarian_Large.fbx,Assets/Animations/MonsterAnimationController.controller,5,20 diff --git a/GameData/Tower.csv b/GameData/Tower.csv index ad9c97b..1c74d6a 100644 --- a/GameData/Tower.csv +++ b/GameData/Tower.csv @@ -1,12 +1,12 @@ id,memo,building_name,level,upgrade_to,tower_type,mana,manpower,size_x,size_y,size_z,max_hp,sight,atk_range,atk_damage,atk_interval_sec,model_path -1,타워,Arrow Tower Lv.1,1,2,attack,100,10,4,10,4,50,10,5,3,2,Assets/Models/building_tower_B_blue.fbx -2,타워,Arrow Tower Lv.2,2,3,attack,200,20,4,10,4,75,10,10,6,2,Assets/Models/building_tower_B_blue.fbx -3,타워,Arrow Tower Lv.3,3,4,attack,300,30,4,10,4,100,15,10,9,2,Assets/Models/building_tower_B_blue.fbx -4,타워,Arrow Tower Lv.4,4,5,attack,400,40,4,10,4,150,15,15,12,2,Assets/Models/building_tower_B_blue.fbx +1,타워,Arrow Tower Lv.1,1,2.0,attack,100,10,4,10,4,50,10,5,3,2,Assets/Models/building_tower_B_blue.fbx +2,타워,Arrow Tower Lv.2,2,3.0,attack,200,20,4,10,4,75,10,10,6,2,Assets/Models/building_tower_B_blue.fbx +3,타워,Arrow Tower Lv.3,3,4.0,attack,300,30,4,10,4,100,15,10,9,2,Assets/Models/building_tower_B_blue.fbx +4,타워,Arrow Tower Lv.4,4,5.0,attack,400,40,4,10,4,150,15,15,12,2,Assets/Models/building_tower_B_blue.fbx 5,타워,Arrow Tower Lv.5,5,,attack,500,50,4,10,4,200,20,15,15,2,Assets/Models/building_tower_B_blue.fbx -6,벽,Wall Lv.1,1,7,defense,10,10,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx -7,벽,Wall Lv.2,2,8,defense,30,10,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx -8,벽,Wall Lv.3,3,9,defense,50,20,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx -9,벽,Wall Lv.4,4,10,defense,100,20,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx +6,벽,Wall Lv.1,1,7.0,defense,10,10,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx +7,벽,Wall Lv.2,2,8.0,defense,30,10,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx +8,벽,Wall Lv.3,3,9.0,defense,50,20,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx +9,벽,Wall Lv.4,4,10.0,defense,100,20,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx 10,벽,Wall Lv.5,5,,defense,150,20,8,4,3,30,1,0,0,0,Assets/Models/wall_straight.fbx 11,와드,Ward Lv.1,1,,sight,10,10,1,1,1,10,5,0,0,0,Assets/Models/torch.fbx