diff --git a/Assets/Materials/Core.png b/Assets/Materials/Core.png new file mode 100644 index 0000000..07ca9f0 Binary files /dev/null and b/Assets/Materials/Core.png differ diff --git a/Assets/Materials/CoreMaterial.mat b/Assets/Materials/CoreMaterial.mat new file mode 100644 index 0000000..234dbed --- /dev/null +++ b/Assets/Materials/CoreMaterial.mat @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: CoreMaterial + m_Shader: {fileID: 4800000, guid: e260cfa7296ee7642b167f1eb5be5023, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _AlphaTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 8e4f24f3ea4a0ed488c8b0abf392ab7a, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MaskTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _EnableExternalAlpha: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _RendererColor: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/EnemyMaterial.mat b/Assets/Materials/EnemyMaterial.mat new file mode 100644 index 0000000..346fcaf --- /dev/null +++ b/Assets/Materials/EnemyMaterial.mat @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: EnemyMaterial + m_Shader: {fileID: 4800000, guid: e260cfa7296ee7642b167f1eb5be5023, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _AlphaTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 2d8756227812cb6418ddf659e94f7226, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MaskTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _EnableExternalAlpha: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _RendererColor: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/GateMaterial.mat b/Assets/Materials/GateMaterial.mat new file mode 100644 index 0000000..b3538c4 --- /dev/null +++ b/Assets/Materials/GateMaterial.mat @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: GateMaterial + m_Shader: {fileID: 4800000, guid: e260cfa7296ee7642b167f1eb5be5023, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _AlphaTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 28b82a4e8f1aa2e4faf3492c62086bce, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MaskTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _EnableExternalAlpha: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _RendererColor: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Ground.png b/Assets/Materials/Ground.png new file mode 100644 index 0000000..30f97f8 Binary files /dev/null and b/Assets/Materials/Ground.png differ diff --git a/Assets/Materials/GroundMaterial.mat b/Assets/Materials/GroundMaterial.mat index 9c13289..20754ca 100644 --- a/Assets/Materials/GroundMaterial.mat +++ b/Assets/Materials/GroundMaterial.mat @@ -28,7 +28,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MainTex: - m_Texture: {fileID: 2800000, guid: b196776e1f0ad0e40b4d75feb0d363b7, type: 3} + m_Texture: {fileID: 2800000, guid: c9946b141fc71a64c958f9fcd9e718cf, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MaskTex: diff --git a/Assets/Materials/GroundMaterial_Generated Maps/MainTex.png b/Assets/Materials/GroundMaterial_Generated Maps/MainTex.png deleted file mode 100644 index 65e6b0c..0000000 Binary files a/Assets/Materials/GroundMaterial_Generated Maps/MainTex.png and /dev/null differ diff --git a/Assets/Materials/Wall.png b/Assets/Materials/Wall.png new file mode 100644 index 0000000..9463a4e Binary files /dev/null and b/Assets/Materials/Wall.png differ diff --git a/Assets/Materials/스피키 회전.png b/Assets/Materials/스피키 회전.png new file mode 100644 index 0000000..39f486d Binary files /dev/null and b/Assets/Materials/스피키 회전.png differ diff --git a/Assets/Prefabs/Enemy.prefab b/Assets/Prefabs/Enemy.prefab new file mode 100644 index 0000000..cb3fbc1 --- /dev/null +++ b/Assets/Prefabs/Enemy.prefab @@ -0,0 +1,284 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3659626783364531313 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6163474767907971787} + - component: {fileID: 2689275992091239379} + - component: {fileID: 3349682118017606557} + - component: {fileID: 2800794347720400813} + - component: {fileID: -5761292396473217197} + - component: {fileID: 8179311635793422716} + - component: {fileID: 7188026176818599596} + - component: {fileID: 9004018437643743475} + m_Layer: 6 + m_Name: Enemy + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6163474767907971787 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + 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: 1, z: 3} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 644112838320947147} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2689275992091239379 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3349682118017606557 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + 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: 10302, guid: 0000000000000000f000000000000000, type: 0} + 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!65 &2800794347720400813 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + 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: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!195 &-5761292396473217197 +NavMeshAgent: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + m_Enabled: 1 + m_AgentTypeID: 0 + m_Radius: 0.5 + m_Speed: 5 + m_Acceleration: 8 + avoidancePriority: 50 + m_AngularSpeed: 120 + m_StoppingDistance: 0 + m_AutoTraverseOffMeshLink: 1 + m_AutoBraking: 1 + m_AutoRepath: 1 + m_Height: 1 + m_BaseOffset: 0.5 + m_WalkableMask: 4294967295 + m_ObstacleAvoidanceType: 4 +--- !u!114 &8179311635793422716 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1c203980d40e2bf4392783aade147dca, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::EnemyAttack + damage: 1 + attackCooldown: 5 +--- !u!114 &7188026176818599596 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0624f93e2b743af4baf8b6459f3a64ff, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::EnemyAI +--- !u!54 &9004018437643743475 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3659626783364531313} + serializedVersion: 5 + m_Mass: 1000 + m_LinearDamping: 0 + m_AngularDamping: 0.05 + m_CenterOfMass: {x: 0, y: 0, z: 0} + m_InertiaTensor: {x: 1, y: 1, z: 1} + m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ImplicitCom: 1 + m_ImplicitTensor: 1 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 112 + m_CollisionDetection: 0 +--- !u!1 &5399706329508289898 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 644112838320947147} + - component: {fileID: 961686847063583643} + - component: {fileID: 1355627780543189246} + m_Layer: 6 + m_Name: Quad + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &644112838320947147 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5399706329508289898} + serializedVersion: 2 + m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.51, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6163474767907971787} + m_LocalEulerAnglesHint: {x: 90, y: 90, z: 0} +--- !u!33 &961686847063583643 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5399706329508289898} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1355627780543189246 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5399706329508289898} + 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: 2100000, guid: 07059e320ce76b044bf5140668021f21, type: 2} + 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/Resources/UGSettingObject.asset b/Assets/Resources/UGSettingObject.asset new file mode 100644 index 0000000..66d0f85 --- /dev/null +++ b/Assets/Resources/UGSettingObject.asset @@ -0,0 +1,22 @@ +%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: 65742e7a9b971e242888935dd58a15a7, type: 3} + m_Name: UGSettingObject + m_EditorClassIdentifier: CAH.UnityGoogleSheets::UGS.UGSettingObject + ScriptURL: + ScriptPassword: default + GoogleFolderID: + GenerateCodePath: Assets/UGS.Generated/Scripts/ + DataPath: Assets/UGS.Generated/Resources/ + RuntimeDataPath: UGS/UGS.Data/ + CDN_URL: + base64: 0 diff --git a/Assets/Scenes/SampleScene/NavMesh-Ground.asset b/Assets/Scenes/SampleScene/NavMesh-Ground.asset new file mode 100644 index 0000000..f55fad9 Binary files /dev/null and b/Assets/Scenes/SampleScene/NavMesh-Ground.asset differ diff --git a/Assets/Scripts/Enemy/EnemyAttack.cs b/Assets/Scripts/Enemy/EnemyAttack.cs new file mode 100644 index 0000000..7f7c6f1 --- /dev/null +++ b/Assets/Scripts/Enemy/EnemyAttack.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class EnemyAttack : MonoBehaviour +{ + [Header("Attack Settings")] + [SerializeField] private float damage = 10f; + [SerializeField] private float attackCooldown = 1.0f; // 공격 간격 (1초) + + private float _nextAttackTime = 0f; + + // EnemyAttack.cs + private void OnCollisionStay(Collision collision) + { + if (Time.time >= _nextAttackTime) + { + // 상대방에게서 IDamageable 인터페이스가 있는지 확인 + IDamageable target = collision.gameObject.GetComponent(); + + if (target != null) + { + target.TakeDamage(damage); + _nextAttackTime = Time.time + attackCooldown; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Enemy/EnemyMoveDefault.cs b/Assets/Scripts/Enemy/EnemyMoveDefault.cs new file mode 100644 index 0000000..dac8a16 --- /dev/null +++ b/Assets/Scripts/Enemy/EnemyMoveDefault.cs @@ -0,0 +1,45 @@ +using UnityEngine; +using UnityEngine.AI; // NavMesh 기능을 위해 필수 + +public class EnemyAI : MonoBehaviour +{ + private NavMeshAgent _agent; + private Transform _target; + + void Awake() + { + _agent = GetComponent(); + } + + void Start() + { + // --- 2번 방법: 위치 보정 로직 시작 --- + // 현재 위치에서 반경 2.0f 이내에 가장 가까운 NavMesh가 있는지 검사합니다. + if (NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 2.0f, NavMesh.AllAreas)) + { + // 에이전트를 해당 위치로 강제 순간이동(Warp) 시킵니다. + // 이 작업은 에러를 방지하고 에이전트를 활성화합니다. + _agent.Warp(hit.position); + } + else + { + Debug.LogError($"{gameObject.name} 근처에 NavMesh를 찾을 수 없습니다! 스폰 위치를 확인하세요."); + } + // --- 2번 방법 끝 --- + + // 기존 타겟(Core) 설정 로직 + GameObject coreObj = GameObject.FindWithTag("Core"); + if (coreObj != null) + { + _target = coreObj.transform; + } + } + + void FixedUpdate() + { + if (_target != null && _agent.isOnNavMesh) + { + _agent.SetDestination(_target.position); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/Core.cs b/Assets/Scripts/GameBase/Core.cs new file mode 100644 index 0000000..4bb3687 --- /dev/null +++ b/Assets/Scripts/GameBase/Core.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using System; + +public class Core : MonoBehaviour, IDamageable +{ + [SerializeField] private float maxHealth = 100f; + private float _currentHealth; + + // 체력이 변경될 때 UI 등에 알리기 위한 이벤트 (Observer 패턴) + public static event Action OnHealthChanged; + public static event Action OnCoreDestroyed; + + void Awake() => _currentHealth = maxHealth; + + public void TakeDamage(float amount) + { + _currentHealth -= amount; + OnHealthChanged?.Invoke(_currentHealth / maxHealth); + + if (_currentHealth <= 0) + OnCoreDestroyed?.Invoke(); + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/GameManager.cs b/Assets/Scripts/GameBase/GameManager.cs new file mode 100644 index 0000000..f08e601 --- /dev/null +++ b/Assets/Scripts/GameBase/GameManager.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using UnityEngine.SceneManagement; // 씬 재시작용 + +public class GameManager : MonoBehaviour +{ + private bool _isGameOver = false; + + private void OnEnable() + { + // Core의 파괴 이벤트를 구독 + Core.OnCoreDestroyed += GameOver; + } + + private void OnDisable() + { + Core.OnCoreDestroyed -= GameOver; + } + + private void GameOver() + { + if (_isGameOver) return; + + _isGameOver = true; + Debug.Log("Game Over! Core has been destroyed."); + + // 여기에 패배 UI 표시 로직 등을 넣습니다. + // 예: 3초 후 게임 재시작 + Invoke(nameof(RestartGame), 3f); + } + + private void RestartGame() + { + // 현재 활성화된 씬을 다시 로드 + SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/Gate.cs b/Assets/Scripts/GameBase/Gate.cs new file mode 100644 index 0000000..5352590 --- /dev/null +++ b/Assets/Scripts/GameBase/Gate.cs @@ -0,0 +1,18 @@ +using UnityEngine; +using System; + +// Gate.cs +public class Gate : MonoBehaviour, IDamageable +{ + [SerializeField] private float maxHealth = 50f; + private float _currentHealth; + + void Awake() => _currentHealth = maxHealth; + + public void TakeDamage(float amount) + { + _currentHealth -= amount; + if (_currentHealth <= 0) + gameObject.SetActive(false); + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/IDamageable.cs b/Assets/Scripts/GameBase/IDamageable.cs new file mode 100644 index 0000000..2ba6b47 --- /dev/null +++ b/Assets/Scripts/GameBase/IDamageable.cs @@ -0,0 +1,5 @@ +// IDamageable.cs +public interface IDamageable +{ + void TakeDamage(float amount); +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/Portal.cs b/Assets/Scripts/GameBase/Portal.cs new file mode 100644 index 0000000..2753cb2 --- /dev/null +++ b/Assets/Scripts/GameBase/Portal.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public class Portal : MonoBehaviour +{ + [SerializeField] private Transform destination; // 순간이동할 목적지 (반대편 포탈의 위치) + [SerializeField] private float cooldown = 1f; // 연속 이동 방지 쿨타임 + private float _lastTeleportTime; + + private void OnTriggerEnter(Collider other) + { + // 플레이어 태그 확인 및 쿨타임 체크 + if (other.CompareTag("Player") && Time.time > _lastTeleportTime + cooldown) + { + // 상대방 포탈의 쿨타임도 같이 설정해야 무한 루프를 방지함 + Portal destPortal = destination.GetComponent(); + if (destPortal != null) destPortal._lastTeleportTime = Time.time; + + _lastTeleportTime = Time.time; + + // 플레이어 위치 이동 + // CharacterController나 Rigidbody를 사용 중이라면 이동 방식에 주의 + other.transform.position = destination.position; + + Debug.Log("Teleported to " + destination.name); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/WaveManager.cs b/Assets/Scripts/GameBase/WaveManager.cs new file mode 100644 index 0000000..201890d --- /dev/null +++ b/Assets/Scripts/GameBase/WaveManager.cs @@ -0,0 +1,76 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +[System.Serializable] // 이 속성이 있어야 인스펙터에 노출됩니다. +public class Wave +{ + public string waveName; // 웨이브 식별용 이름 + public GameObject enemyPrefab; // 소환할 적 프리팹 + public int count; // 소환할 마릿수 + public float spawnRate; // 적 한 마리당 소환 간격 (초) +} + +public class WaveManager : MonoBehaviour +{ + [Header("Wave Settings")] + [SerializeField] private List waves; // 웨이브 데이터 리스트 + [SerializeField] private float timeBetweenWaves = 5f; // 웨이브 간 대기 시간 + [SerializeField] private Transform[] spawnPoints; // 적이 나타날 위치들 + + private Transform _target; + + private int _currentWaveIndex = 0; + + void Start() + { + _target = GameObject.FindWithTag("Core").transform; + + // 게임 시작 시 웨이브 루틴 시작 + StartCoroutine(StartWaveRoutine()); + } + + IEnumerator StartWaveRoutine() + { + // 모든 웨이브를 순회 + while (_currentWaveIndex < waves.Count) + { + Wave currentWave = waves[_currentWaveIndex]; + + Debug.Log($"Wave {_currentWaveIndex + 1}: {currentWave.waveName} 시작!"); + + // 1. 적 소환 로직 + for (int i = 0; i < currentWave.count; i++) + { + SpawnEnemy(currentWave.enemyPrefab); + + // 지정된 간격만큼 대기 (이게 코루틴의 핵심입니다) + yield return new WaitForSeconds(currentWave.spawnRate); + } + + // 2. 다음 웨이브 전까지 대기 + Debug.Log("웨이브 종료. 다음 웨이브 대기 중..."); + yield return new WaitForSeconds(timeBetweenWaves); + + _currentWaveIndex++; + } + + Debug.Log("모든 웨이브가 종료되었습니다!"); + } + + void SpawnEnemy(GameObject enemyPrefab) + { + // 1. 스폰 위치 선택 + Transform spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)]; + + // 2. 방향 계산 (Core - SpawnPoint) + Vector3 directionToCore = (_target.position - spawnPoint.position).normalized; + + // 3. 방향을 Quaternion 회전값으로 변환 (Y축 기준으로만 회전하도록 설정) + // 윗방향(Vector3.up)을 축으로 하여 해당 방향을 바라보게 함 + Quaternion lookRotation = Quaternion.LookRotation(new Vector3(directionToCore.x, 0, directionToCore.z)); + + // 4. 계산된 위치와 회전값으로 생성 + Instantiate(enemyPrefab, spawnPoint.position, lookRotation); + } +} \ No newline at end of file diff --git a/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png b/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png deleted file mode 100644 index 65e6b0c..0000000 Binary files a/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png and /dev/null differ diff --git a/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png.json b/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png.json deleted file mode 100644 index f1a6b8a..0000000 --- a/GeneratedAssets/c179f86efc9ecef499be9cb95262e4f9/019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "asset": "c179f86efc9ecef499be9cb95262e4f9", - "fileName": "019bafb9-28c6-7653-8648-9f0d69f0338e_Preview.png", - "prompt": "ground", - "negativePrompt": "", - "model": "44ec3749-963a-44b1-aa54-dc19f6ed8ab2", - "modelName": "Unity Texture2D", - "customSeed": 1351168645, - "w3CTraceId": "bb3e280eb26aeab699d5529f12fdae5e", - "refinementMode": "Generation" -} \ No newline at end of file diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset index fc90ab9..eb777c1 100644 --- a/ProjectSettings/DynamicsManager.asset +++ b/ProjectSettings/DynamicsManager.asset @@ -3,10 +3,11 @@ --- !u!55 &1 PhysicsManager: m_ObjectHideFlags: 0 - serializedVersion: 13 + serializedVersion: 22 m_Gravity: {x: 0, y: -9.81, z: 0} m_DefaultMaterial: {fileID: 0} m_BounceThreshold: 2 + m_DefaultMaxDepenetrationVelocity: 10 m_SleepThreshold: 0.005 m_DefaultContactOffset: 0.01 m_DefaultSolverIterations: 6 @@ -16,11 +17,11 @@ PhysicsManager: m_EnableAdaptiveForce: 0 m_ClothInterCollisionDistance: 0.1 m_ClothInterCollisionStiffness: 0.2 - m_ContactsGeneration: 1 - m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - m_AutoSimulation: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_SimulationMode: 0 m_AutoSyncTransforms: 0 m_ReuseCollisionCallbacks: 1 + m_InvokeCollisionCallbacks: 1 m_ClothInterCollisionSettingsToggle: 0 m_ClothGravity: {x: 0, y: -9.81, z: 0} m_ContactPairsMode: 0 @@ -31,6 +32,13 @@ PhysicsManager: m_WorldSubdivisions: 8 m_FrictionType: 0 m_EnableEnhancedDeterminism: 0 - m_EnableUnifiedHeightmaps: 1 + m_ImprovedPatchFriction: 0 + m_GenerateOnTriggerStayEvents: 1 m_SolverType: 0 m_DefaultMaxAngularSpeed: 50 + m_ScratchBufferChunkCount: 4 + m_CurrentBackendId: 4072204805 + m_FastMotionThreshold: 3.4028235e+38 + m_SceneBuffersReleaseInterval: 0 + m_ReleaseSceneBuffers: 0 + m_LogVerbosity: 3 diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset index 3b0b7c3..cf9a13f 100644 --- a/ProjectSettings/NavMeshAreas.asset +++ b/ProjectSettings/NavMeshAreas.asset @@ -69,12 +69,12 @@ NavMeshProjectSettings: cost: 1 - name: cost: 1 - m_LastAgentTypeID: -887442657 + m_LastAgentTypeID: -1372625422 m_Settings: - - serializedVersion: 2 + - serializedVersion: 3 agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 + agentRadius: 0.05 + agentHeight: 1 agentSlope: 45 agentClimb: 0.75 ledgeDropHeight: 0 @@ -84,8 +84,29 @@ NavMeshProjectSettings: cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 - accuratePlacement: 0 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + - serializedVersion: 3 + agentTypeID: -1372625422 + agentRadius: 0.05 + agentHeight: 0.001 + agentSlope: 10 + agentClimb: 0.1 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_SettingNames: - Humanoid + - Enemy diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 1c92a78..e332701 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -2,8 +2,10 @@ %TAG !u! tag:unity3d.com,2011: --- !u!78 &1 TagManager: - serializedVersion: 2 - tags: [] + serializedVersion: 3 + tags: + - Core + - Gate layers: - Default - TransparentFX @@ -11,7 +13,7 @@ TagManager: - - Water - UI - - + - Enemy - - - @@ -41,3 +43,5 @@ TagManager: - name: Default uniqueID: 0 locked: 0 + m_RenderingLayers: + - Default