feat(BT12-Dev): 스킬 시스템 누적 작업물 (PD 지시 2026-05-12~13)

본 세션 (BurningTimes worktree cranky-wescoff-e855b0) 누적 작업물.
직전 commit 4건 (2ebf313·60e28e3·ea7d32f·f6c6eb5) 영역 외 잔존
미커밋 변경 일괄 commit.

Scripts:
- Health.cs  DecrementBypassInvuln (DoT) + DecrementBypassInvulnWithHit
  (다단 히트) + StartHitFlash + FlashHurtCoroutine + TriggerHitOrHurt
- ActiveSkillData.cs  신규 필드 (DamageFrameDelay·EnableRepeatDamage·
  MaxHitCount·RepeatFrameInterval·OffsetDistance Vector2 등)
- PiercingProjectile.cs  A13 천둥발 관통 + Kinematic Rigidbody2D +
  useFullKinematicContacts + OverlapBox 매 frame
- StatusApplier.cs  ApplyDoT 시 DotFxScale 전달
- TestSkillFireOn1to5.cs  1~5 키 발사 + lazy init EnsureRuntimes

Animator:
- Enemy.controller  Baddie-Hurt self-loop transition (hurt 조건)
- Player.controller  Player-Hit self-loop transition (hit 조건)

Prefab:
- FX_Lightningball.prefab  ball 자식 PS simulationSpace World → Local
- Enemy.prefab  본 세션 측정 조정

Active skill assets (PD Inspector 직접 조정):
- A01·A02·A03·A04·A05·A08·A13·A14·A15·A_Laser
  HitboxSize·OffsetDistance(Vector2)·OffsetXY·FxRotation·HitFxScale·
  DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval

Font:
- NotoSansKR-Regular SDF.asset  본 세션 SDF atlas 갱신

→ 박스↔이펙트 분리 원칙 표준화 (박스 = facing 만 · 이펙트 =
   facing + FxRotation · runtime spawn = HideFlags.DontSave)
→ 모든 피해 시 hit flash + Animator self-loop transition

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-05-13 18:05:13 +09:00
parent f6c6eb5ef5
commit 60812b96ba
22 changed files with 1629 additions and 706 deletions

View File

@ -149,6 +149,31 @@ AnimatorStateTransition:
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1101 &-1054890429478161942
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: hurt
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 1102385943819249538}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 0
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
@ -547,6 +572,7 @@ AnimatorState:
m_Transitions:
- {fileID: 1101786070068309808}
- {fileID: -4341369660076969782}
- {fileID: -1054890429478161942}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -4797,7 +4797,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199602487225978726
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -4813,6 +4813,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -4834,9 +4839,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 2
m_MaskInteraction: 0
m_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -4868,7 +4875,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1218159422115918
GameObject:
m_ObjectHideFlags: 0
@ -9639,7 +9645,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199178698435135056
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -9655,6 +9661,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -9676,9 +9687,11 @@ ParticleSystemRenderer:
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_RenderMode: 1
m_MeshDistribution: 0
m_SortMode: 0
@ -9710,7 +9723,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1265071587776744
GameObject:
m_ObjectHideFlags: 0
@ -14508,7 +14520,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199079735770803486
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -14524,6 +14536,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -14545,9 +14562,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_MaskInteraction: 0
m_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -14579,7 +14598,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1266033033076060
GameObject:
m_ObjectHideFlags: 0
@ -19377,7 +19395,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199316331968399260
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -19393,6 +19411,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -19414,9 +19437,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_MaskInteraction: 0
m_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -19448,7 +19473,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1336197874745238
GameObject:
m_ObjectHideFlags: 0
@ -19555,7 +19579,7 @@ ParticleSystem:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
moveWithTransform: 1
moveWithTransform: 0
moveWithCustomTransform: {fileID: 0}
scalingMode: 0
randomSeed: 0
@ -24295,7 +24319,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199083982413283124
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -24311,6 +24335,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -24332,9 +24361,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 3
m_MaskInteraction: 0
m_RenderMode: 4
m_MeshDistribution: 0
m_SortMode: 0
@ -24366,7 +24397,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1337908085395112
GameObject:
m_ObjectHideFlags: 0
@ -29137,7 +29167,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199773320965910138
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -29153,6 +29183,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -29174,9 +29209,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_MaskInteraction: 0
m_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -29208,7 +29245,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1633638331671150
GameObject:
m_ObjectHideFlags: 0
@ -34006,7 +34042,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199298104296613716
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -34022,6 +34058,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -34043,9 +34084,11 @@ ParticleSystemRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_MaskInteraction: 0
m_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -34077,7 +34120,6 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!1 &1876142652232468
GameObject:
m_ObjectHideFlags: 0
@ -38856,7 +38898,7 @@ ParticleSystem:
vectorLabel1_3: W
--- !u!199 &199835933980034168
ParticleSystemRenderer:
serializedVersion: 6
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -38872,6 +38914,11 @@ ParticleSystemRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
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:
@ -38893,9 +38940,11 @@ ParticleSystemRenderer:
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_RenderMode: 0
m_MeshDistribution: 0
m_SortMode: 0
@ -38927,10 +38976,9 @@ ParticleSystemRenderer:
m_MeshWeighting1: 1
m_MeshWeighting2: 1
m_MeshWeighting3: 1
m_MaskInteraction: 0
--- !u!95 &95222076721961440
Animator:
serializedVersion: 5
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -38944,6 +38992,7 @@ Animator:
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_AnimatePhysics: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1

View File

@ -341,8 +341,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ffad43bb006db4856a9c527b89b48db9, type: 3}
m_Name:
m_EditorClassIdentifier:
maxHearts: 5
maxHP: 20
maxHearts: 250000
maxHP: 1000000
invulnerableDuration: 0.5
resurrectInvulnerableDuration: 2
canResurrect: 0

View File

@ -16,8 +16,9 @@ MonoBehaviour:
DisplayName: "\uB9C8\uBC95 \uD654\uC0B4"
EnglishName: Magic Arrow
Icon: {fileID: 21300000, guid: dde9b620f02314f50b193f224fd60738, type: 3}
Description: "\uC804\uBC29 \uC9C1\uC120 \uB9C8\uBC95 \uD654\uC0B4 \uC790\uB3D9
\uBC1C\uC0AC. \uB2E8\uC77C \uC801 \uD0C0\uACA9. \uAC00\uC7A5 \uAE30\uBCF8 \uD328\uD134."
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC804\uBC29\uC73C\uB85C \uB9C8\uBC95
\uD654\uC0B4\uC744 \uC790\uB3D9 \uBC1C\uC0AC\uD55C\uB2E4. (\uC9C1\uC120 \uC0C1\uC758
\uB2E8\uC77C \uC801 \uD0C0\uACA9)"
AttributeTags: 1
TypeTags: 2
maxLevel: 5
@ -45,3 +46,10 @@ MonoBehaviour:
DebuffStackLimit: 0
FireProbability: 1
Range: 2
ProjectilePrefab: {fileID: 0}
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.5
DotFxScale: 1

View File

@ -16,9 +16,9 @@ MonoBehaviour:
DisplayName: "\uD30C\uC774\uC5B4\uBCFC"
EnglishName: Fireball
Icon: {fileID: 21300000, guid: d8aebc85b5ef946159a971f9c2d1ee78, type: 3}
Description: "\uC804\uBC29 \uC9C1\uC120 \uD654\uC5FC\uAD6C \uC790\uB3D9 \uBC1C\uC0AC.
\uC801\uC911 \uC2DC \uAD11\uC5ED \uD53C\uD574 \uBC0F \uD654\uC5FC \uB3C4\uD2B8
\uBD80\uC5EC."
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC804\uBC29 \uC9C1\uC120 \uD654\uC5FC\uAD6C\uB97C
\uC790\uB3D9 \uBC1C\uC0AC\uD55C\uB2E4. \uC801\uC911 \uC2DC \uAD11\uC5ED \uD53C\uD574
\uBC0F \uD654\uC5FC \uB3C4\uD2B8 \uBD80\uC5EC"
AttributeTags: 2
TypeTags: 6
maxLevel: 5
@ -53,3 +53,6 @@ MonoBehaviour:
OnDotFxPrefab: {fileID: 5410697229499434688, guid: 5505cd51531ed3743b06068c3aca0ce4,
type: 3}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.5
DotFxScale: 0.5

View File

@ -16,8 +16,9 @@ MonoBehaviour:
DisplayName: "\uBD09\uC778 \uB9C8\uBC95"
EnglishName: Sealing Magic
Icon: {fileID: 21300000, guid: 68fc864ccf15b4a81a72d77166aaabf1, type: 3}
Description: "\uC801 \uBC29\uD5A5\uC73C\uB85C \uB0A0\uC544\uAC00\uB294 \uBD80\uC801\uC744
\uC790\uB3D9 \uD22C\uCC99. \uC801\uC911 \uC2DC \uD589\uB3D9 \uC815\uC9C0 (\uC2A4\uD134)."
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC801 \uBC29\uD5A5\uC73C\uB85C \uB0A0\uC544\uAC00\uB294
\uBD80\uC801\uC744 \uC790\uB3D9 \uD22C\uCC99\uD55C\uB2E4. \uC801\uC911 \uC2DC
\uD589\uB3D9 \uC815\uC9C0(\uC2A4\uD134)"
AttributeTags: 16
TypeTags: 2
maxLevel: 5
@ -45,3 +46,10 @@ MonoBehaviour:
DebuffStackLimit: 0
FireProbability: 1
Range: 2
ProjectilePrefab: {fileID: 0}
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.5
DotFxScale: 1

View File

@ -16,8 +16,9 @@ MonoBehaviour:
DisplayName: "\uBC88\uAC1C \uCDA9\uACA9"
EnglishName: Lightning Strike
Icon: {fileID: 0}
Description: "\uD654\uBA74 \uB0B4 \uC784\uC758 \uC801 1\uAE30\uC5D0 \uBC88\uAC1C\uB97C
\uB5A8\uC5B4\uB728\uB824 \uBC94\uC704 \uD53C\uD574"
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC8FC\uBCC0 \uAC00\uAE4C\uC6B4 \uC801\uC758
\uC704\uCE58\uC5D0 \uBC88\uAC1C\uB97C \uB5A8\uC5B4\uB728\uB824 \uD0C0\uACA9\uD55C\uB2E4
(\uC881\uC740 \uBC94\uC704 \uAD11\uC5ED \uD53C\uD574)"
AttributeTags: 8
TypeTags: 2
maxLevel: 5
@ -25,8 +26,8 @@ MonoBehaviour:
Trigger: 0
BaseCooldown: 2.5
BaseDamage: 15
HitboxSize: {x: 1.5, y: 1.5}
OffsetDistance: 0.5
HitboxSize: {x: 1, y: 1}
OffsetDistance: {x: 0, y: 0.5}
Trajectory: 0
MinionPrefab: {fileID: 0}
ChainCount: 0
@ -50,3 +51,12 @@ MonoBehaviour:
type: 3}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 1
HitFxScale: 0.2
DotFxScale: 1
FxRotation: 0
OffsetXY: {x: 0, y: 0}
DamageFrameDelay: 46
EnableRepeatDamage: 0
MaxHitCount: 1
RepeatFrameInterval: 30

View File

@ -13,11 +13,12 @@ MonoBehaviour:
m_Name: A05_hakikjin
m_EditorClassIdentifier: Assembly-CSharp::EerieVillage.Skills.ActiveSkillData
CardId: A05
DisplayName: "\uD559\uC775\uC9C4 (\u9DB4\u7FFC\u9663)"
EnglishName: Fan Slash
DisplayName: "\uC88C/\uC6B0 \uBC94\uC704 \uBCA0\uAE30"
EnglishName: Bi-directional Slash
Icon: {fileID: 0}
Description: "1.5\uCD08 \uAC04\uACA9 \uD50C\uB808\uC774\uC5B4 \uC8FC\uBCC0 \uD559\uC775\uC9C4\xB7\uBC94\uC704
\uB0B4 \uC801 \uC77C\uAD04 \uD0C0\uACA9"
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC804\uBC29/\uD6C4\uBC29 \uBC94\uC704\uB97C
\uC790\uB3D9\uC73C\uB85C \uBCA0\uAE30 \uACF5\uACA9\uC744 \uBC18\uBCF5\uD55C\uB2E4.
\uB2E4\uC911 \uC801 \uB3D9\uC2DC \uD0C0\uACA9(\uBC94\uC704 \uD53C\uD574)"
AttributeTags: 1
TypeTags: 5
maxLevel: 5
@ -25,8 +26,8 @@ MonoBehaviour:
Trigger: 0
BaseCooldown: 1.5
BaseDamage: 10
HitboxSize: {x: 2, y: 2}
OffsetDistance: 0.5
HitboxSize: {x: 4.8, y: 1.2}
OffsetDistance: {x: 0, y: 1}
Trajectory: 0
MinionPrefab: {fileID: 0}
ChainCount: 0
@ -50,3 +51,12 @@ MonoBehaviour:
type: 3}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 1
HitFxScale: 0.5
DotFxScale: 1
FxRotation: 0
OffsetXY: {x: 0.2, y: -1.2}
DamageFrameDelay: 10
EnableRepeatDamage: 0
MaxHitCount: 1
RepeatFrameInterval: 30

View File

@ -16,9 +16,10 @@ MonoBehaviour:
DisplayName: "\uC800\uC8FC\uC758 \uD654\uC0B4"
EnglishName: Cursed Arrow
Icon: {fileID: 21300000, guid: 7d40f81d1194044f9b42a03c80ddcf7b, type: 3}
Description: "\uC9E7\uC740 \uC8FC\uAE30\uB85C \uB2E8\uAC70\uB9AC \uC9C1\uC120 \uB2E8\uC77C
\uC801 \uD0C0\uACA9. \uC801\uC911 \uC2DC \uC800\uC8FC \uC2A4\uD0DD \uB204\uC801\xB7N\uC2A4\uD0DD
\uC2DC \uD3ED\uBC1C."
Description: "\uC9E7\uC740 \uC8FC\uAE30\uB85C \uB2E8\uAC70\uB9AC \uC9C1\uC120 \uC0C1\uC758
\uB2E8\uC77C \uC801 \uD0C0\uACA9\uD558\uB294 \uC800\uC8FC \uD654\uC0B4\uC744
\uC790\uB3D9 \uD22C\uCC99\uD55C\uB2E4. \uC801\uC911 \uC2DC \uC800\uC8FC \uC2A4\uD0DD
\uB204\uC801\xB7N\uC2A4\uD0DD \uC2DC \uD3ED\uBC1C"
AttributeTags: 16
TypeTags: 2
maxLevel: 5
@ -26,7 +27,7 @@ MonoBehaviour:
Trigger: 0
BaseCooldown: 0.8
BaseDamage: 2
HitboxSize: {x: 1.5, y: 1}
HitboxSize: {x: 1.5, y: 3}
OffsetDistance: 0.5
Trajectory: 0
MinionPrefab: {fileID: 0}
@ -46,3 +47,12 @@ MonoBehaviour:
DebuffStackLimit: 5
FireProbability: 1
Range: 1
ProjectilePrefab: {fileID: 0}
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 1
HitFxScale: 1
DotFxScale: 1
FxRotation: 0
OffsetXY: {x: 0, y: 0}

View File

@ -13,12 +13,13 @@ MonoBehaviour:
m_Name: A13_cheondoongbal
m_EditorClassIdentifier: Assembly-CSharp::EerieVillage.Skills.ActiveSkillData
CardId: A13
DisplayName: "\uCC9C\uB465\uBC1C (\u5929\u52D5\u64A5)"
EnglishName: Thunder Ball
DisplayName: "\uC800\uC8FC \uAD6C\uCCB4"
EnglishName: Cursed Orb
Icon: {fileID: 0}
Description: "2.5\uCD08\uB9C8\uB2E4 Lightningball \uD22C\uC0AC\uCCB4 \uBC1C\uC0AC\xB7\uCC9C\uCC9C\uD788
\uC804\uC9C4\xB7\uACBD\uB85C \uB2FF\uB294 \uC801 0.2\uCD08 \uAC04\uACA9 8 \uD53C\uD574
(\uAD00\uD1B5)"
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC804\uBC29\uC73C\uB85C \uCC9C\uCC9C\uD788
\uB0A0\uC544\uAC00\uBA70 \uACBD\uB85C \uC0C1 \uC801\uC5D0\uAC8C \uC9E7\uC740
\uC8FC\uAE30\uB85C \uD53C\uD574\uB97C \uC8FC\uB294 \uC6D0\uD615 \uAD6C\uCCB4\uB97C
\uC0DD\uC131\uD55C\uB2E4"
AttributeTags: 8
TypeTags: 2
maxLevel: 5
@ -26,7 +27,7 @@ MonoBehaviour:
Trigger: 0
BaseCooldown: 2.5
BaseDamage: 8
HitboxSize: {x: 1, y: 1}
HitboxSize: {x: 8, y: 8}
OffsetDistance: 0.5
Trajectory: 2
MinionPrefab: {fileID: 0}
@ -51,3 +52,8 @@ MonoBehaviour:
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.15
HitFxScale: 0
DotFxScale: 0
FxRotation: 0
OffsetXY: {x: 0, y: 0}

View File

@ -16,8 +16,8 @@ MonoBehaviour:
DisplayName: "\uC5BC\uC74C \uCC3D"
EnglishName: Ice Spear
Icon: {fileID: 21300000, guid: 36e0d7c11193d4620aab8c81598ea0fe, type: 3}
Description: "\uC9C1\uC120 \uC5BC\uC74C \uCC3D \uBC1C\uC0AC. \uC801\uC911 \uC2DC
\uB454\uD654 \uBD80\uC5EC."
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uC9C1\uC120 \uC5BC\uC74C \uCC3D\uC744
\uBC1C\uC0AC\uD55C\uB2E4. \uC801\uC911 \uC2DC \uB454\uD654 \uBD80\uC5EC"
AttributeTags: 4
TypeTags: 2
maxLevel: 5
@ -45,3 +45,10 @@ MonoBehaviour:
DebuffStackLimit: 0
FireProbability: 1
Range: 3
ProjectilePrefab: {fileID: 0}
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.5
DotFxScale: 1

View File

@ -13,11 +13,12 @@ MonoBehaviour:
m_Name: A15_chujeok_hwayeomgu
m_EditorClassIdentifier:
CardId: A15
DisplayName: "\uCD94\uC801 \uD654\uC5FC\uAD6C"
EnglishName: Homing Fireball
DisplayName: "\uCD94\uC801 \uB808\uC774\uC800"
EnglishName: Tracking Laser
Icon: {fileID: 21300000, guid: 027cbee02deda4dc5a434de3acf7fc4a, type: 3}
Description: "\uAC00\uC7A5 \uAC00\uAE4C\uC6B4 \uB2E8\uC77C \uC801\uC744 \uCD94\uC801.
\uC9C0\uC18D\uC801 \uD53C\uD574."
Description: "\uC911\uAC04 \uC8FC\uAE30\uB85C \uAC00\uC7A5 \uAC00\uAE4C\uC6B4 \uB2E8\uC77C
\uC801\uC744 \uCD94\uC801\uD574 \uC9C0\uC18D\uC801\uC73C\uB85C \uD53C\uD574\uB97C
\uC8FC\uB294 \uB808\uC774\uC800\uB97C \uC18C\uD658\uD55C\uB2E4"
AttributeTags: 2
TypeTags: 2
maxLevel: 5
@ -45,3 +46,10 @@ MonoBehaviour:
DebuffStackLimit: 0
FireProbability: 1
Range: 4
ProjectilePrefab: {fileID: 0}
OnHitFxPrefab: {fileID: 0}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.5
DotFxScale: 1

View File

@ -26,8 +26,8 @@ MonoBehaviour:
Trigger: 0
BaseCooldown: 3
BaseDamage: 5
HitboxSize: {x: 8, y: 1}
OffsetDistance: 0.5
HitboxSize: {x: 0, y: 10}
OffsetDistance: {x: 3, y: -0.6}
Trajectory: 0
MinionPrefab: {fileID: 0}
ChainCount: 0
@ -51,3 +51,12 @@ MonoBehaviour:
type: 3}
OnDotFxPrefab: {fileID: 0}
DotDamageMultiplier: 0.25
ProjectileFxScale: 0.5
HitFxScale: 0.25
DotFxScale: 0.5
FxRotation: 90
OffsetXY: {x: 0, y: 0}
DamageFrameDelay: 12
EnableRepeatDamage: 1
MaxHitCount: 1
RepeatFrameInterval: 18

View File

@ -143,6 +143,7 @@ namespace Platformer.Mechanics
if (animator == null) animator = GetComponentInChildren<Animator>();
if (animator != null) TriggerHitOrHurt(animator);
OnDamagedEvent?.Invoke(damage);
StartHitFlash(); // PD 지시 2026-05-13 — 모든 피해 영역 flash 연출
}
if (currentHP == 0)
@ -199,14 +200,45 @@ namespace Platformer.Mechanics
/// BT12-Dev 2026-05-13 — Animator parameter 영역 "hit" (Player) 또는 "hurt" (Enemy) Trigger 호출.
/// 어느 한쪽만 존재하므로 둘 다 시도해 정합 발화.
/// </summary>
// PD 지시 2026-05-13 — 모든 피해 영역 sprite flash (붉은색·alpha 50%·1 frame 후 원복)
public void StartHitFlash()
{
StartCoroutine(FlashHurtCoroutine());
}
System.Collections.IEnumerator FlashHurtCoroutine()
{
var sr = GetComponent<SpriteRenderer>();
if (sr == null) sr = GetComponentInChildren<SpriteRenderer>();
if (sr == null) yield break;
var orig = sr.color;
sr.color = new Color(1f, 0.3f, 0.3f, 0.5f);
yield return null;
if (sr != null) sr.color = orig;
}
static void TriggerHitOrHurt(Animator animator)
{
if (animator == null || animator.runtimeAnimatorController == null) return;
// PD 지시 2026-05-13 — Hurt State 영역 영역 영역 영역 SetTrigger 영역 무시 영역 영역.
// ResetTrigger → 강제 rewind (현재 State Time=0) → SetTrigger 영역 매번 hit 모션 발화 정합.
string trigName = null;
foreach (var p in animator.parameters)
{
if (p.type != AnimatorControllerParameterType.Trigger) continue;
if (p.name == "hit" || p.name == "hurt") animator.SetTrigger(p.name);
if (p.name == "hit" || p.name == "hurt") { trigName = p.name; break; }
}
if (trigName == null) return;
animator.ResetTrigger(trigName);
// 현재 State 가 hit/hurt 관련 영역 영역 강제 rewind (time=0) 영역 영역 영역 — 자동 transition 영역 영역 영역 SetTrigger.
var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
// State 이름이 Hurt/Hit 포함 영역 영역 rewind
if (stateInfo.IsTag("Hit") || stateInfo.IsTag("Hurt"))
{
animator.Play(stateInfo.fullPathHash, 0, 0f);
}
animator.SetTrigger(trigName);
}
/// <summary>
@ -221,6 +253,34 @@ namespace Platformer.Mechanics
if (currentHP > 0)
{
OnDamagedEvent?.Invoke(damage);
StartHitFlash(); // PD 지시 2026-05-13 — DoT 영역도 flash 영역
}
if (currentHP == 0)
{
var animator = GetComponent<Animator>();
if (animator != null) animator.SetBool("dead", true);
OnDeathEvent?.Invoke();
var ev = Schedule<HealthIsZero>();
ev.health = this;
}
}
/// <summary>
/// PD 지시 2026-05-13 — invuln 미갱신·hit Animator Trigger 영역 (A05·A_Laser·A13 등 영역 영역 영역).
/// DoT 와 분리: DoT 영역 hit 모션 X·이 영역 hit 모션 표시.
/// </summary>
public void DecrementBypassInvulnWithHit(int damage)
{
if (damage <= 0) return;
currentHP = Mathf.Clamp(currentHP - damage, 0, maxHP);
// invulnerableUntil 갱신 X·hit Animator Trigger ON
if (currentHP > 0)
{
var animator = GetComponent<Animator>();
if (animator == null) animator = GetComponentInChildren<Animator>();
if (animator != null) TriggerHitOrHurt(animator);
OnDamagedEvent?.Invoke(damage);
StartHitFlash();
}
if (currentHP == 0)
{

View File

@ -24,8 +24,8 @@ namespace EerieVillage.Skills
[Tooltip("판정 박스 기본 크기 (A·B 카테고리). balance/01 v0.2 AttackBoxSize 1.5x1.0 참조")]
public Vector2 HitboxSize = new Vector2(1.5f, 1.0f);
[Tooltip("투사체 발사 오프셋 거리 (A 카테고리)")]
public float OffsetDistance = 0.5f;
[Tooltip("히트박스 위치 오프셋 (anchor 기준 X·Y 절대). 투사체 영역 X=facing 방향 거리·Y=직각 거리")]
public Vector2 OffsetDistance = new Vector2(0.5f, 0f);
[Tooltip("투사체 전용 (A 카테고리). 궤적 타입 — Line·Homing·Arc")]
public ProjectileTrajectory Trajectory = ProjectileTrajectory.Line;
@ -98,6 +98,45 @@ namespace EerieVillage.Skills
[Tooltip("DoT damage = BaseDamage × DotDamageMultiplier (예: 0.25 = 25%)")]
[Range(0f, 5f)]
public float DotDamageMultiplier = 0.25f;
// BT12-Dev 2026-05-13 — 이펙트 크기 분리 조절 (PD 지시·옵션 B)
[Header("이펙트 크기 (1.0 = 원본)")]
[Tooltip("ProjectilePrefab 영역 크기 배율 (Projectile·PiercingProjectile 자체)")]
[Range(0f, 5f)]
public float ProjectileFxScale = 1.0f;
[Tooltip("OnHitFxPrefab 영역 크기 배율 (피격·번개·학익진 FX 등)")]
[Range(0f, 5f)]
public float HitFxScale = 1.0f;
[Tooltip("OnDotFxPrefab 영역 크기 배율 (불태우기 등 DoT FX)")]
[Range(0f, 5f)]
public float DotFxScale = 1.0f;
// PD 지시 2026-05-13 — 이펙트 회전·위치 X·Y 조정 (옵션 A — 단일 필드)
[Tooltip("이펙트 회전 각도 (도 단위·Z 축 회전). 모든 FX·시각화 박스 공통 적용")]
[Range(-360f, 360f)]
public float FxRotation = 0f;
[Tooltip("이펙트 위치 X·Y 오프셋 (이펙트 전용). 모든 스킬 공통 적용")]
public Vector2 OffsetXY = Vector2.zero;
// PD 지시 2026-05-13 — 판정 발생 정밀 제어 (투사체 제외 고정 발동형: A04·A05·A_Laser 등)
[Header("판정 타이밍 (고정 발동형 전용)")]
[Tooltip("Trigger 시점 영역 첫 판정 프레임 (예: 25 = Trigger 후 25프레임 후 첫 hit)")]
[Min(0)]
public int DamageFrameDelay = 0;
[Tooltip("반복 피해 활성 — false 영역 1회만·true 영역 MaxHitCount 회 영역 RepeatFrameInterval 간격")]
public bool EnableRepeatDamage = false;
[Tooltip("최대 타격 횟수 (EnableRepeatDamage=true 시)")]
[Min(1)]
public int MaxHitCount = 1;
[Tooltip("반복 피해 간격 (프레임 단위·EnableRepeatDamage=true 시)")]
[Min(1)]
public int RepeatFrameInterval = 30;
}
public enum RangeTier { Short, MediumShort, Medium, MediumLong, Long }

View File

@ -0,0 +1,68 @@
using UnityEngine;
using Platformer.Mechanics;
namespace EerieVillage.Skills.Effectors
{
/// <summary>
/// PD 지시 2026-05-13 — Inspector 영역 ActiveSkillData 값 변경 시 살아있는 시각화 박스도 즉시 반영.
/// LateUpdate 매 frame data 정합 갱신: position·rotation·localScale.
/// </summary>
public class LiveHitboxSync : MonoBehaviour
{
public enum FollowMode
{
/// <summary>Anchor + (0, OffsetDistance) + OffsetXY · size=HitboxSize · rot=FxRotation (A05 MeleeArea)</summary>
AnchorYOffset,
/// <summary>Anchor (Enemy) + (0, OffsetDistance) + OffsetXY · size=HitboxSize · rot=FxRotation (A04 Lightning·primary 사망 시 마지막 위치 유지)</summary>
EnemyAnchoredAtStrike,
/// <summary>Anchor (Player) + facing × (OffsetDistance + length/2) + OffsetXY · size=(length, width) · rot=facing+FxRotation (A_Laser)</summary>
PlayerFacingLaser,
}
public ActiveSkillData Data;
public Transform Anchor;
public FollowMode Mode;
// PlayerFacingLaser 영역 영역 — Anchor (Player) 영역 PlayerController.Facing 영역 영역
public PlayerController PlayerCtrl;
// EnemyAnchoredAtStrike — Anchor (primary enemy) 사망 시 마지막 위치 캐싱
Vector2 _lastAnchorPos;
bool _hasLastPos;
void LateUpdate()
{
if (Data == null) return;
Vector2 anchorPos;
if (Anchor != null) { anchorPos = Anchor.position; _lastAnchorPos = anchorPos; _hasLastPos = true; }
else if (_hasLastPos) anchorPos = _lastAnchorPos;
else return;
Vector2 pos = anchorPos;
float angle = 0f;
Vector3 scale = transform.localScale;
switch (Mode)
{
case FollowMode.AnchorYOffset:
case FollowMode.EnemyAnchoredAtStrike:
pos += Data.OffsetDistance + Data.OffsetXY;
angle = Data.FxRotation;
scale = new Vector3(Data.HitboxSize.x, Data.HitboxSize.y, 1f);
break;
case FollowMode.PlayerFacingLaser:
Vector2 facing = (PlayerCtrl != null) ? PlayerCtrl.Facing : Vector2.right;
facing = facing.normalized;
float length = Mathf.Max(Data.HitboxSize.x, 1f);
float width = Mathf.Max(Data.HitboxSize.y, 0.5f);
pos += Data.OffsetDistance + Data.OffsetXY + facing * (length * 0.5f);
angle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg + Data.FxRotation;
scale = new Vector3(length, width, 1f);
break;
}
transform.position = pos;
transform.rotation = Quaternion.Euler(0f, 0f, angle);
transform.localScale = scale;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6d9ea6b34638696488f9d035f9313e80

View File

@ -25,40 +25,63 @@ namespace EerieVillage.Skills.Effectors
_speed = 2.5f; // PD 지시 2026-05-13 — A13 천둥발 천천히 전진 (기본 6 → 2.5)
_lifetime = 6f; // 관통이므로 lifetime 길게
_lastHitTime.Clear();
// PD 정합 2026-05-13 — OnTriggerStay2D 발화 영역 Kinematic Rigidbody2D + useFullKinematicContacts 영역
// Enemy 영역 Kinematic Rb → Kinematic vs Kinematic OnTriggerStay2D 영역 기본 발화 X.
// useFullKinematicContacts=true 영역 영역 발화 정합.
var rb = GetComponent<Rigidbody2D>();
if (rb == null) rb = gameObject.AddComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Kinematic;
rb.simulated = true;
rb.gravityScale = 0f;
rb.useFullKinematicContacts = true;
}
// 관통이므로 OnTriggerEnter2D 영역 영역 X·OnTriggerStay2D 영역 영역 영역 영역
// PD 정합 2026-05-13 — OnTrigger 영역 폐기 (Kinematic vs Kinematic 발화 영역 영역 X).
// Update 영역 OverlapBox 영역 매 frame 직접 검사·적별 0.2s 간격 영역 (다른 액티브 정합).
protected override void OnTriggerEnter2D(Collider2D other) { /* no-op */ }
void OnTriggerStay2D(Collider2D other)
protected override void Update()
{
// PlayerController·Wall 영역 영역 X
if (other.GetComponent<PlayerController>() != null) return;
int enemyLayer = LayerMask.NameToLayer("Enemy");
bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer)
|| other.GetComponent<EnemyController>() != null;
if (!isEnemy) return;
var enemy = other.GetComponent<EnemyController>();
if (enemy == null) return;
var health = other.GetComponent<Health>();
if (health == null || !health.IsAlive) return;
base.Update(); // 이동·페이드·SyncHitboxToData
if (_data == null) return;
float interval = (_data.DotInterval > 0.01f) ? _data.DotInterval : 0.2f;
float now = Time.time;
float last;
if (_lastHitTime.TryGetValue(enemy, out last))
{
if (now - last < interval) return;
}
_lastHitTime[enemy] = now;
int damage = Mathf.Max(_runtime.CalculateEffectiveDamage(), _data.BaseDamage);
// 관통 형 — DoT 처럼 invuln 미갱신 데미지 (다른 적도 동시 영역 영역)
health.DecrementBypassInvuln(damage);
if (!health.IsAlive)
var cf = new ContactFilter2D();
cf.useTriggers = false;
int enemyLayer = LayerMask.NameToLayer("Enemy");
if (enemyLayer >= 0) { cf.SetLayerMask(1 << enemyLayer); cf.useLayerMask = true; }
var results = new Collider2D[16];
// 박스 영역 transform.position + collider.size × localScale 영역 정합
var box = GetComponent<BoxCollider2D>();
Vector2 worldSize = box != null
? new Vector2(box.size.x * Mathf.Abs(transform.lossyScale.x), box.size.y * Mathf.Abs(transform.lossyScale.y))
: (Vector2)_data.HitboxSize;
int n = Physics2D.OverlapBox(transform.position, worldSize, transform.eulerAngles.z, cf, results);
int damage = Mathf.Max(_data.BaseDamage, 1);
for (int i = 0; i < n; i++)
{
Schedule<EnemyDeath>().enemy = enemy;
var c = results[i];
if (c == null) continue;
var enemy = c.GetComponent<EnemyController>();
if (enemy == null) continue;
var health = c.GetComponent<Health>();
if (health == null || !health.IsAlive) continue;
float last;
if (_lastHitTime.TryGetValue(enemy, out last))
{
if (now - last < interval) continue;
}
_lastHitTime[enemy] = now;
health.DecrementBypassInvulnWithHit(damage);
if (!health.IsAlive)
{
Schedule<EnemyDeath>().enemy = enemy;
}
}
}
}

View File

@ -20,7 +20,7 @@ namespace EerieVillage.Skills.Effectors
if ((data.DotDuration > 0f || data.OnDotFxPrefab != null) && data.DotInterval > 0f)
{
int dotDamage = Mathf.Max(1, Mathf.RoundToInt(data.BaseDamage * data.DotDamageMultiplier));
ApplyDoT(enemy, dotDamage, data.DotDuration, data.DotInterval, data.OnDotFxPrefab);
ApplyDoT(enemy, dotDamage, data.DotDuration, data.DotInterval, data.OnDotFxPrefab, data.DotFxScale);
}
// 기절 (스턴)
@ -52,11 +52,11 @@ namespace EerieVillage.Skills.Effectors
// 내부 헬퍼
// -------------------------------------------------------------------
private static void ApplyDoT(EnemyController enemy, int damagePerTick, float duration, float interval, GameObject fxPrefab = null)
private static void ApplyDoT(EnemyController enemy, int damagePerTick, float duration, float interval, GameObject fxPrefab = null, float fxScale = 1f)
{
var existing = enemy.GetComponent<EnemyDoTState>();
if (existing == null) existing = enemy.gameObject.AddComponent<EnemyDoTState>();
existing.AddDoT(damagePerTick, duration, interval, fxPrefab);
existing.AddDoT(damagePerTick, duration, interval, fxPrefab, fxScale);
}
private static void ApplyStun(EnemyController enemy, float duration)

View File

@ -31,10 +31,17 @@ namespace EerieVillage.Skills.Test
void Awake()
{
_inventory = GetComponent<PlayerSkillInventory>();
EnsureRuntimes();
}
// PD 지시 2026-05-13 — Awake 시점 Inspector reference 미정합 가능성 대비 lazy init.
void EnsureRuntimes()
{
if (_inventory == null) _inventory = GetComponent<PlayerSkillInventory>();
ActiveSkillData[] datas = { Skill1, Skill2, Skill3, Skill4, Skill5 };
for (int i = 0; i < 5; i++)
{
if (_runtimes[i] != null) continue;
if (datas[i] == null) continue;
_runtimes[i] = new ActiveSkillRuntime(datas[i]);
_runtimes[i].OnEquip(_inventory);
@ -43,6 +50,7 @@ namespace EerieVillage.Skills.Test
void Update()
{
EnsureRuntimes();
if (Keyboard.current == null) return;
if (Keyboard.current.digit1Key.wasPressedThisFrame) Fire(0);