diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 33273b5..4901f29 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -43,6 +43,7 @@ 6000.3.5f2 + @@ -54,9 +55,12 @@ + + + @@ -1245,14 +1249,14 @@ Library\ScriptAssemblies\PPv2URPConverters.dll False - - Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll - False - Library\ScriptAssemblies\Unity.2D.Common.Editor.dll False + + Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll + False + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll False @@ -1289,6 +1293,10 @@ Library\ScriptAssemblies\Unity.2D.Aseprite.Common.dll False + + Library\ScriptAssemblies\Unity.Rider.Editor.dll + False + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll False @@ -1297,10 +1305,6 @@ Library\ScriptAssemblies\Unity.2D.Aseprite.Editor.dll False - - Library\ScriptAssemblies\Unity.Rider.Editor.dll - False - Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll False diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 2006850..99a8509 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -43,6 +43,7 @@ 6000.3.5f2 + @@ -71,6 +72,7 @@ + @@ -1266,14 +1268,14 @@ Library\ScriptAssemblies\PPv2URPConverters.dll False - - Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll - False - Library\ScriptAssemblies\Unity.2D.Common.Editor.dll False + + Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll + False + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll False @@ -1310,6 +1312,10 @@ Library\ScriptAssemblies\Unity.2D.Aseprite.Common.dll False + + Library\ScriptAssemblies\Unity.Rider.Editor.dll + False + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll False @@ -1318,10 +1324,6 @@ Library\ScriptAssemblies\Unity.2D.Aseprite.Editor.dll False - - Library\ScriptAssemblies\Unity.Rider.Editor.dll - False - Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll False diff --git a/Assets/Data/ScriptableObjects/Tower/Tower1.asset b/Assets/Data/ScriptableObjects/Tower/Tower1.asset new file mode 100644 index 0000000..30f963d --- /dev/null +++ b/Assets/Data/ScriptableObjects/Tower/Tower1.asset @@ -0,0 +1,52 @@ +%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: 8c40fef5ebc37b743a3f225c1ca57c32, type: 3} + m_Name: Tower1 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.TowerData + buildingName: "\uD0C0\uC6CC" + prefab: {fileID: 8512676738329978770, guid: 3f7838db2c2fc424d9bd9a0d243b43be, type: 3} + icon: {fileID: 0} + width: 3 + length: 3 + height: 4 + placementOffset: {x: 0, y: 0, z: 0} + allowRotation: 1 + requiredWorkAmount: 10 + workPerInteraction: 10 + interactionCooldown: 1 + constructionAnimationTrigger: Build + constructionEquipment: + socketName: RightHand + equipmentPrefab: {fileID: 0} + attachOnStart: 1 + detachOnEnd: 1 + keepEquipped: 0 + attachDelay: 0 + detachDelay: 0 + maxHealth: 50 + isIndestructible: 0 + autoRegenerate: 0 + regenPerSecond: 1 + providesVision: 1 + visionRange: 10 + id: 1 + memo: "\uD0C0\uC6CC" + mana: 25 + manpower: 10 + sizeX: 3 + sizeY: 3 + sizeZ: 3 + maxHp: 50 + atkRange: 10 + atkDamage: 5 + atkIntervalSec: 2 + modelPath: Assets/Models/building_tower_B_blue.fbx diff --git a/Assets/Data/ScriptableObjects/Tower/Tower1.asset.meta b/Assets/Data/ScriptableObjects/Tower/Tower1.asset.meta new file mode 100644 index 0000000..64011f4 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Tower/Tower1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e2e145df85a3ee4eb615f87efba4554 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/ScriptableObjects/Tower/Tower2.asset b/Assets/Data/ScriptableObjects/Tower/Tower2.asset new file mode 100644 index 0000000..015e69a --- /dev/null +++ b/Assets/Data/ScriptableObjects/Tower/Tower2.asset @@ -0,0 +1,52 @@ +%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: 8c40fef5ebc37b743a3f225c1ca57c32, type: 3} + m_Name: Tower2 + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Data.TowerData + buildingName: "\uBCBD" + prefab: {fileID: 3671057791414486316, guid: ae9a9b515e1792a45887f0d967b943d6, type: 3} + icon: {fileID: 0} + width: 2 + length: 1 + height: 4 + placementOffset: {x: 0, y: 0, z: 0} + allowRotation: 1 + requiredWorkAmount: 5 + workPerInteraction: 10 + interactionCooldown: 1 + constructionAnimationTrigger: Build + constructionEquipment: + socketName: RightHand + equipmentPrefab: {fileID: 0} + attachOnStart: 1 + detachOnEnd: 1 + keepEquipped: 0 + attachDelay: 0 + detachDelay: 0 + maxHealth: 30 + isIndestructible: 0 + autoRegenerate: 0 + regenPerSecond: 1 + providesVision: 1 + visionRange: 0 + id: 2 + memo: "\uBCBD" + mana: 5 + manpower: 5 + sizeX: 2 + sizeY: 2 + sizeZ: 1 + maxHp: 30 + atkRange: 0 + atkDamage: 0 + atkIntervalSec: 0 + modelPath: Assets/Models/wall_straight.fbx diff --git a/Assets/Data/ScriptableObjects/Tower/Tower2.asset.meta b/Assets/Data/ScriptableObjects/Tower/Tower2.asset.meta new file mode 100644 index 0000000..3099776 --- /dev/null +++ b/Assets/Data/ScriptableObjects/Tower/Tower2.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03a521eb1160745439ba2d0efeb12f3c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Scripts/DataClasses/TowerData.cs b/Assets/Data/Scripts/DataClasses/TowerData.cs index 59b9751..138d7fb 100644 --- a/Assets/Data/Scripts/DataClasses/TowerData.cs +++ b/Assets/Data/Scripts/DataClasses/TowerData.cs @@ -3,11 +3,12 @@ using UnityEngine; using System.Collections.Generic; // 리스트 지원을 위해 추가 +using Northbound; namespace Northbound.Data { [CreateAssetMenu(fileName = "TowerData", menuName = "Northbound/Tower Data")] - public class TowerData : ScriptableObject + public class TowerData : BuildingData { [Header("기본 정보")] /// 고유 ID @@ -22,6 +23,8 @@ namespace Northbound.Data public int sizeX; /// Y 그리드 차지 공간 public int sizeY; + /// Z 차지 공간 + public int sizeZ; /// 체력 public int maxHp; /// 사정거리 @@ -30,8 +33,40 @@ namespace Northbound.Data public int atkDamage; /// 공격 주기 public float atkIntervalSec; - /// 프리팹/리소스 경로 - public string prefabPath; + /// 모델 경로 + public string modelPath; + private bool fieldsSynced = false; + + private void Awake() + { + SyncFields(); + } + + private void SyncFields() + { + if (fieldsSynced) return; + fieldsSynced = true; + + // Map TowerData fields to BuildingData fields + if (string.IsNullOrEmpty(base.buildingName)) + { + base.buildingName = memo; + } + base.width = sizeX; + base.length = sizeY; + base.height = sizeZ; + base.maxHealth = maxHp; + base.visionRange = atkRange; + base.requiredWorkAmount = manpower; + base.workPerInteraction = 10f; + base.interactionCooldown =1f; + base.providesVision = true; + } + + public void EnsureSynced() + { + SyncFields(); + } } } \ No newline at end of file diff --git a/Assets/Data/Templates/TowerTemplate.prefab b/Assets/Data/Templates/TowerTemplate.prefab new file mode 100644 index 0000000..5c079e2 --- /dev/null +++ b/Assets/Data/Templates/TowerTemplate.prefab @@ -0,0 +1,146 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7169488976654481418 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4800397361066136527} + - component: {fileID: 4995981673923607444} + - component: {fileID: -5559005308629590716} + - component: {fileID: 8546144977850478548} + - component: {fileID: -4086363217010332088} + - component: {fileID: 4822792797652874450} + m_Layer: 0 + m_Name: TowerTemplate + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4800397361066136527 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + 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: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4995981673923607444 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + 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: 4259369348 + 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!65 &-5559005308629590716 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 2, z: 1} + m_Center: {x: 0, y: 1, z: 0} +--- !u!208 &8546144977850478548 +NavMeshObstacle: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + m_Enabled: 1 + serializedVersion: 3 + m_Shape: 1 + m_Extents: {x: 0.5, y: 1, z: 0.5} + m_MoveThreshold: 0.1 + m_Carve: 0 + m_CarveOnlyStationary: 1 + m_Center: {x: 0, y: 1, z: 0} + m_TimeToStationary: 0.5 +--- !u!114 &-4086363217010332088 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0ceedb9b012d848478813136b65738ae, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Building + ShowTopMostFoldoutHeaderGroup: 1 + buildingData: {fileID: 0} + gridPosition: {x: 0, y: 0, z: 0} + rotation: 0 + initialTeam: 1 + initialOwnerId: 0 + useInitialOwner: 0 + showHealthBar: 1 + healthBarPrefab: {fileID: 0} + destroyEffectPrefab: {fileID: 0} + damageEffectPrefab: {fileID: 0} + effectSpawnPoint: {fileID: 0} + showGridBounds: 1 + gridBoundsColor: {r: 0, g: 1, b: 1, a: 1} +--- !u!114 &4822792797652874450 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7169488976654481418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 0 + updateInterval: 0.2 + renderers: [] + enableDistantVisibility: 1 + heightVisibilityMultiplier: 2 + minHeightForDistantVisibility: 3 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} diff --git a/Assets/Data/Templates/TowerTemplate.prefab.meta b/Assets/Data/Templates/TowerTemplate.prefab.meta new file mode 100644 index 0000000..eb72a97 --- /dev/null +++ b/Assets/Data/Templates/TowerTemplate.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5cb8ca5552f975e4c88d418d11d28dbc +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/DefaultNetworkPrefabs.asset b/Assets/DefaultNetworkPrefabs.asset index eca1e29..ea8eed0 100644 --- a/Assets/DefaultNetworkPrefabs.asset +++ b/Assets/DefaultNetworkPrefabs.asset @@ -99,3 +99,18 @@ MonoBehaviour: SourcePrefabToOverride: {fileID: 0} SourceHashToOverride: 0 OverridingTargetPrefab: {fileID: 0} + - Override: 0 + Prefab: {fileID: 7169488976654481418, guid: 5cb8ca5552f975e4c88d418d11d28dbc, type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} + - Override: 0 + Prefab: {fileID: 8512676738329978770, guid: 3f7838db2c2fc424d9bd9a0d243b43be, type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} + - Override: 0 + Prefab: {fileID: 3671057791414486316, guid: ae9a9b515e1792a45887f0d967b943d6, type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} diff --git a/Assets/Models/building_tower_B_blue.fbx b/Assets/Models/building_tower_B_blue.fbx new file mode 100644 index 0000000..f067591 Binary files /dev/null and b/Assets/Models/building_tower_B_blue.fbx differ diff --git a/Assets/Models/building_tower_B_blue.fbx.meta b/Assets/Models/building_tower_B_blue.fbx.meta new file mode 100644 index 0000000..7b7b2c9 --- /dev/null +++ b/Assets/Models/building_tower_B_blue.fbx.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 3dbb43609bf79104da27aad0a7704ed3 +ModelImporter: + serializedVersion: 24200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + generateMeshLods: 0 + meshLodGenerationFlags: 0 + maximumMeshLod: -1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Models/wall_straight.fbx b/Assets/Models/wall_straight.fbx new file mode 100644 index 0000000..dee0508 Binary files /dev/null and b/Assets/Models/wall_straight.fbx differ diff --git a/Assets/Models/wall_straight.fbx.meta b/Assets/Models/wall_straight.fbx.meta new file mode 100644 index 0000000..31cf921 --- /dev/null +++ b/Assets/Models/wall_straight.fbx.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 0204078ba040180418c65c7f09f3bdb2 +ModelImporter: + serializedVersion: 24200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + generateMeshLods: 0 + meshLodGenerationFlags: 0 + maximumMeshLod: -1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Monster/Monster101.prefab b/Assets/Prefabs/Monster/Monster101.prefab index 4227abb..e34c056 100644 --- a/Assets/Prefabs/Monster/Monster101.prefab +++ b/Assets/Prefabs/Monster/Monster101.prefab @@ -1285,7 +1285,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 2991918417 + GlobalObjectIdHash: 209349728 InScenePlacedSourceGlobalObjectIdHash: 0 DeferredDespawnTick: 0 Ownership: 1 diff --git a/Assets/Prefabs/Monster/Monster105.prefab b/Assets/Prefabs/Monster/Monster105.prefab index cc44787..77039a5 100644 --- a/Assets/Prefabs/Monster/Monster105.prefab +++ b/Assets/Prefabs/Monster/Monster105.prefab @@ -964,8 +964,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 3377967349 - InScenePlacedSourceGlobalObjectIdHash: 2825901034 + GlobalObjectIdHash: 209349728 + InScenePlacedSourceGlobalObjectIdHash: 0 DeferredDespawnTick: 0 Ownership: 1 AlwaysReplicateAsRoot: 0 diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab index 4f292c3..b6ee481 100644 --- a/Assets/Prefabs/Player.prefab +++ b/Assets/Prefabs/Player.prefab @@ -55,7 +55,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 4211758632 + GlobalObjectIdHash: 1360081626 InScenePlacedSourceGlobalObjectIdHash: 4211758632 DeferredDespawnTick: 0 Ownership: 1 diff --git a/Assets/Prefabs/Tower/Tower1.prefab b/Assets/Prefabs/Tower/Tower1.prefab new file mode 100644 index 0000000..4275411 --- /dev/null +++ b/Assets/Prefabs/Tower/Tower1.prefab @@ -0,0 +1,342 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1289760089446993883 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6062607789191353382} + - component: {fileID: 7470654452104141725} + - component: {fileID: 6347255101590433954} + m_Layer: 0 + m_Name: building_tower_B_top_blue + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6062607789191353382 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1289760089446993883} + 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: 1872842023463012809} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7470654452104141725 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1289760089446993883} + m_Mesh: {fileID: -2975848345017946836, guid: 3dbb43609bf79104da27aad0a7704ed3, type: 3} +--- !u!23 &6347255101590433954 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1289760089446993883} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: -6545801570897300931, guid: 3dbb43609bf79104da27aad0a7704ed3, type: 3} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &7757785777080043176 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1872842023463012809} + - component: {fileID: 7668707206409267505} + - component: {fileID: 2906673092929627781} + m_Layer: 0 + m_Name: Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1872842023463012809 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7757785777080043176} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 3, y: 3, z: 3} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6062607789191353382} + m_Father: {fileID: 5446357005769341236} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7668707206409267505 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7757785777080043176} + m_Mesh: {fileID: -1867165846391908481, guid: 3dbb43609bf79104da27aad0a7704ed3, type: 3} +--- !u!23 &2906673092929627781 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7757785777080043176} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: -6545801570897300931, guid: 3dbb43609bf79104da27aad0a7704ed3, type: 3} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &8512676738329978770 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5446357005769341236} + - component: {fileID: 6253727954874418700} + - component: {fileID: 1804512144580361968} + - component: {fileID: 100877884298911200} + - component: {fileID: 8485093670801034058} + - component: {fileID: 7262612124217315611} + - component: {fileID: 3089566480349729} + m_Layer: 0 + m_Name: Tower1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5446357005769341236 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1872842023463012809} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6253727954874418700 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + 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: 4259369348 + 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!65 &1804512144580361968 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 3, y: 3, z: 3} + m_Center: {x: 0, y: 1.5, z: 0} +--- !u!208 &100877884298911200 +NavMeshObstacle: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + m_Enabled: 1 + serializedVersion: 3 + m_Shape: 1 + m_Extents: {x: 1.5, y: 1.5, z: 1.5} + m_MoveThreshold: 0.1 + m_Carve: 0 + m_CarveOnlyStationary: 1 + m_Center: {x: 0, y: 1.5, z: 0} + m_TimeToStationary: 0.5 +--- !u!114 &8485093670801034058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0ceedb9b012d848478813136b65738ae, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Building + ShowTopMostFoldoutHeaderGroup: 1 + buildingData: {fileID: 0} + gridPosition: {x: 0, y: 0, z: 0} + rotation: 0 + initialTeam: 1 + initialOwnerId: 0 + useInitialOwner: 0 + showHealthBar: 1 + healthBarPrefab: {fileID: 0} + destroyEffectPrefab: {fileID: 0} + damageEffectPrefab: {fileID: 0} + effectSpawnPoint: {fileID: 0} + showGridBounds: 1 + gridBoundsColor: {r: 0, g: 1, b: 1, a: 1} +--- !u!114 &7262612124217315611 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 0 + updateInterval: 0.2 + renderers: [] + enableDistantVisibility: 1 + heightVisibilityMultiplier: 2 + minHeightForDistantVisibility: 3 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} +--- !u!114 &3089566480349729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8512676738329978770} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 56c4536effc49fe47af593bf9d17e979, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.TowerDataComponent + towerData: {fileID: 11400000, guid: 3e2e145df85a3ee4eb615f87efba4554, type: 2} diff --git a/Assets/Prefabs/Tower/Tower1.prefab.meta b/Assets/Prefabs/Tower/Tower1.prefab.meta new file mode 100644 index 0000000..1abb589 --- /dev/null +++ b/Assets/Prefabs/Tower/Tower1.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3f7838db2c2fc424d9bd9a0d243b43be +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Tower/Tower2.prefab b/Assets/Prefabs/Tower/Tower2.prefab new file mode 100644 index 0000000..965619e --- /dev/null +++ b/Assets/Prefabs/Tower/Tower2.prefab @@ -0,0 +1,251 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3671057791414486316 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1657799771882240} + - component: {fileID: 3850164934046790335} + - component: {fileID: 7724449748843190139} + - component: {fileID: 2615519446934682856} + - component: {fileID: 3203720634638459019} + - component: {fileID: 3906797260079127802} + - component: {fileID: 3692219876976097854} + m_Layer: 0 + m_Name: Tower2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1657799771882240 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8553397989698296005} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3850164934046790335 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + 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: 4259369348 + 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!65 &7724449748843190139 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 2, y: 1, z: 2} + m_Center: {x: 0, y: 0.5, z: 0} +--- !u!208 &2615519446934682856 +NavMeshObstacle: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + m_Enabled: 1 + serializedVersion: 3 + m_Shape: 1 + m_Extents: {x: 1, y: 0.5, z: 1} + m_MoveThreshold: 0.1 + m_Carve: 0 + m_CarveOnlyStationary: 1 + m_Center: {x: 0, y: 0.5, z: 0} + m_TimeToStationary: 0.5 +--- !u!114 &3203720634638459019 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0ceedb9b012d848478813136b65738ae, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.Building + ShowTopMostFoldoutHeaderGroup: 1 + buildingData: {fileID: 0} + gridPosition: {x: 0, y: 0, z: 0} + rotation: 0 + initialTeam: 1 + initialOwnerId: 0 + useInitialOwner: 0 + showHealthBar: 1 + healthBarPrefab: {fileID: 0} + destroyEffectPrefab: {fileID: 0} + damageEffectPrefab: {fileID: 0} + effectSpawnPoint: {fileID: 0} + showGridBounds: 1 + gridBoundsColor: {r: 0, g: 1, b: 1, a: 1} +--- !u!114 &3906797260079127802 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 760137a2fd0da7f458ac4b0ee7f485d6, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.FogOfWarVisibility + showInExploredAreas: 0 + updateInterval: 0.2 + renderers: [] + enableDistantVisibility: 1 + heightVisibilityMultiplier: 2 + minHeightForDistantVisibility: 3 + useExploredMaterial: 0 + exploredMaterial: {fileID: 0} +--- !u!114 &3692219876976097854 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3671057791414486316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 56c4536effc49fe47af593bf9d17e979, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Northbound.TowerDataComponent + towerData: {fileID: 11400000, guid: 03a521eb1160745439ba2d0efeb12f3c, type: 2} +--- !u!1 &8947776510381915047 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8553397989698296005} + - component: {fileID: 5020570213282043347} + - component: {fileID: 3242347197691888434} + m_Layer: 0 + m_Name: Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8553397989698296005 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8947776510381915047} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 1, z: 2} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1657799771882240} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5020570213282043347 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8947776510381915047} + m_Mesh: {fileID: -4423419886561025764, guid: 0204078ba040180418c65c7f09f3bdb2, type: 3} +--- !u!23 &3242347197691888434 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8947776510381915047} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: -6545801570897300931, guid: 0204078ba040180418c65c7f09f3bdb2, type: 3} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Prefabs/Tower/Tower2.prefab.meta b/Assets/Prefabs/Tower/Tower2.prefab.meta new file mode 100644 index 0000000..56bc1b7 --- /dev/null +++ b/Assets/Prefabs/Tower/Tower2.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ae9a9b515e1792a45887f0d967b943d6 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/GameMain.unity b/Assets/Scenes/GameMain.unity index ccf40cd..4a60462 100644 --- a/Assets/Scenes/GameMain.unity +++ b/Assets/Scenes/GameMain.unity @@ -1712,6 +1712,7 @@ MonoBehaviour: enableHeightBlocking: 1 viewerEyeHeight: 1.5 minBlockingHeight: 2 + disableInEditor: 1 --- !u!4 &946527919 Transform: m_ObjectHideFlags: 0 @@ -1962,16 +1963,28 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.size - value: 0 + value: 5 objectReference: {fileID: 0} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[0].prefab value: - objectReference: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3} + objectReference: {fileID: 7146441246397375875, guid: eccdace7a7b21a446891da5739b1549f, type: 3} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[1].prefab value: - objectReference: {fileID: 5176576196123937037, guid: 951b69041a2ace947afd721fefb3eaba, type: 3} + objectReference: {fileID: 9065146123892903723, guid: 4ee9b364dfe9d0949a23374e660d3e13, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[2].prefab + value: + objectReference: {fileID: 2347008446492047424, guid: 9cac250ebe8d420469bd4da3ab8cfd86, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[3].prefab + value: + objectReference: {fileID: 4973514444862586119, guid: ff2924ffa397a8e44925625790831d25, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[4].prefab + value: + objectReference: {fileID: 5710477988932221578, guid: e8d09b814275ad745a427433c28dd53f, type: 3} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[0].monsterData value: @@ -3315,16 +3328,28 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.size - value: 0 + value: 5 objectReference: {fileID: 0} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[0].prefab value: - objectReference: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3} + objectReference: {fileID: 7146441246397375875, guid: eccdace7a7b21a446891da5739b1549f, type: 3} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[1].prefab value: - objectReference: {fileID: 5176576196123937037, guid: 951b69041a2ace947afd721fefb3eaba, type: 3} + objectReference: {fileID: 9065146123892903723, guid: 4ee9b364dfe9d0949a23374e660d3e13, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[2].prefab + value: + objectReference: {fileID: 2347008446492047424, guid: 9cac250ebe8d420469bd4da3ab8cfd86, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[3].prefab + value: + objectReference: {fileID: 4973514444862586119, guid: ff2924ffa397a8e44925625790831d25, type: 3} + - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} + propertyPath: monsterEntries.Array.data[4].prefab + value: + objectReference: {fileID: 5710477988932221578, guid: e8d09b814275ad745a427433c28dd53f, type: 3} - target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3} propertyPath: monsterEntries.Array.data[0].monsterData value: diff --git a/Assets/ScriptableObjects.meta b/Assets/ScriptableObjects.meta new file mode 100644 index 0000000..1160584 --- /dev/null +++ b/Assets/ScriptableObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5e2a173b42c98746a251ef1dcb4f1a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ScriptableObjects/Monster.meta b/Assets/ScriptableObjects/Monster.meta new file mode 100644 index 0000000..6e990d9 --- /dev/null +++ b/Assets/ScriptableObjects/Monster.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: def17a694f320ed4a80ff136df2b01b7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ScriptableObjects/Tower.meta b/Assets/ScriptableObjects/Tower.meta new file mode 100644 index 0000000..8d82dc8 --- /dev/null +++ b/Assets/ScriptableObjects/Tower.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32bffeae31a205549b9fb32d3674b199 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/BuildingPlacement.cs b/Assets/Scripts/BuildingPlacement.cs index 8022b63..7d6ba65 100644 --- a/Assets/Scripts/BuildingPlacement.cs +++ b/Assets/Scripts/BuildingPlacement.cs @@ -189,6 +189,13 @@ namespace Northbound } Debug.Log($"[BuildingPlacement] 건설 모드 {(isBuildModeActive ? "활성화" : "비활성화")}"); + Debug.Log($"[BuildingPlacement] Preview object: {(previewObject != null ? "CREATED" : "NULL")}"); + if (previewObject != null) + { + Debug.Log($"[BuildingPlacement] Preview position: {previewObject.transform.position}"); + Debug.Log($"[BuildingPlacement] Preview scale: {previewObject.transform.localScale}"); + Debug.Log($"[BuildingPlacement] Preview active: {previewObject.activeSelf}"); + } } /// @@ -231,6 +238,10 @@ namespace Northbound return; } + Debug.Log($"[BuildingPlacement] Creating preview..."); + Debug.Log($"[BuildingPlacement] BuildingManager.availableBuildings.Count: {BuildingManager.Instance.availableBuildings.Count}"); + Debug.Log($"[BuildingPlacement] selectedBuildingIndex: {selectedBuildingIndex}"); + if (selectedBuildingIndex < 0 || selectedBuildingIndex >= BuildingManager.Instance.availableBuildings.Count) { Debug.LogWarning($"[BuildingPlacement] 유효하지 않은 건물 인덱스: {selectedBuildingIndex}"); @@ -238,12 +249,21 @@ namespace Northbound } BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex]; - if (data == null || data.prefab == null) + if (data == null) { - Debug.LogWarning("[BuildingPlacement] BuildingData 또는 Prefab이 없습니다."); + Debug.LogError($"[BuildingPlacement] BuildingData is NULL at index {selectedBuildingIndex}"); return; } + if (data.prefab == null) + { + Debug.LogError($"[BuildingPlacement] BuildingData.prefab is NULL at index {selectedBuildingIndex}. Run 'Northbound > Diagnose Tower System'"); + return; + } + + Debug.Log($"[BuildingPlacement] BuildingData: {data.buildingName}, Prefab: {data.prefab.name}"); + Debug.Log($"[BuildingPlacement] Prefab scale: {data.prefab.transform.localScale}"); + // 완성 건물 프리팹으로 프리뷰 생성 (사용자가 완성 모습을 볼 수 있도록) previewObject = Instantiate(data.prefab); @@ -296,11 +316,17 @@ namespace Northbound if (previewObject == null || BuildingManager.Instance == null) return; + if (selectedBuildingIndex < 0 || selectedBuildingIndex >= BuildingManager.Instance.availableBuildings.Count) + return; + + BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex]; + if (data == null || data.prefab == null) + return; + Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()); if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer)) { - BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex]; // Check if placement is valid bool isValid = BuildingManager.Instance.IsValidPlacement(data, hit.point, currentRotation, out Vector3 snappedPosition); @@ -412,13 +438,24 @@ namespace Northbound { if (BuildingManager.Instance == null) return; + if (selectedBuildingIndex < 0 || selectedBuildingIndex >= BuildingManager.Instance.availableBuildings.Count) + { + Debug.LogWarning($"[BuildingPlacement] Invalid building index: {selectedBuildingIndex}"); + return; + } + + BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex]; + if (data == null || data.prefab == null) + { + Debug.LogError($"[BuildingPlacement] BuildingData or prefab is null at index {selectedBuildingIndex}. Please run 'Northbound > Populate Towers from Prefabs' and update BuildingManager."); + return; + } + Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()); if (!Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer)) { return; } - - BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex]; // 드래그 영역 계산 Vector3 dragEndPosition = hit.point; diff --git a/Assets/Scripts/BuildingQuickslotUI.cs b/Assets/Scripts/BuildingQuickslotUI.cs index e4211e8..7658d39 100644 --- a/Assets/Scripts/BuildingQuickslotUI.cs +++ b/Assets/Scripts/BuildingQuickslotUI.cs @@ -99,6 +99,8 @@ namespace Northbound Debug.LogWarning($"[BuildingQuickslotUI] QuickSlot{i + 1} 액션이 null입니다. Input Actions 에셋을 확인하세요."); } } + + Debug.Log($"[BuildingQuickslotUI] {_quickslotActions.Length}개의 퀵슬롯 액션 초기화됨 (최대 8개 키 바인딩)"); } /// @@ -155,6 +157,10 @@ namespace Northbound { SelectBuilding(slotIndex); } + else if (slotIndex >= slotButtons.Count && quickslotPanel != null && quickslotPanel.activeSelf) + { + Debug.LogWarning($"[BuildingQuickslotUI] 슬롯 {slotIndex + 1}은 존재하지 않습니다. 마우스로 클릭하여 선택하세요."); + } } /// @@ -176,11 +182,10 @@ namespace Northbound } slotButtons.Clear(); - // 건물 목록으로 슬롯 생성 (최대 maxSlots개) + // 모든 건물 슬롯 생성 (제한 없음) var buildings = BuildingManager.Instance.availableBuildings; - int slotCount = Mathf.Min(buildings.Count, maxSlots); - for (int i = 0; i < slotCount; i++) + for (int i = 0; i < buildings.Count; i++) { CreateSlot(buildings[i], i); } diff --git a/Assets/Scripts/Editor/CSVToSOImporter.cs b/Assets/Scripts/Editor/CSVToSOImporter.cs new file mode 100644 index 0000000..4bd8d83 --- /dev/null +++ b/Assets/Scripts/Editor/CSVToSOImporter.cs @@ -0,0 +1,353 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using Northbound.Data; + +namespace Northbound.Editor +{ + public class CSVToSOImporter : EditorWindow + { + private static Dictionary prefabSetups; + + [MenuItem("Tools/Data/Import All CSV")] + public static void ImportAllCSV() + { + InitializePrefabSetups(); + string dataPath = Path.Combine(Application.dataPath, "../GameData"); + + if (!Directory.Exists(dataPath)) + { + Debug.LogError("[CSVToSOImporter] GameData folder not found!"); + return; + } + + string[] csvFiles = Directory.GetFiles(dataPath, "*.csv"); + int successCount = 0; + int failCount = 0; + bool towerImported = false; + + foreach (string csvFile in csvFiles) + { + string fileName = Path.GetFileNameWithoutExtension(csvFile); + if (ImportCSV(fileName)) + { + successCount++; + if (fileName == "Tower") + towerImported = true; + } + else + { + failCount++; + } + } + + Debug.Log($"[CSVToSOImporter] Import complete: {successCount} succeeded, {failCount} failed"); + + if (towerImported) + { + AutoConfigureBuildingManager(); + } + + AssetDatabase.Refresh(); + } + + private static void InitializePrefabSetups() + { + prefabSetups = new Dictionary + { + { "Monster", new MonsterPrefabSetup() }, + { "Tower", new TowerPrefabSetup() } + }; + } + + private static bool ImportCSV(string typeName) + { + string csvPath = Path.Combine(Application.dataPath, "../GameData", $"{typeName}.csv"); + + if (!File.Exists(csvPath)) + { + Debug.LogWarning($"[CSVToSOImporter] CSV file not found: {csvPath}"); + return false; + } + + if (!prefabSetups.ContainsKey(typeName)) + { + Debug.LogWarning($"[CSVToSOImporter] No prefab setup found for type: {typeName}"); + return false; + } + + IPrefabSetup prefabSetup = prefabSetups[typeName]; + string templateName = prefabSetup.GetTemplateName(); + string templatePath = $"Assets/Data/Templates/{templateName}.prefab"; + + GameObject template = AssetDatabase.LoadAssetAtPath(templatePath); + if (template == null) + { + Debug.LogError($"[CSVToSOImporter] Template not found: {templatePath}"); + return false; + } + + string[] csvLines = File.ReadAllLines(csvPath); + if (csvLines.Length < 2) + { + Debug.LogWarning($"[CSVToSOImporter] CSV file is empty or has no data: {csvPath}"); + return false; + } + + string[] headers = ParseCSVLine(csvLines[0]); + int successCount = 0; + + for (int i = 1; i < csvLines.Length; i++) + { + if (string.IsNullOrWhiteSpace(csvLines[i])) + continue; + + string[] values = ParseCSVLine(csvLines[i]); + if (CreatePrefabFromRow(typeName, headers, values, template, prefabSetup)) + { + successCount++; + } + } + + Debug.Log($"[CSVToSOImporter] {typeName}: {successCount} prefabs created/updated"); + + // If towers were imported, auto-configure BuildingManager + // TowerData now extends BuildingData, so it can be used directly! + if (typeName == "Tower") + { + Debug.Log($"[CSVToSOImporter] Tower import complete, TowerData extends BuildingData now!"); + } + + return true; + } + + 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}")); + + int id = 0; + for (int i = 0; i < headers.Length && i < values.Length; i++) + { + if (headers[i].ToLower() == "id") + { + int.TryParse(values[i], out id); + break; + } + } + + if (id == 0) + { + Debug.LogWarning($"[CSVToSOImporter] No valid ID found in row"); + return false; + } + + ScriptableObject data; + string soAssetPath = $"{soPath}/{typeName}{id}.asset"; + data = AssetDatabase.LoadAssetAtPath(soAssetPath); + + bool isNew = false; + if (data == null) + { + data = CreateInstance(typeName + "Data"); + isNew = true; + } + + for (int i = 0; i < headers.Length && i < values.Length; i++) + { + string fieldName = CSVToCamelCase(headers[i]); + var field = data.GetType().GetField(fieldName); + if (field != null) + { + try + { + object value = ParseValue(values[i], field.FieldType); + field.SetValue(data, value); + } + catch (System.Exception e) + { + Debug.LogWarning($"[CSVToSOImporter] Failed to set {fieldName}: {e.Message}"); + } + } + } + + string prefabPath = $"Assets/Prefabs/{typeName}/{typeName}{id}.prefab"; + Directory.CreateDirectory(Path.Combine(Application.dataPath, $"Prefabs/{typeName}")); + + GameObject prefabInstance = GameObject.Instantiate(template); + prefabInstance.name = $"{typeName}{id}"; + + prefabSetup.SetupPrefab(prefabInstance, data); + + GameObject prefabObj = PrefabUtility.SaveAsPrefabAsset(prefabInstance, prefabPath); + GameObject.DestroyImmediate(prefabInstance); + + // Now set the prefab reference on data + if (data is BuildingData buildingData) + { + buildingData.prefab = prefabObj; + Debug.Log($"[CSVToSOImporter] Set prefab reference: {buildingData.name} -> {prefabObj.name}"); + } + + // Save data asset + if (isNew) + { + AssetDatabase.CreateAsset(data, soAssetPath); + } + else + { + EditorUtility.SetDirty(data); + } + + // Force save assets to disk + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + return true; + } + + private static void AutoConfigureBuildingManager() + { + BuildingManager buildingManager = GameObject.FindObjectOfType(); + + if (buildingManager == null) + { + Debug.LogError("[CSVToSOImporter] BuildingManager not found in scene! Please add a BuildingManager component to a GameObject in your scene."); + return; + } + + // Load TowerData (which extends BuildingData) + string[] towerDataGuids = AssetDatabase.FindAssets("t:TowerData", new[] { "Assets/Data/ScriptableObjects" }); + List allTowers = new List(); + + Debug.Log($"[CSVToSOImporter] Found {towerDataGuids.Length} TowerData assets"); + + foreach (string guid in towerDataGuids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guid); + TowerData towerData = AssetDatabase.LoadAssetAtPath(assetPath); + + if (towerData == null) + { + Debug.LogWarning($"[CSVToSOImporter] Failed to load TowerData: {assetPath}"); + continue; + } + + if (towerData.prefab == null) + { + Debug.LogWarning($"[CSVToSOImporter] TowerData {towerData.name} has no prefab reference - skipping"); + continue; + } + + allTowers.Add(towerData); + Debug.Log($"[CSVToSOImporter] Added tower: {towerData.buildingName}"); + } + + if (allTowers.Count == 0) + { + Debug.LogWarning("[CSVToSOImporter] No TowerData with valid prefabs found!"); + Debug.LogWarning("Run 'Northbound > Diagnose Tower System' to see what's wrong"); + return; + } + + allTowers.Sort((a, b) => string.Compare(a.buildingName, b.buildingName)); + + buildingManager.availableBuildings.Clear(); + foreach (var towerData in allTowers) + { + buildingManager.availableBuildings.Add(towerData); + } + + EditorUtility.SetDirty(buildingManager); + EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); + + Debug.Log($"========================================"); + Debug.Log($"🏗️ TOWER IMPORT COMPLETE!"); + Debug.Log($"========================================"); + Debug.Log($"✓ BuildingManager automatically configured!"); + Debug.Log($"✓ Added {allTowers.Count} TowerData to availableBuildings list"); + Debug.Log($"✓ Ready to play - all towers will appear in quickslot!"); + Debug.Log($"========================================"); + foreach (var towerData in allTowers) + { + Debug.Log($" - {towerData.buildingName}"); + } + Debug.Log($"========================================"); + } + + private static object ParseValue(string value, System.Type type) + { + if (string.IsNullOrEmpty(value)) + { + return type.IsValueType ? System.Activator.CreateInstance(type) : null; + } + + if (type == typeof(int)) + { + int result; + if (int.TryParse(value, out result)) return result; + } + else if (type == typeof(float)) + { + float result; + if (float.TryParse(value, out result)) return result; + } + else if (type == typeof(bool)) + { + bool result; + if (bool.TryParse(value, out result)) return result; + } + else if (type == typeof(string)) + { + return value; + } + + return type.IsValueType ? System.Activator.CreateInstance(type) : null; + } + + private static string CSVToCamelCase(string csvName) + { + if (string.IsNullOrEmpty(csvName)) + return csvName; + + string[] parts = csvName.Split('_'); + for (int i = 1; i < parts.Length; i++) + { + if (!string.IsNullOrEmpty(parts[i])) + { + parts[i] = char.ToUpper(parts[i][0]) + parts[i].Substring(1); + } + } + return string.Join("", parts); + } + + private static string[] ParseCSVLine(string line) + { + List result = new List(); + bool inQuotes = false; + string current = ""; + + foreach (char c in line) + { + if (c == '"') + { + inQuotes = !inQuotes; + } + else if (c == ',' && !inQuotes) + { + result.Add(current); + current = ""; + } + else + { + current += c; + } + } + result.Add(current); + return result.ToArray(); + } + } +} diff --git a/Assets/Scripts/Editor/CSVToSOImporter.cs.meta b/Assets/Scripts/Editor/CSVToSOImporter.cs.meta new file mode 100644 index 0000000..275f321 --- /dev/null +++ b/Assets/Scripts/Editor/CSVToSOImporter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c00f900c9a822184dbb4dc85440d40dd \ No newline at end of file diff --git a/Assets/Scripts/Editor/TemplateCreator.cs b/Assets/Scripts/Editor/TemplateCreator.cs index 63cb655..0b66088 100644 --- a/Assets/Scripts/Editor/TemplateCreator.cs +++ b/Assets/Scripts/Editor/TemplateCreator.cs @@ -2,6 +2,7 @@ using Unity.Netcode; using UnityEditor; using UnityEngine; using UnityEngine.AI; +using Northbound; namespace Northbound.Editor { @@ -147,9 +148,35 @@ namespace Northbound.Editor private static void SetupTowerComponents(GameObject go) { + Transform t = go.transform; + t.localPosition = Vector3.zero; + t.localRotation = Quaternion.identity; + t.localScale = Vector3.one; + if (go.GetComponent() == null) go.AddComponent(); + if (go.GetComponent() == null) + go.AddComponent(); + + if (go.GetComponent() == null) + go.AddComponent(); + + if (go.GetComponent() == null) + { + BoxCollider collider = go.AddComponent(); + collider.size = new Vector3(1f, 2f, 1f); + collider.center = new Vector3(0f, 1f, 0f); + } + + if (go.GetComponent() == null) + { + NavMeshObstacle obstacle = go.AddComponent(); + obstacle.shape = NavMeshObstacleShape.Box; + obstacle.size = new Vector3(1f, 1f, 1f); + obstacle.center = new Vector3(0f, 0.5f, 0f); + } + int defaultLayer = LayerMask.NameToLayer("Default"); if (defaultLayer >= 0) { diff --git a/Assets/Scripts/Editor/TowerPopulator.cs b/Assets/Scripts/Editor/TowerPopulator.cs new file mode 100644 index 0000000..d4772b1 --- /dev/null +++ b/Assets/Scripts/Editor/TowerPopulator.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using Northbound; +using Northbound.Data; + +namespace Northbound.Editor +{ + public class TowerPopulator + { + private const string TOWER_PREFAB_PATH = "Assets/Prefabs/Tower"; + private const string TOWER_DATA_PATH = "Assets/Data/ScriptableObjects"; + + [MenuItem("Northbound/Diagnose Tower System")] + public static void DiagnoseTowerSystem() + { + Debug.Log($"========================================"); + Debug.Log($"[TowerPopulator] DIAGNOSING TOWER SYSTEM"); + Debug.Log($"========================================"); + + string[] prefabGuids = AssetDatabase.FindAssets("t:Tower", new[] { TOWER_PREFAB_PATH }); + Debug.Log($"Tower Prefabs in Assets/Prefabs/Tower/:"); + if (prefabGuids.Length == 0) + { + Debug.Log($"✗ No tower prefabs found!"); + } + else + { + foreach (string guid in prefabGuids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guid); + GameObject prefab = AssetDatabase.LoadAssetAtPath(assetPath); + TowerDataComponent tower = prefab?.GetComponent(); + string towerStatus = tower != null && tower.towerData != null ? "✓" : "✗"; + string towerDataName = tower?.towerData?.name ?? "MISSING"; + Debug.Log($" {towerStatus} {prefab.name} - TowerDataComponent: {tower != null}, TowerData: {towerDataName}"); + } + } + + string[] towerDataGuids = AssetDatabase.FindAssets("t:TowerData", new[] { TOWER_DATA_PATH }); + Debug.Log($"TowerData assets in Assets/Data/ScriptableObjects/:"); + if (towerDataGuids.Length == 0) + { + Debug.Log($"⚠ No TowerData assets found - Run 'Tools > Data > Import All CSV' first!"); + } + else + { + foreach (string guid in towerDataGuids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guid); + TowerData data = AssetDatabase.LoadAssetAtPath(assetPath); + string prefabStatus = data?.prefab != null ? "✓" : "✗"; + Debug.Log($" {prefabStatus} {data.name} - Prefab: {data?.prefab?.name ?? "MISSING"}, BuildingName: {data?.buildingName}"); + } + } + + BuildingManager buildingManager = GameObject.FindObjectOfType(); + Debug.Log($"BuildingManager in Scene:"); + if (buildingManager == null) + { + Debug.Log($"✗ BuildingManager not found in scene!"); + } + else + { + Debug.Log($"✓ BuildingManager found: {buildingManager.gameObject.name}"); + Debug.Log($" Available Buildings: {buildingManager.availableBuildings.Count}"); + foreach (var building in buildingManager.availableBuildings) + { + string status = building?.prefab != null ? "✓" : "✗"; + string isTower = building is TowerData ? "[Tower]" : "yellow>[Building]"; + Debug.Log($" {status} {isTower} {building?.name ?? "MISSING"} - {building?.buildingName}"); + } + } + + Debug.Log($"========================================"); + Debug.Log($"[TowerPopulator] DIAGNOSIS COMPLETE"); + Debug.Log($"========================================"); + } + } +} diff --git a/Assets/Scripts/Editor/TowerPopulator.cs.meta b/Assets/Scripts/Editor/TowerPopulator.cs.meta new file mode 100644 index 0000000..d4dd3ed --- /dev/null +++ b/Assets/Scripts/Editor/TowerPopulator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 069a105319ca9cf4a8323e1d5357960f \ No newline at end of file diff --git a/Assets/Scripts/Editor/TowerPrefabSetup.cs b/Assets/Scripts/Editor/TowerPrefabSetup.cs new file mode 100644 index 0000000..005a462 --- /dev/null +++ b/Assets/Scripts/Editor/TowerPrefabSetup.cs @@ -0,0 +1,128 @@ +using Northbound.Data; +using UnityEditor; +using UnityEngine; +using UnityEngine.AI; + +namespace Northbound.Editor +{ + public class TowerPrefabSetup : IPrefabSetup + { + public string GetTemplateName() + { + return "TowerTemplate"; + } + + public void SetupPrefab(GameObject prefab, ScriptableObject data) + { + if (!(data is TowerData towerData)) + { + Debug.LogWarning($"[TowerPrefabSetup] Expected TowerData, got {data.GetType().Name}"); + return; + } + + var towerDataComponent = prefab.GetComponent(); + if (towerDataComponent == null) + { + towerDataComponent = prefab.AddComponent(); + Debug.Log($"[TowerPrefabSetup] Added TowerDataComponent component"); + } + + if (towerDataComponent != null) + { + towerDataComponent.towerData = towerData; + } + + // TowerData now extends BuildingData, so set prefab reference + towerData.prefab = prefab; + + // Ensure TowerData fields are synced to BuildingData + towerData.EnsureSynced(); + + Transform modelTransform = null; + + if (!string.IsNullOrEmpty(towerData.modelPath)) + { + RemoveOldModel(prefab); + + if (towerData.modelPath.ToLower().EndsWith(".fbx")) + { + GameObject fbxModel = AssetDatabase.LoadAssetAtPath(towerData.modelPath); + if (fbxModel != null) + { + GameObject fbxInstance = GameObject.Instantiate(fbxModel); + fbxInstance.name = "Model"; + fbxInstance.transform.SetParent(prefab.transform, false); + fbxInstance.transform.localPosition = Vector3.zero; + fbxInstance.transform.localRotation = Quaternion.identity; + + // Set model scale based on sizeX/sizeY/sizeZ + fbxInstance.transform.localScale = new Vector3(towerData.sizeX, towerData.sizeZ, towerData.sizeY); + + modelTransform = fbxInstance.transform; + + Debug.Log($"[TowerPrefabSetup] Applied FBX model: {towerData.modelPath} with scale {towerData.sizeX}x{towerData.sizeZ}x{towerData.sizeY}"); + } + else + { + Debug.LogWarning($"[TowerPrefabSetup] Could not load FBX model: {towerData.modelPath}"); + } + } + else + { + var meshFilter = prefab.GetComponent(); + if (meshFilter == null) + { + meshFilter = prefab.AddComponent(); + } + + var renderer = prefab.GetComponent(); + if (renderer == null) + { + renderer = prefab.AddComponent(); + } + + Mesh mesh = AssetDatabase.LoadAssetAtPath(towerData.modelPath); + if (mesh != null) + { + meshFilter.sharedMesh = mesh; + + modelTransform = renderer.transform; + modelTransform.localScale = new Vector3(towerData.sizeX, towerData.sizeZ, towerData.sizeY); + + Debug.Log($"[TowerPrefabSetup] Applied mesh: {towerData.modelPath} with scale {towerData.sizeX}x{towerData.sizeZ}x{towerData.sizeY}"); + } + else + { + Debug.LogWarning($"[TowerPrefabSetup] Could not load mesh: {towerData.modelPath}"); + } + } + } + + var collider = prefab.GetComponent(); + if (collider == null) + { + collider = prefab.AddComponent(); + } + collider.size = new Vector3(towerData.sizeX, towerData.sizeZ, towerData.sizeY); + collider.center = new Vector3(0f, towerData.sizeZ / 2f, 0f); + + var navObstacle = prefab.GetComponent(); + if (navObstacle == null) + { + navObstacle = prefab.AddComponent(); + navObstacle.shape = NavMeshObstacleShape.Box; + } + navObstacle.size = new Vector3(towerData.sizeX, towerData.sizeZ, towerData.sizeY); + navObstacle.center = new Vector3(0f, towerData.sizeZ / 2f, 0f); + } + + private void RemoveOldModel(GameObject prefab) + { + Transform oldModel = prefab.transform.Find("Model"); + if (oldModel != null) + { + GameObject.DestroyImmediate(oldModel.gameObject); + } + } + } +} diff --git a/Assets/Scripts/Editor/TowerPrefabSetup.cs.meta b/Assets/Scripts/Editor/TowerPrefabSetup.cs.meta new file mode 100644 index 0000000..026c9ce --- /dev/null +++ b/Assets/Scripts/Editor/TowerPrefabSetup.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ea17487cde4842d45baf5eb92943142a \ No newline at end of file diff --git a/Assets/Scripts/TowerDataComponent.cs b/Assets/Scripts/TowerDataComponent.cs new file mode 100644 index 0000000..35525e8 --- /dev/null +++ b/Assets/Scripts/TowerDataComponent.cs @@ -0,0 +1,26 @@ +using Northbound.Data; +using Unity.Netcode; +using UnityEngine; + +namespace Northbound +{ + [RequireComponent(typeof(Building))] + [RequireComponent(typeof(NetworkObject))] + public class TowerDataComponent : MonoBehaviour + { + [Header("Data Reference")] + [Tooltip("ScriptableObject containing tower data")] + public TowerData towerData; + + private void Awake() + { + // TowerData now extends BuildingData, so just pass it directly + Building building = GetComponent(); + if (building != null && towerData != null) + { + building.buildingData = towerData; + building.initialTeam = TeamType.Player; + } + } + } +} diff --git a/Assets/Scripts/TowerDataComponent.cs.meta b/Assets/Scripts/TowerDataComponent.cs.meta new file mode 100644 index 0000000..f7f5fa3 --- /dev/null +++ b/Assets/Scripts/TowerDataComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 56c4536effc49fe47af593bf9d17e979 \ No newline at end of file diff --git a/ExternAttributes.Editor.csproj b/ExternAttributes.Editor.csproj index 35f03b0..a9c702c 100644 --- a/ExternAttributes.Editor.csproj +++ b/ExternAttributes.Editor.csproj @@ -43,6 +43,7 @@ 6000.3.5f2 + diff --git a/FlatKit.Utils.Editor.csproj b/FlatKit.Utils.Editor.csproj index 9988b14..850b945 100644 --- a/FlatKit.Utils.Editor.csproj +++ b/FlatKit.Utils.Editor.csproj @@ -43,6 +43,7 @@ 6000.3.5f2 + diff --git a/GameData/.Tower_schema.json b/GameData/.Tower_schema.json index bd677e4..878b8b4 100644 --- a/GameData/.Tower_schema.json +++ b/GameData/.Tower_schema.json @@ -35,6 +35,12 @@ "condition": null, "description": "Y 그리드 차지 공간" }, + { + "name": "size_z", + "type": "int", + "condition": null, + "description": "Z 차지 공간" + }, { "name": "max_hp", "type": "int", @@ -60,9 +66,9 @@ "description": "공격 주기" }, { - "name": "prefab_path", + "name": "model_path", "type": "string", "condition": null, - "description": "프리팹/리소스 경로" + "description": "모델 경로" } ] \ No newline at end of file diff --git a/GameData/Tower.csv b/GameData/Tower.csv index ffbde1e..6dd9fb9 100644 --- a/GameData/Tower.csv +++ b/GameData/Tower.csv @@ -1,3 +1,3 @@ -id,memo,mana,manpower,size_x,size_y,max_hp,atk_range,atk_damage,atk_interval_sec,prefab_path -1,타워,25,10,3,3,50,10,5,2,Assets/Prefabs/TowerArrow -2,벽,5,5,1,1,30,0,0,0,Assets/Prefabs/Wall +id,memo,mana,manpower,size_x,size_y,size_z,max_hp,atk_range,atk_damage,atk_interval_sec,model_path +1,타워,25,10,3,3,3,50,10,5,2,Assets/Models/building_tower_B_blue.fbx +2,벽,5,5,2,2,1,30,0,0,0,Assets/Models/wall_straight.fbx diff --git a/TOWER_CSV_IMPORTER.md b/TOWER_CSV_IMPORTER.md new file mode 100644 index 0000000..b49e3bf --- /dev/null +++ b/TOWER_CSV_IMPORTER.md @@ -0,0 +1,138 @@ +# Tower CSV Importer Guide + +## Overview +The tower CSV importer allows you to create tower prefabs from CSV data in one step, similar to the monster importer. + +## Files Created +1. **TowerDataComponent.cs** - Component that applies TowerData to a GameObject +2. **TowerPrefabSetup.cs** - Implementation of IPrefabSetup for tower prefab generation +3. **CSVToSOImporter.cs** - Generic CSV importer that works with any data type + +## How to Use + +### Step 1: Ensure Tower Template Exists +If you haven't created the TowerTemplate yet: +1. In Unity, go to `Tools > Data > Create Tower Template` +2. This creates `Assets/Data/Templates/TowerTemplate.prefab` with all required components: + - NetworkObject + - Building + - TowerDataComponent + - MeshFilter & MeshRenderer + - BoxCollider + - NavMeshObstacle + +### Step 2: Update Tower.csv +Edit `GameData/Tower.csv` with your tower data. The CSV uses camelCase field names matching TowerData class: + +```csv +id,memo,mana,manpower,sizeX,sizeY,maxHp,atkRange,atkDamage,atkIntervalSec,modelPath +1,타워,25,10,3,3,50,10,5,2,Assets/Meshes/building_tower_B_blue.fbx +2,벽,5,5,1,1,30,0,0,0,Assets/Meshes/building_tower_B_blue.fbx +``` + +**Field Descriptions:** +- `id`: Unique tower ID +- `memo`: Tower name/description +- `mana`: Mana cost to build +- `manpower`: Construction work required +- `sizeX`: Grid width +- `sizeY`: Grid length +- `maxHp`: Maximum health +- `atkRange`: Attack range +- `atkDamage`: Attack damage +- `atkIntervalSec`: Attack interval in seconds +- `modelPath`: Path to FBX model or mesh asset + +### Step 3: Import CSV +In Unity, go to `Tools > Data > Import All CSV` + +The importer will: +1. Create ScriptableObject files in `Assets/Data/ScriptableObjects/Tower/` +2. Create/Update prefabs in `Assets/Prefabs/Tower/` +3. Apply models from `modelPath` column +4. Configure components based on CSV data +5. Link TowerData to TowerDataComponent + +### Step 4: Use Tower Prefabs +Your generated tower prefabs are ready to use in the BuildingManager system! + +## File Structure After Import +``` +Assets/ +├── Data/ +│ ├── ScriptableObjects/ +│ │ └── Tower/ # SO files (generated from CSV) +│ │ ├── Tower1.asset +│ │ └── Tower2.asset +│ └── Templates/ # Template prefabs (created once) +│ └── TowerTemplate.prefab +├── Prefabs/ +│ └── Tower/ # Generated tower prefabs +│ ├── Tower1.prefab +│ └── Tower2.prefab +└── GameData/ + └── Tower.csv # Source data (editable) +``` + +## How It Works + +### CSV Import Pipeline +``` +Tower.csv (CSV data) + ↓ CSVToSOImporter +TowerData (ScriptableObject) + ↓ TowerPrefabSetup +Tower.prefab (GameObject with components) +``` + +### TowerPrefabSetup Logic +1. **TowerDataComponent**: Links TowerData SO to the prefab +2. **Model Application**: Loads and applies FBX model from modelPath +3. **Collider Setup**: Creates BoxCollider sized to tower dimensions +4. **Building Integration**: Converts TowerData to BuildingData for Building component + +## Benefits +- ✅ **One-click import**: Import all towers from CSV at once +- ✅ **Consistent structure**: All towers have the same components +- ✅ **Easy updates**: Edit CSV and re-import to update all towers +- ✅ **Designer-friendly**: Non-programmers can add new towers +- ✅ **Type-safe**: TowerData class ensures data integrity + +## Troubleshooting + +**"No prefab setup found for Tower"** +- Make sure TowerPrefabSetup.cs is in the Assets/Scripts/Editor folder +- Restart Unity Editor to ensure the script is compiled + +**"Template not found"** +- Run `Tools > Data > Create Tower Template` first +- Verify TowerTemplate.prefab exists in Assets/Data/Templates/ + +**Prefabs not created** +- Check the Console for error messages +- Verify Tower.csv exists in GameData folder +- Ensure modelPath in CSV points to valid assets + +**Model not showing** +- Verify modelPath in CSV is correct +- Check that the FBX file exists at the specified path +- Ensure the model has valid materials assigned + +## Customization + +### Adding New Components to All Towers +1. Open `Assets/Data/Templates/TowerTemplate.prefab` +2. Add the component +3. Configure defaults +4. Save template +5. Re-import CSV to apply changes to new towers + +### Modifying Existing Towers +- Edit the prefab directly (changes persist on next import) +- OR modify Tower.csv and re-import (will update SO link and model) + +## Notes +- TowerDataComponent converts TowerData to BuildingData for compatibility with the existing Building system +- The importer creates prefabs if they don't exist, or updates existing ones +- Prefab edits (other than SO and model) are preserved on re-import +- CSV field names must match TowerData class property names exactly (case-sensitive, camelCase) diff --git a/TOWER_QUICKSLOT_SETUP.md b/TOWER_QUICKSLOT_SETUP.md new file mode 100644 index 0000000..060925c --- /dev/null +++ b/TOWER_QUICKSLOT_SETUP.md @@ -0,0 +1,120 @@ +# Tower Quickslot Setup Guide + +## 🎯 ULTRA-SIMPLE 1-CLICK SETUP (For Non-Programmers!) + +### Just ONE Step! + +Edit your `GameData/Tower.csv` file with tower data, then in Unity: + +``` +Tools > Data > Import All CSV +``` + +**THAT'S IT!** This automatically does everything: +- ✅ Creates TowerData from CSV (TowerData now extends BuildingData!) +- ✅ Creates Tower prefabs with TowerDataComponent +- ✅ **Auto-configures BuildingManager with all TowerData!** + +### Testing +Press **B** in-game → All towers appear in quickslot! 🎉 + +--- + +## 📝 Adding New Towers + +1. Add row to `GameData/Tower.csv` +2. Run `Tools > Data > Import All CSV` +3. Done! 🚀 + +Everything is automatic! + +--- + +## 🔧 Troubleshooting + +### Error: "BuildingManager not found in scene" + +**Cause:** Your scene doesn't have a GameObject with BuildingManager component. + +**Fix:** +1. Create a new GameObject (e.g., "BuildingManager") +2. Add BuildingManager component to it +3. Run `Tools > Data > Import All CSV` again +4. Done! + +### Error: "MissingReferenceException: prefab doesn't exist" + +**Cause:** TowerData doesn't have prefab reference. + +**Fix:** +1. Run `Northbound > Diagnose Tower System` +2. Check which TowerData shows `✗ MISSING PREFAB` +3. Run `Tools > Data > Import All CSV` to fix +4. Done! + +### No towers appear in quickslot + +**Cause:** BuildingManager wasn't found or configured. + +**Fix:** +1. Run `Northbound > Diagnose Tower System` +2. Check if BuildingManager is found and has TowerData in list +3. If not, add BuildingManager to your scene +4. Run `Tools > Data > Import All CSV` + +--- + +## 🎮 Menu Commands + +| Command | What it does | When to use | +|---------|--------------|--------------| +| `Tools > Data > Import All CSV` | **ONE-CLICK SETUP** - Import all CSV files, create prefabs, auto-configure BuildingManager with TowerData | After editing Tower.csv or anytime you want to update towers | +| `Northbound > Diagnose Tower System` | Check tower system health and find issues | When something doesn't work | + +--- + +## ✅ Why This is Awesome + +- ✅ **ONE CLICK** - Edit CSV, run importer, done! +- ✅ **One folder for towers** - `Assets/Prefabs/Tower/` only +- ✅ **No duplicates** - No manual copying anywhere +- ✅ **Fully automatic** - BuildingManager configured automatically +- ✅ **Non-programmer friendly** - Just edit CSV and click one button! +- ✅ **Works in builds** - Everything is pre-populated +- ✅ **Instant testing** - Press B and see all towers! +- ✅ **Unified data structure** - TowerData extends BuildingData, no redundant data! + +--- + +## 🎉 Complete Workflow for New Teammates + +1. Open Unity project +2. Add BuildingManager GameObject to scene (once) +3. Edit `GameData/Tower.csv` with tower data +4. Run `Tools > Data > Import All CSV` +5. Play game, press **B**, build towers! 🏗️ + +**That's literally it! No manual configuration needed!** + +--- + +## 🏗️ Technical Details + +### Unified Data Structure + +**Before:** Two separate data systems +- TowerData (CSV, tower-specific stats) +- BuildingData (auto-generated, building stats) + +**Now:** Single unified system +- TowerData extends BuildingData +- TowerData has all tower-specific fields (atkRange, atkDamage, etc.) +- TowerData automatically maps to BuildingData fields (width, length, maxHealth, etc.) +- BuildingManager uses TowerData directly (no conversion needed!) + +### Benefits of Unified Structure +- ✅ No duplicate data +- ✅ Single source of truth +- ✅ Cleaner code +- ✅ Easier to maintain +- ✅ Tower prefabs can be used directly without intermediate BuildingData files diff --git a/Unity.RenderPipelines.Universal.Runtime.csproj b/Unity.RenderPipelines.Universal.Runtime.csproj index c30acff..faa692e 100644 --- a/Unity.RenderPipelines.Universal.Runtime.csproj +++ b/Unity.RenderPipelines.Universal.Runtime.csproj @@ -43,14 +43,15 @@ 6000.3.5f2 + - + @@ -142,8 +143,8 @@ - + @@ -246,8 +247,8 @@ - +