diff --git a/Assets/Character/Animations/Hero2.meta b/Assets/Character/Animations/Hero2.meta
new file mode 100644
index 0000000..a44bec2
--- /dev/null
+++ b/Assets/Character/Animations/Hero2.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: fa75e2ac0f9004042beb1fd0e63db5b7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2.overrideController b/Assets/Character/Animations/Hero2/Hero2.overrideController
new file mode 100644
index 0000000..4aa3920
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2.overrideController
@@ -0,0 +1,27 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!221 &22100000
+AnimatorOverrideController:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2
+ m_Controller: {fileID: 9100000, guid: b09e60546065cf9448b36ebb7f759a91, type: 2}
+ m_Clips:
+ - m_OriginalClip: {fileID: 7400000, guid: 712f4510fc9b249348d4d8e97b12dc45, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 337bb548869a6b445b5613c7dfb922da, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: 56811a918221743d69fe84599f43c740, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: c75d6c9ba53c4a544b2994a888fb6357, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: 1d7e02f8cf5ba47a78bc1e19cc378478, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 5664346396fe1d84a9dec390673543b9, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: e0e8baec160e44e1bb74ca8e08777453, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 337bb548869a6b445b5613c7dfb922da, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: c8d7e5a1f9b24e63a7f5d2c8e1b9a4f7, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 34f88233ac11b9149acad25af534d4cc, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: a1b2c3d4e5f6789012345678abcdef01, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 337bb548869a6b445b5613c7dfb922da, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: b2c3d4e5f6789012345678abcdef0102, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 0fb79f0ef462be243aa5a4d2b6aa4f89, type: 2}
+ - m_OriginalClip: {fileID: 7400000, guid: c3d4e5f6789012345678abcdef010203, type: 2}
+ m_OverrideClip: {fileID: 7400000, guid: 337bb548869a6b445b5613c7dfb922da, type: 2}
diff --git a/Assets/Character/Animations/Hero2/Hero2.overrideController.meta b/Assets/Character/Animations/Hero2/Hero2.overrideController.meta
new file mode 100644
index 0000000..45a32ec
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2.overrideController.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7dc53f5b013ff8d49a65bc6d14f88cbf
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 22100000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2_Attack.anim b/Assets/Character/Animations/Hero2/Hero2_Attack.anim
new file mode 100644
index 0000000..9c3d6c4
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Attack.anim
@@ -0,0 +1,81 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2_Attack
+ serializedVersion: 7
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves: []
+ m_PPtrCurves:
+ - serializedVersion: 2
+ curve:
+ - time: 0
+ value: {fileID: 21300000, guid: 13af56d1c9bf3004c9addcdecece8d5c, type: 3}
+ - time: 0.08
+ value: {fileID: 21300000, guid: b28a21fabdc7f264fa4b7b80bacb2af5, type: 3}
+ - time: 0.18
+ value: {fileID: 21300000, guid: a44382e766c8c5e4c92f95f4bd151c0d, type: 3}
+ - time: 0.32
+ value: {fileID: 21300000, guid: a44382e766c8c5e4c92f95f4bd151c0d, type: 3}
+ attribute: m_Sprite
+ path:
+ classID: 212
+ script: {fileID: 0}
+ flags: 2
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 0
+ attribute: 0
+ script: {fileID: 0}
+ typeID: 212
+ customType: 23
+ isPPtrCurve: 1
+ isIntCurve: 0
+ isSerializeReferenceCurve: 0
+ pptrCurveMapping:
+ - {fileID: 21300000, guid: 13af56d1c9bf3004c9addcdecece8d5c, type: 3}
+ - {fileID: 21300000, guid: b28a21fabdc7f264fa4b7b80bacb2af5, type: 3}
+ - {fileID: 21300000, guid: a44382e766c8c5e4c92f95f4bd151c0d, type: 3}
+ - {fileID: 21300000, guid: a44382e766c8c5e4c92f95f4bd151c0d, type: 3}
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0.33666667
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 0
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
diff --git a/Assets/Character/Animations/Hero2/Hero2_Attack.anim.meta b/Assets/Character/Animations/Hero2/Hero2_Attack.anim.meta
new file mode 100644
index 0000000..6438421
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Attack.anim.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 34f88233ac11b9149acad25af534d4cc
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 7400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2_Hit.anim b/Assets/Character/Animations/Hero2/Hero2_Hit.anim
new file mode 100644
index 0000000..dd30426
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Hit.anim
@@ -0,0 +1,75 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2_Hit
+ serializedVersion: 7
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves: []
+ m_PPtrCurves:
+ - serializedVersion: 2
+ curve:
+ - time: 0
+ value: {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ - time: 0.2
+ value: {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ attribute: m_Sprite
+ path:
+ classID: 212
+ script: {fileID: 0}
+ flags: 2
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 0
+ attribute: 0
+ script: {fileID: 0}
+ typeID: 212
+ customType: 23
+ isPPtrCurve: 1
+ isIntCurve: 0
+ isSerializeReferenceCurve: 0
+ pptrCurveMapping:
+ - {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ - {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0.21666667
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 0
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
diff --git a/Assets/Character/Animations/Hero2/Hero2_Hit.anim.meta b/Assets/Character/Animations/Hero2/Hero2_Hit.anim.meta
new file mode 100644
index 0000000..78ad811
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Hit.anim.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0fb79f0ef462be243aa5a4d2b6aa4f89
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 7400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2_Jump.anim b/Assets/Character/Animations/Hero2/Hero2_Jump.anim
new file mode 100644
index 0000000..19643dd
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Jump.anim
@@ -0,0 +1,75 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2_Jump
+ serializedVersion: 7
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves: []
+ m_PPtrCurves:
+ - serializedVersion: 2
+ curve:
+ - time: 0
+ value: {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ - time: 0.083233334
+ value: {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ attribute: m_Sprite
+ path:
+ classID: 212
+ script: {fileID: 0}
+ flags: 2
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 0
+ attribute: 0
+ script: {fileID: 0}
+ typeID: 212
+ customType: 23
+ isPPtrCurve: 1
+ isIntCurve: 0
+ isSerializeReferenceCurve: 0
+ pptrCurveMapping:
+ - {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ - {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0.0999
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 1
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
diff --git a/Assets/Character/Animations/Hero2/Hero2_Jump.anim.meta b/Assets/Character/Animations/Hero2/Hero2_Jump.anim.meta
new file mode 100644
index 0000000..00fe60f
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Jump.anim.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5664346396fe1d84a9dec390673543b9
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 7400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2_Run.anim b/Assets/Character/Animations/Hero2/Hero2_Run.anim
new file mode 100644
index 0000000..f2fd398
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Run.anim
@@ -0,0 +1,90 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2_Run
+ serializedVersion: 7
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves: []
+ m_PPtrCurves:
+ - serializedVersion: 2
+ curve:
+ - time: 0
+ value: {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ - time: 0.083333336
+ value: {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ - time: 0.16666667
+ value: {fileID: 21300000, guid: a463912fc4688394aab70774bae5ef40, type: 3}
+ - time: 0.25
+ value: {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ - time: 0.33333334
+ value: {fileID: 21300000, guid: dd92421615ecd394b91c5558f6d7c833, type: 3}
+ - time: 0.4166667
+ value: {fileID: 21300000, guid: 52fc79783d2c1e241b0b9e2444ea9579, type: 3}
+ - time: 0.4999
+ value: {fileID: 21300000, guid: 52fc79783d2c1e241b0b9e2444ea9579, type: 3}
+ attribute: m_Sprite
+ path:
+ classID: 212
+ script: {fileID: 0}
+ flags: 2
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 0
+ attribute: 0
+ script: {fileID: 0}
+ typeID: 212
+ customType: 23
+ isPPtrCurve: 1
+ isIntCurve: 0
+ isSerializeReferenceCurve: 0
+ pptrCurveMapping:
+ - {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ - {fileID: 21300000, guid: 558d57f72e084f04aae4c0f5b58512fb, type: 3}
+ - {fileID: 21300000, guid: a463912fc4688394aab70774bae5ef40, type: 3}
+ - {fileID: 21300000, guid: 64d67bc6c8db2674bb3b0c8df377bcdf, type: 3}
+ - {fileID: 21300000, guid: dd92421615ecd394b91c5558f6d7c833, type: 3}
+ - {fileID: 21300000, guid: 52fc79783d2c1e241b0b9e2444ea9579, type: 3}
+ - {fileID: 21300000, guid: 52fc79783d2c1e241b0b9e2444ea9579, type: 3}
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0.5165667
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 1
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
diff --git a/Assets/Character/Animations/Hero2/Hero2_Run.anim.meta b/Assets/Character/Animations/Hero2/Hero2_Run.anim.meta
new file mode 100644
index 0000000..807c1e9
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Run.anim.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c75d6c9ba53c4a544b2994a888fb6357
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 7400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Animations/Hero2/Hero2_Still.anim b/Assets/Character/Animations/Hero2/Hero2_Still.anim
new file mode 100644
index 0000000..db765a8
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Still.anim
@@ -0,0 +1,75 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Hero2_Still
+ serializedVersion: 7
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves: []
+ m_PPtrCurves:
+ - serializedVersion: 2
+ curve:
+ - time: 0
+ value: {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ - time: 0.1
+ value: {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ attribute: m_Sprite
+ path:
+ classID: 212
+ script: {fileID: 0}
+ flags: 2
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 0
+ attribute: 0
+ script: {fileID: 0}
+ typeID: 212
+ customType: 23
+ isPPtrCurve: 1
+ isIntCurve: 0
+ isSerializeReferenceCurve: 0
+ pptrCurveMapping:
+ - {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ - {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0.11666667
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 1
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
diff --git a/Assets/Character/Animations/Hero2/Hero2_Still.anim.meta b/Assets/Character/Animations/Hero2/Hero2_Still.anim.meta
new file mode 100644
index 0000000..8665091
--- /dev/null
+++ b/Assets/Character/Animations/Hero2/Hero2_Still.anim.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 337bb548869a6b445b5613c7dfb922da
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 7400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2.meta b/Assets/Character/Sprites/Hero2.meta
new file mode 100644
index 0000000..c00820f
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: baa8597614350e84f9176635e9f6c8a8
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_01.png b/Assets/Character/Sprites/Hero2/hero2_attack_01.png
new file mode 100644
index 0000000..0d906c0
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_attack_01.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_01.png.meta b/Assets/Character/Sprites/Hero2/hero2_attack_01.png.meta
new file mode 100644
index 0000000..05039e0
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_attack_01.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: 13af56d1c9bf3004c9addcdecece8d5c
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 6135626975730281620
+ second: hero2_attack_01_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_attack_01_0
+ rect:
+ serializedVersion: 2
+ x: 53
+ y: 7
+ width: 162
+ height: 215
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 49c25baf930262550800000000000000
+ internalID: 6135626975730281620
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_attack_01_0: 6135626975730281620
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_02.png b/Assets/Character/Sprites/Hero2/hero2_attack_02.png
new file mode 100644
index 0000000..3e2fb46
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_attack_02.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_02.png.meta b/Assets/Character/Sprites/Hero2/hero2_attack_02.png.meta
new file mode 100644
index 0000000..71513eb
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_attack_02.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: b28a21fabdc7f264fa4b7b80bacb2af5
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -4555075445918632043
+ second: hero2_attack_02_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_attack_02_0
+ rect:
+ serializedVersion: 2
+ x: 41
+ y: 7
+ width: 193
+ height: 210
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 5977ae8040f19c0c0800000000000000
+ internalID: -4555075445918632043
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_attack_02_0: -4555075445918632043
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_03.png b/Assets/Character/Sprites/Hero2/hero2_attack_03.png
new file mode 100644
index 0000000..31398cf
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_attack_03.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_attack_03.png.meta b/Assets/Character/Sprites/Hero2/hero2_attack_03.png.meta
new file mode 100644
index 0000000..b0157db
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_attack_03.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: a44382e766c8c5e4c92f95f4bd151c0d
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -6164578762513089740
+ second: hero2_attack_03_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_attack_03_0
+ rect:
+ serializedVersion: 2
+ x: 4
+ y: 7
+ width: 215
+ height: 208
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 43b7d7ed644037aa0800000000000000
+ internalID: -6164578762513089740
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_attack_03_0: -6164578762513089740
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_import.json b/Assets/Character/Sprites/Hero2/hero2_import.json
new file mode 100644
index 0000000..29fa9f2
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_import.json
@@ -0,0 +1,50 @@
+{
+ "note": "Hero2 import SOT — finalize_frames.py 산출 (2026-11-10)",
+ "canvas": [
+ 254,
+ 234
+ ],
+ "anchor_px_from_top_left": [
+ 129.8,
+ 225.0
+ ],
+ "ppu": 205,
+ "old_visible_height_px": 313.5,
+ "old_ppu": 300.0,
+ "new_visible_height_px": 214.0,
+ "clips": {
+ "run": {
+ "frames": [
+ "hero2_run_01",
+ "hero2_run_02",
+ "hero2_run_03",
+ "hero2_run_04",
+ "hero2_run_05",
+ "hero2_run_06"
+ ],
+ "fps": 12,
+ "loop": true
+ },
+ "attack": {
+ "frames": [
+ "hero2_attack_01",
+ "hero2_attack_02",
+ "hero2_attack_03"
+ ],
+ "times": [
+ 0.0,
+ 0.08,
+ 0.18
+ ],
+ "length": 0.32,
+ "loop": false
+ },
+ "jump": {
+ "frames": [
+ "hero2_run_04"
+ ],
+ "fps": 12,
+ "loop": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Character/Sprites/Hero2/hero2_import.json.meta b/Assets/Character/Sprites/Hero2/hero2_import.json.meta
new file mode 100644
index 0000000..367e388
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_import.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2a10a7a14aaaf234296ef8cef13288f4
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_01.png b/Assets/Character/Sprites/Hero2/hero2_run_01.png
new file mode 100644
index 0000000..bcc5bf6
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_01.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_01.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_01.png.meta
new file mode 100644
index 0000000..4e8d952
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_01.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: d0ef15db1d7cfe942833a436e709d5de
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 4594355425956087001
+ second: hero2_run_01_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_01_0
+ rect:
+ serializedVersion: 2
+ x: 34
+ y: 5
+ width: 197
+ height: 224
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 9d440000bed62cf30800000000000000
+ internalID: 4594355425956087001
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_01_0: 4594355425956087001
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_02.png b/Assets/Character/Sprites/Hero2/hero2_run_02.png
new file mode 100644
index 0000000..62d9cad
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_02.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_02.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_02.png.meta
new file mode 100644
index 0000000..4cbba09
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_02.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: 558d57f72e084f04aae4c0f5b58512fb
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -8171492585566603228
+ second: hero2_run_02_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_02_0
+ rect:
+ serializedVersion: 2
+ x: 30
+ y: 7
+ width: 214
+ height: 216
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 4287090b9c6099e80800000000000000
+ internalID: -8171492585566603228
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_02_0: -8171492585566603228
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_03.png b/Assets/Character/Sprites/Hero2/hero2_run_03.png
new file mode 100644
index 0000000..62d9cad
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_03.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_03.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_03.png.meta
new file mode 100644
index 0000000..c26c1bd
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_03.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: a463912fc4688394aab70774bae5ef40
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -7297110809570715322
+ second: hero2_run_03_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_03_0
+ rect:
+ serializedVersion: 2
+ x: 30
+ y: 7
+ width: 214
+ height: 216
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 649dfd461647bba90800000000000000
+ internalID: -7297110809570715322
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_03_0: -7297110809570715322
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_04.png b/Assets/Character/Sprites/Hero2/hero2_run_04.png
new file mode 100644
index 0000000..36b6c35
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_04.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_04.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_04.png.meta
new file mode 100644
index 0000000..5110d33
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_04.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: 64d67bc6c8db2674bb3b0c8df377bcdf
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 4643626016116899493
+ second: hero2_run_04_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_04_0
+ rect:
+ serializedVersion: 2
+ x: 28
+ y: 13
+ width: 221
+ height: 216
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 5aef8683249717040800000000000000
+ internalID: 4643626016116899493
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_04_0: 4643626016116899493
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_05.png b/Assets/Character/Sprites/Hero2/hero2_run_05.png
new file mode 100644
index 0000000..32efa95
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_05.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_05.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_05.png.meta
new file mode 100644
index 0000000..c8ab5e4
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_05.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: dd92421615ecd394b91c5558f6d7c833
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -4788721669207052375
+ second: hero2_run_05_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_05_0
+ rect:
+ serializedVersion: 2
+ x: 31
+ y: 7
+ width: 203
+ height: 214
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 9afa2ba730b0b8db0800000000000000
+ internalID: -4788721669207052375
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_05_0: -4788721669207052375
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_06.png b/Assets/Character/Sprites/Hero2/hero2_run_06.png
new file mode 100644
index 0000000..0871a4d
Binary files /dev/null and b/Assets/Character/Sprites/Hero2/hero2_run_06.png differ
diff --git a/Assets/Character/Sprites/Hero2/hero2_run_06.png.meta b/Assets/Character/Sprites/Hero2/hero2_run_06.png.meta
new file mode 100644
index 0000000..8b4ccbe
--- /dev/null
+++ b/Assets/Character/Sprites/Hero2/hero2_run_06.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: 52fc79783d2c1e241b0b9e2444ea9579
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 2364528057764446928
+ second: hero2_run_06_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.51102364, y: 0.3984499}
+ spritePixelsToUnits: 205
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: hero2_run_06_0
+ rect:
+ serializedVersion: 2
+ x: 33
+ y: 5
+ width: 198
+ height: 219
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 0d28e70adbd70d020800000000000000
+ internalID: 2364528057764446928
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ hero2_run_06_0: 2364528057764446928
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Editor/Renewal.meta b/Assets/Editor/Renewal.meta
new file mode 100644
index 0000000..12ca649
--- /dev/null
+++ b/Assets/Editor/Renewal.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 59d58f08c16a66b459625dd4537d0251
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Editor/Renewal/BackdropRenewalSetup.cs b/Assets/Editor/Renewal/BackdropRenewalSetup.cs
new file mode 100644
index 0000000..a02b11b
--- /dev/null
+++ b/Assets/Editor/Renewal/BackdropRenewalSetup.cs
@@ -0,0 +1,138 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using EerieVillage.Background;
+using Unity.Cinemachine;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+
+///
+/// 리뉴얼 2026-11-10 (PD 지시) — ComfyUI 로 만든 이음매 없는 마을 배경(2층)을 Ingame 씬에 무한 스크롤로 깐다.
+/// 층 정보 SOT = Assets/Environment/Backdrop/backdrop_layers.json (make_layers.py 산출 · 파일 · 높이 px · 발 디딤선 · 시차 · 정렬).
+/// 배율(px/월드)은 씬의 실제 땅 높이 · 카메라 범위에서 계산한다(값 중복 없음).
+///
+public static class BackdropRenewalSetup
+{
+ const string Dir = "Assets/Environment/Backdrop";
+ const string ScenePath = "Assets/Scenes/Ingame.unity";
+ const string RootName = "Backdrop_EerieVillage";
+
+ [System.Serializable] class Layer { public string file; public float height_px; public float walk_v; public float parallax; public int sorting_order; }
+ [System.Serializable] class Layers { public Layer far, ground; }
+ [System.Serializable] class Cfg { public float tile_width_px; public Layers layers; public float camera_margin_world; }
+
+ static Cfg LoadCfg() => JsonUtility.FromJson(File.ReadAllText(Path.Combine(Dir, "backdrop_layers.json")));
+
+ [MenuItem("Tools/Renewal/4. Backdrop Import Settings")]
+ public static string ImportTexture()
+ {
+ var cfg = LoadCfg();
+ var log = new List();
+ foreach (var l in new[] { cfg.layers.far, cfg.layers.ground })
+ {
+ string path = $"{Dir}/{l.file}";
+ var ti = (TextureImporter)AssetImporter.GetAtPath(path);
+ ti.textureType = TextureImporterType.Sprite;
+ ti.spriteImportMode = SpriteImportMode.Single;
+ var s = new TextureImporterSettings();
+ ti.ReadTextureSettings(s);
+ s.spriteAlignment = (int)SpriteAlignment.Center;
+ s.spriteMeshType = SpriteMeshType.FullRect;
+ s.mipmapEnabled = false;
+ s.wrapMode = TextureWrapMode.Clamp;
+ s.filterMode = FilterMode.Bilinear;
+ s.alphaIsTransparency = true;
+ ti.SetTextureSettings(s);
+ ti.maxTextureSize = 4096;
+ ti.textureCompression = TextureImporterCompression.CompressedHQ;
+ ti.SaveAndReimport();
+ var sp = AssetDatabase.LoadAssetAtPath(path);
+ log.Add($"{l.file} {sp?.rect.width}x{sp?.rect.height}");
+ }
+ return string.Join(" | ", log);
+ }
+
+ /// 현재 열린 씬의 기존 배경 후보(무한 배경·패럴랙스·이름에 Background) 목록.
+ public static string ListOldBackgrounds()
+ {
+ var rows = new List();
+ foreach (var go in Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).Select(t => t.gameObject))
+ {
+ bool hit = go.GetComponent() || go.GetComponent() || go.GetComponent()
+ || go.GetComponent("ParallaxLayer") || go.name.ToLower().Contains("background") || go.name.ToLower().Contains("bg");
+ if (!hit) continue;
+ var sr = go.GetComponent();
+ string comps = string.Join(",", go.GetComponents().Where(c => c != null && !(c is Transform)).Select(c => c.GetType().Name));
+ rows.Add($"{GetPath(go.transform)} [{(go.activeInHierarchy ? "on" : "off")}] {comps}" +
+ (sr ? $" layer={sr.sortingLayerName}/{sr.sortingOrder}" : ""));
+ }
+ return string.Join("\n", rows);
+ }
+
+ static string GetPath(Transform t) => t.parent == null ? t.name : GetPath(t.parent) + "/" + t.name;
+
+ ///
+ /// 배경 2층을 만들고(있으면 갱신) 지정한 기존 배경 오브젝트는 끈다. 씬 저장까지.
+ /// 배율 = 먼 층 위 끝이 카메라 최고 높이를, 흙길 층 아래 끝이 카메라 최저 높이를 덮는 가장 작은 배경 크기.
+ ///
+ public static string SetupScene(string[] disablePaths)
+ {
+ var scene = EditorSceneManager.GetActiveScene();
+ if (scene.path != ScenePath) scene = EditorSceneManager.OpenScene(ScenePath);
+ var cfg = LoadCfg();
+ var log = new List();
+ foreach (var p in disablePaths)
+ {
+ var go = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)
+ .Select(t => t.gameObject).FirstOrDefault(g => GetPath(g.transform) == p);
+ if (go == null) { log.Add($"없음: {p}"); continue; }
+ Undo.RecordObject(go, "Disable old background");
+ go.SetActive(false);
+ log.Add($"끔: {p}");
+ }
+
+ // 실제 땅 윗면(무한 지면 콜라이더) · 카메라 세로 범위(시작 높이 · Confiner 위 끝)
+ var ground = Object.FindFirstObjectByType();
+ float groundY = ground.GetComponent().bounds.max.y;
+ var cam = Camera.main;
+ float camBottom = cam.transform.position.y - cam.orthographicSize;
+ float camTop = cam.transform.position.y + cam.orthographicSize;
+ var confiner = Object.FindFirstObjectByType();
+ if (confiner != null && confiner.BoundingShape2D is PolygonCollider2D poly && poly.enabled)
+ camTop = Mathf.Max(camTop, poly.bounds.max.y);
+ float m = cfg.camera_margin_world;
+ var far = cfg.layers.far; var gnd = cfg.layers.ground;
+ float kTop = far.height_px * (1f - far.walk_v) / (camTop - groundY + m);
+ float kBottom = gnd.height_px * gnd.walk_v / (groundY - camBottom + m);
+ float k = Mathf.Min(kTop, kBottom);
+ log.Add($"땅 {groundY:F2} · 카메라 {camBottom:F2}~{camTop:F2} · px/월드 {k:F1} (위 {kTop:F1} · 아래 {kBottom:F1})");
+
+ MakeLayer(RootName, far, k, groundY, cam, log);
+ MakeLayer(RootName + "_Ground", gnd, k, groundY, cam, log);
+ EditorSceneManager.MarkSceneDirty(scene);
+ EditorSceneManager.SaveScene(scene);
+ return string.Join("\n", log);
+ }
+
+ static void MakeLayer(string goName, Layer l, float k, float groundY, Camera cam, List log)
+ {
+ var root = GameObject.Find(goName);
+ if (root == null) root = new GameObject(goName);
+ root.transform.position = new Vector3(cam.transform.position.x, groundY, 10f);
+ var sr = root.GetComponent();
+ if (sr == null) sr = root.AddComponent();
+ sr.sprite = AssetDatabase.LoadAssetAtPath($"{Dir}/{l.file}");
+ sr.sortingLayerName = "Default";
+ sr.sortingOrder = l.sorting_order;
+ var lb = root.GetComponent();
+ if (lb == null) lb = root.AddComponent();
+ lb.parallax = l.parallax;
+ lb.pixelsPerWorldUnit = k;
+ lb.anchorImageV = l.walk_v;
+ lb.anchorWorldY = groundY;
+ lb.verticalFollow = 0f;
+ EditorUtility.SetDirty(lb);
+ log.Add($"{goName}: {l.file} 시차 {l.parallax} 정렬 {l.sorting_order} 높이 {l.height_px / k:F2}");
+ }
+}
diff --git a/Assets/Editor/Renewal/BackdropRenewalSetup.cs.meta b/Assets/Editor/Renewal/BackdropRenewalSetup.cs.meta
new file mode 100644
index 0000000..f70eb42
--- /dev/null
+++ b/Assets/Editor/Renewal/BackdropRenewalSetup.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c0696e3a558af1d4bba5b045880ef303
\ No newline at end of file
diff --git a/Assets/Editor/Renewal/Hero2RenewalSetup.cs b/Assets/Editor/Renewal/Hero2RenewalSetup.cs
new file mode 100644
index 0000000..4b9b908
--- /dev/null
+++ b/Assets/Editor/Renewal/Hero2RenewalSetup.cs
@@ -0,0 +1,171 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Platformer.Gameplay;
+using Platformer.Mechanics;
+using UnityEditor;
+using UnityEditor.Animations;
+using UnityEngine;
+
+///
+/// 리뉴얼 2026-11-10 (PD 지시) — 새 캐릭터(Hero2) 스프라이트 교체 + 근접 자동 공격 부착.
+/// 값 SOT = Assets/Character/Sprites/Hero2/hero2_import.json (finalize_frames.py 산출 · 캔버스·기준점·PPU·클립 구성).
+/// 발 위치 = Player 프리팹 콜라이더 바닥에서 계산(값 중복 없음).
+///
+public static class Hero2RenewalSetup
+{
+ const string Hero2Dir = "Assets/Character/Sprites/Hero2";
+ const string ClipDir = "Assets/Character/Animations/Hero2";
+ const string PlayerPrefab = "Assets/Prefabs/Player.prefab";
+ const string BaseController = "Assets/Character/Animations/Player.controller";
+ const string OverridePath = "Assets/Character/Animations/Hero2/Hero2.overrideController";
+
+ [System.Serializable] class ClipCfg { public string[] frames; public float fps; public bool loop; public float[] times; public float length; }
+ [System.Serializable] class ClipSet { public ClipCfg run, attack, jump; }
+ [System.Serializable] class ImportCfg { public int[] canvas; public float[] anchor_px_from_top_left; public float ppu; public ClipSet clips; }
+
+ static ImportCfg LoadCfg() => JsonUtility.FromJson(File.ReadAllText(Path.Combine(Hero2Dir, "hero2_import.json")));
+
+ /// 프리팹 콜라이더 바닥(로컬 y, 스케일 적용 전).
+ static float ColliderBottomLocal(GameObject root)
+ {
+ var box = root.GetComponent();
+ if (box != null) return box.offset.y - box.size.y * 0.5f - box.edgeRadius;
+ var cap = root.GetComponent();
+ if (cap != null) return cap.offset.y - cap.size.y * 0.5f;
+ var circle = root.GetComponent();
+ if (circle != null) return circle.offset.y - circle.radius;
+ throw new System.Exception("Player 콜라이더를 찾지 못함");
+ }
+
+ [MenuItem("Tools/Renewal/1. Hero2 Import Settings")]
+ public static string ImportSprites()
+ {
+ var cfg = LoadCfg();
+ var prefab = AssetDatabase.LoadAssetAtPath(PlayerPrefab);
+ float feetLocal = ColliderBottomLocal(prefab);
+ float W = cfg.canvas[0], H = cfg.canvas[1];
+ float ax = cfg.anchor_px_from_top_left[0], ay = cfg.anchor_px_from_top_left[1];
+ // 발 픽셀 행(ay, 위에서) 이 콜라이더 바닥(feetLocal) 에 오도록 기준점 y 를 정한다.
+ var pivot = new Vector2(ax / W, (H - ay - feetLocal * cfg.ppu) / H);
+ int n = 0;
+ foreach (var guid in AssetDatabase.FindAssets("t:Texture2D", new[] { Hero2Dir }))
+ {
+ var path = AssetDatabase.GUIDToAssetPath(guid);
+ var ti = (TextureImporter)AssetImporter.GetAtPath(path);
+ ti.textureType = TextureImporterType.Sprite;
+ ti.spriteImportMode = SpriteImportMode.Single;
+ var s = new TextureImporterSettings();
+ ti.ReadTextureSettings(s);
+ s.spriteAlignment = (int)SpriteAlignment.Custom;
+ s.spritePivot = pivot;
+ s.spritePixelsPerUnit = cfg.ppu;
+ s.spriteMeshType = SpriteMeshType.FullRect;
+ s.alphaIsTransparency = true;
+ s.mipmapEnabled = false;
+ s.filterMode = FilterMode.Bilinear;
+ s.wrapMode = TextureWrapMode.Clamp;
+ ti.SetTextureSettings(s);
+ ti.textureCompression = TextureImporterCompression.CompressedHQ;
+ ti.SaveAndReimport();
+ n++;
+ }
+ return $"import {n} sprites · ppu {cfg.ppu} · pivot {pivot.x:F4},{pivot.y:F4} · feetLocal {feetLocal:F4}";
+ }
+
+ static Sprite S(string name) => AssetDatabase.LoadAssetAtPath($"{Hero2Dir}/{name}.png");
+
+ static AnimationClip MakeClip(string clipName, string[] frames, float[] times, float length, bool loop)
+ {
+ Directory.CreateDirectory(ClipDir);
+ string path = $"{ClipDir}/{clipName}.anim";
+ var clip = AssetDatabase.LoadAssetAtPath(path);
+ if (clip == null) { clip = new AnimationClip { frameRate = 60 }; AssetDatabase.CreateAsset(clip, path); }
+ clip.ClearCurves();
+ var binding = EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite");
+ var keys = new List();
+ for (int i = 0; i < frames.Length; i++) keys.Add(new ObjectReferenceKeyframe { time = times[i], value = S(frames[i]) });
+ // 마지막 프레임을 끝 시각까지 유지(클립 길이 = length)
+ keys.Add(new ObjectReferenceKeyframe { time = length, value = S(frames[frames.Length - 1]) });
+ AnimationUtility.SetObjectReferenceCurve(clip, binding, keys.ToArray());
+ var st = AnimationUtility.GetAnimationClipSettings(clip);
+ st.loopTime = loop;
+ AnimationUtility.SetAnimationClipSettings(clip, st);
+ EditorUtility.SetDirty(clip);
+ return clip;
+ }
+
+ static AnimationClip MakeFpsClip(string clipName, ClipCfg c)
+ {
+ float dt = 1f / c.fps;
+ var times = Enumerable.Range(0, c.frames.Length).Select(i => i * dt).ToArray();
+ // 반복 클립은 마지막 키를 한 칸 뒤(= 첫 프레임 직전)에 두어 모든 프레임이 같은 시간 보이게 한다.
+ return MakeClip(clipName, c.frames, times, c.frames.Length * dt - (c.loop ? 0.0001f : 0f), c.loop);
+ }
+
+ [MenuItem("Tools/Renewal/2. Hero2 Clips + Override")]
+ public static string BuildAnimation()
+ {
+ var cfg = LoadCfg();
+ var run = MakeFpsClip("Hero2_Run", cfg.clips.run);
+ var attack = MakeClip("Hero2_Attack", cfg.clips.attack.frames, cfg.clips.attack.times, cfg.clips.attack.length, false);
+ var jump = MakeFpsClip("Hero2_Jump", cfg.clips.jump);
+ // 대기·피격·사망·부활 전용 그림은 아직 없다 → 달리기 첫 프레임 정지 그림으로 대신(보고에 명시).
+ var still = MakeClip("Hero2_Still", new[] { cfg.clips.run.frames[0] }, new[] { 0f }, 0.1f, true);
+ var hit = MakeClip("Hero2_Hit", new[] { cfg.clips.run.frames[1] }, new[] { 0f }, 0.2f, false);
+
+ var baseCtrl = AssetDatabase.LoadAssetAtPath(BaseController);
+ var ov = AssetDatabase.LoadAssetAtPath(OverridePath);
+ if (ov == null) { ov = new AnimatorOverrideController(baseCtrl); AssetDatabase.CreateAsset(ov, OverridePath); }
+ ov.runtimeAnimatorController = baseCtrl;
+
+ var byState = new Dictionary
+ {
+ { "Player-Run", run }, { "Player-Attack", attack }, { "Player-Jump", jump },
+ { "Player-Idle", still }, { "Player-CombatIdle", still }, { "Player-Hit", hit },
+ { "Player-Death", still }, { "Player-Resurrection", still },
+ };
+ var pairs = new List>();
+ var log = new List();
+ foreach (var cs in baseCtrl.layers[0].stateMachine.states)
+ {
+ var orig = cs.state.motion as AnimationClip;
+ if (orig == null) { log.Add($"{cs.state.name}: (클립 아님)"); continue; }
+ if (byState.TryGetValue(cs.state.name, out var nc)) { pairs.Add(new KeyValuePair(orig, nc)); log.Add($"{cs.state.name}: {orig.name}->{nc.name}"); }
+ else log.Add($"{cs.state.name}: {orig.name} (그대로)");
+ }
+ ov.ApplyOverrides(pairs);
+ EditorUtility.SetDirty(ov);
+ AssetDatabase.SaveAssets();
+ return string.Join(" | ", log);
+ }
+
+ [MenuItem("Tools/Renewal/3. Apply Hero2 To Player Prefab")]
+ public static string ApplyToPrefab()
+ {
+ var root = PrefabUtility.LoadPrefabContents(PlayerPrefab);
+ try
+ {
+ var cfg = LoadCfg();
+ var sr = root.GetComponent();
+ sr.sprite = S(cfg.clips.run.frames[0]);
+ var anim = root.GetComponent();
+ anim.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath(OverridePath);
+ var pc = root.GetComponent();
+ pc.autoRun = true;
+ var ticker = root.GetComponent();
+ if (ticker == null) ticker = root.AddComponent();
+ ticker.onlyWhenEnemyNear = true;
+ if (pc.attackHitbox == null) pc.attackHitbox = root.GetComponent();
+ PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefab);
+ }
+ finally { PrefabUtility.UnloadPrefabContents(root); }
+ // 기본 그림은 프리팹 편집 장면에서 저장되지 않는 경우가 있어(2026-11-10 실측) 에셋에 직접 한 번 더 넣는다.
+ var asset = AssetDatabase.LoadAssetAtPath(PlayerPrefab);
+ var assetSr = asset.GetComponent();
+ var first = S(LoadCfg().clips.run.frames[0]);
+ if (assetSr.sprite != first) { assetSr.sprite = first; EditorUtility.SetDirty(asset); PrefabUtility.SavePrefabAsset(asset); }
+ var a2 = asset.GetComponent();
+ return $"prefab ok · sprite {assetSr.sprite?.name} · ctrl {a2.runtimeAnimatorController?.name} · ticker {asset.GetComponent() != null}";
+ }
+}
diff --git a/Assets/Editor/Renewal/Hero2RenewalSetup.cs.meta b/Assets/Editor/Renewal/Hero2RenewalSetup.cs.meta
new file mode 100644
index 0000000..34cfc3a
--- /dev/null
+++ b/Assets/Editor/Renewal/Hero2RenewalSetup.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 973c500806fa393478207d518219c68b
\ No newline at end of file
diff --git a/Assets/Editor/Renewal/RunnerRenewalSetup.cs b/Assets/Editor/Renewal/RunnerRenewalSetup.cs
new file mode 100644
index 0000000..dcc20f4
--- /dev/null
+++ b/Assets/Editor/Renewal/RunnerRenewalSetup.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+using Platformer.Mechanics;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+
+///
+/// 리뉴얼 2026-11-10 (PD 지시 「무한 스크롤 중 적은 새로 스크롤되는 화면에 랜덤 등장」) —
+/// Ingame 씬의 미리 놓인 적을 끄고 무한 적 생성기를 둔다. 생성 프리팹 = 미리 놓인 적들의 원본 프리팹.
+///
+public static class RunnerRenewalSetup
+{
+ const string ScenePath = "Assets/Scenes/Ingame.unity";
+ const string SpawnerName = "EnemySpawner_Endless";
+
+ [MenuItem("Tools/Renewal/5. Endless Enemy Spawner")]
+ public static string SetupSpawner()
+ {
+ var scene = EditorSceneManager.GetActiveScene();
+ if (scene.path != ScenePath) scene = EditorSceneManager.OpenScene(ScenePath);
+ var enemies = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None);
+ var sources = new Dictionary();
+ var prefabs = new List();
+ foreach (var e in enemies)
+ {
+ var src = PrefabUtility.GetCorrespondingObjectFromSource(e.gameObject);
+ string path = src != null ? AssetDatabase.GetAssetPath(src) : "(프리팹 아님)";
+ sources[path] = sources.TryGetValue(path, out var n) ? n + 1 : 1;
+ if (src != null && !prefabs.Contains(src)) prefabs.Add(src);
+ Undo.RecordObject(e.gameObject, "Disable placed enemy");
+ e.gameObject.SetActive(false);
+ }
+ var root = GameObject.Find(SpawnerName);
+ if (root == null) root = new GameObject(SpawnerName);
+ var sp = root.GetComponent();
+ if (sp == null) sp = root.AddComponent();
+ sp.enemyPrefabs = prefabs.OrderBy(p => p.name).ToArray();
+ EditorUtility.SetDirty(sp);
+ EditorSceneManager.MarkSceneDirty(scene);
+ EditorSceneManager.SaveScene(scene);
+ return $"미리 놓인 적 {enemies.Length} 끔 · 원본 프리팹: " + string.Join(", ", sources.Select(kv => $"{kv.Key}×{kv.Value}")) +
+ $" · 생성기 프리팹 {sp.enemyPrefabs.Length}종";
+ }
+}
diff --git a/Assets/Editor/Renewal/RunnerRenewalSetup.cs.meta b/Assets/Editor/Renewal/RunnerRenewalSetup.cs.meta
new file mode 100644
index 0000000..316ef75
--- /dev/null
+++ b/Assets/Editor/Renewal/RunnerRenewalSetup.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 27796c6cf234b81498113feab3dfe594
\ No newline at end of file
diff --git a/Assets/Environment/Backdrop.meta b/Assets/Environment/Backdrop.meta
new file mode 100644
index 0000000..b89f5ed
--- /dev/null
+++ b/Assets/Environment/Backdrop.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 041bd918d5ff5da418bf0bca18cd13d5
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Environment/Backdrop/backdrop_layers.json b/Assets/Environment/Backdrop/backdrop_layers.json
new file mode 100644
index 0000000..ef71164
--- /dev/null
+++ b/Assets/Environment/Backdrop/backdrop_layers.json
@@ -0,0 +1,21 @@
+{
+ "note": "수상한 고을 배경 2층 (2026-11-10 · make_layers.py)",
+ "tile_width_px": 3584,
+ "layers": {
+ "far": {
+ "file": "bg_eerie_village_tile.png",
+ "height_px": 1536,
+ "walk_v": 0.10026,
+ "parallax": 0.4,
+ "sorting_order": -100
+ },
+ "ground": {
+ "file": "bg_eerie_ground.png",
+ "height_px": 316,
+ "walk_v": 0.89241,
+ "parallax": 1.0,
+ "sorting_order": -99
+ }
+ },
+ "camera_margin_world": 0.4
+}
\ No newline at end of file
diff --git a/Assets/Environment/Backdrop/backdrop_layers.json.meta b/Assets/Environment/Backdrop/backdrop_layers.json.meta
new file mode 100644
index 0000000..511fe34
--- /dev/null
+++ b/Assets/Environment/Backdrop/backdrop_layers.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 91b3d4c218d56be46982faba8762813a
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Environment/Backdrop/bg_eerie_ground.png b/Assets/Environment/Backdrop/bg_eerie_ground.png
new file mode 100644
index 0000000..737afdb
Binary files /dev/null and b/Assets/Environment/Backdrop/bg_eerie_ground.png differ
diff --git a/Assets/Environment/Backdrop/bg_eerie_ground.png.meta b/Assets/Environment/Backdrop/bg_eerie_ground.png.meta
new file mode 100644
index 0000000..a637559
--- /dev/null
+++ b/Assets/Environment/Backdrop/bg_eerie_ground.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: 73edcbbe2553d20408ee98c2065d29e6
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 1890837388944703917
+ second: bg_eerie_ground_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 4096
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: bg_eerie_ground_0
+ rect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 3584
+ height: 316
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: da18310569a9d3a10800000000000000
+ internalID: 1890837388944703917
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ bg_eerie_ground_0: 1890837388944703917
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Environment/Backdrop/bg_eerie_village_tile.png b/Assets/Environment/Backdrop/bg_eerie_village_tile.png
new file mode 100644
index 0000000..7b1f29c
Binary files /dev/null and b/Assets/Environment/Backdrop/bg_eerie_village_tile.png differ
diff --git a/Assets/Environment/Backdrop/bg_eerie_village_tile.png.meta b/Assets/Environment/Backdrop/bg_eerie_village_tile.png.meta
new file mode 100644
index 0000000..6cd872b
--- /dev/null
+++ b/Assets/Environment/Backdrop/bg_eerie_village_tile.png.meta
@@ -0,0 +1,169 @@
+fileFormatVersion: 2
+guid: cf32ef17b2aef6d48b55a7bcc26457f7
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -7533943643031670097
+ second: bg_eerie_village_tile_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 4096
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 2
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: bg_eerie_village_tile_0
+ rect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 3584
+ height: 1536
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: fa2f8475c2e027790800000000000000
+ internalID: -7533943643031670097
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable:
+ bg_eerie_village_tile_0: -7533943643031670097
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab
index 59b9dcd..e0fba2d 100644
--- a/Assets/Prefabs/Player.prefab
+++ b/Assets/Prefabs/Player.prefab
@@ -18,6 +18,7 @@ GameObject:
- component: {fileID: 1824045667}
- component: {fileID: 7700000000000000001}
- component: {fileID: 7700000000000000004}
+ - component: {fileID: 5396725966993708724}
m_Layer: 13
m_Name: Player
m_TagString: Player
@@ -62,12 +63,15 @@ MonoBehaviour:
attackAudio: {fileID: 0}
maxSpeed: 3
jumpTakeOffSpeed: 7
- attackHitbox: {fileID: 0}
+ attackHitbox: {fileID: 7700000000000000001}
jumpState: 0
+ maxJumps: 2
collider2d: {fileID: 0}
audioSource: {fileID: 0}
health: {fileID: 0}
controlEnabled: 1
+ autoRun: 1
+ autoRunDirection: 1
--- !u!212 &212064061491315838
SpriteRenderer:
serializedVersion: 2
@@ -117,8 +121,7 @@ SpriteRenderer:
m_SortingLayer: 0
m_SortingOrder: 5
m_MaskInteraction: 0
- m_Sprite: {fileID: -7999245345599557054, guid: 78c7da0e2fc366543ae4ad5e3ceb1b94,
- type: 3}
+ m_Sprite: {fileID: 21300000, guid: d0ef15db1d7cfe942833a436e709d5de, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 1
m_FlipY: 0
@@ -138,7 +141,7 @@ Animator:
m_GameObject: {fileID: 1208144871472054}
m_Enabled: 1
m_Avatar: {fileID: 0}
- m_Controller: {fileID: 9100000, guid: b09e60546065cf9448b36ebb7f759a91, type: 2}
+ m_Controller: {fileID: 22100000, guid: 7dc53f5b013ff8d49a65bc6d14f88cbf, type: 2}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
@@ -329,8 +332,8 @@ BoxCollider2D:
m_Offset: {x: 0.03327547, y: -0.15880941}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
- pivot: {x: 0.5, y: 0.5}
- oldSize: {x: 0.6566667, y: 1.1033334}
+ pivot: {x: 0.51102364, y: 0.3984499}
+ oldSize: {x: 1.2390244, y: 1.1414634}
newSize: {x: 1.28, y: 1.26}
adaptiveTilingThreshold: 0.5
drawMode: 0
@@ -370,3 +373,20 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
combatIdleDuration: 5
+--- !u!114 &5396725966993708724
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1208144871472054}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: c7d8e9f0a1b20314253647586978a9b0, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::Platformer.Gameplay.PlayerAttackTicker
+ attackInterval: 0.5
+ startupDelay: 0.3
+ onlyWhenEnemyNear: 1
+ detectLead: 0.6
+ detectHeight: 1.4
diff --git a/Assets/Scenes/Ingame.unity b/Assets/Scenes/Ingame.unity
index 96d7492..bcf1663 100644
--- a/Assets/Scenes/Ingame.unity
+++ b/Assets/Scenes/Ingame.unity
@@ -5168,6 +5168,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M001_Wolf
objectReference: {fileID: 0}
+ - target: {fileID: 6504999383530317407, guid: 9c65c4487bc1dba448954dd4c349a574,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 6508303935943450553, guid: 9c65c4487bc1dba448954dd4c349a574,
type: 3}
propertyPath: m_LocalPosition.x
@@ -5395,6 +5400,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M006_Spider
objectReference: {fileID: 0}
+ - target: {fileID: 1352356591422558597, guid: ae920194bcfccc94193aa9849a5c43a3,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 1355808528257542243, guid: ae920194bcfccc94193aa9849a5c43a3,
type: 3}
propertyPath: m_LocalPosition.x
@@ -19094,6 +19104,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M006_Spider
objectReference: {fileID: 0}
+ - target: {fileID: 1352356591422558597, guid: ae920194bcfccc94193aa9849a5c43a3,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 1355808528257542243, guid: ae920194bcfccc94193aa9849a5c43a3,
type: 3}
propertyPath: m_LocalPosition.x
@@ -120409,6 +120424,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M005_Ghost
objectReference: {fileID: 0}
+ - target: {fileID: 7848113793813235637, guid: 6ff2339bdaf2e2f4799006c5fd6fb987,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 7853816376061787731, guid: 6ff2339bdaf2e2f4799006c5fd6fb987,
type: 3}
propertyPath: m_LocalPosition.x
@@ -120861,6 +120881,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M004_ZombieF
objectReference: {fileID: 0}
+ - target: {fileID: 188415537611797449, guid: 5d0e2b70bea8e7f4aae3b841903f1572,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -130769,6 +130794,64 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 526.9}
m_SizeDelta: {x: 905.2, y: 542}
m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &910664597
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 910664599}
+ - component: {fileID: 910664598}
+ m_Layer: 0
+ m_Name: EnemySpawner_Endless
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &910664598
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910664597}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: a64a5b45504ee0f448c65f4419271acd, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::Platformer.Mechanics.EndlessEnemySpawner
+ enemyPrefabs:
+ - {fileID: 6504999383530317407, guid: 9c65c4487bc1dba448954dd4c349a574, type: 3}
+ - {fileID: 603666063910396448, guid: c942a945bbf795c4fb34c7c41ad3eba8, type: 3}
+ - {fileID: 6888660251421648212, guid: 5166868e077e5a345bae2929e402f427, type: 3}
+ - {fileID: 188415537611797449, guid: 5d0e2b70bea8e7f4aae3b841903f1572, type: 3}
+ - {fileID: 7848113793813235637, guid: 6ff2339bdaf2e2f4799006c5fd6fb987, type: 3}
+ - {fileID: 1352356591422558597, guid: ae920194bcfccc94193aa9849a5c43a3, type: 3}
+ minGap: 5
+ maxGap: 10
+ firstSpawnDistance: 12
+ spawnOutsideMargin: 1.5
+ despawnBehindMargin: 4
+ minHits: 1
+ maxHits: 3
+--- !u!4 &910664599
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910664597}
+ 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!1 &914162667
GameObject:
m_ObjectHideFlags: 0
@@ -131357,6 +131440,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M003_ZombieM
objectReference: {fileID: 0}
+ - target: {fileID: 6888660251421648212, guid: 5166868e077e5a345bae2929e402f427,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -131830,6 +131918,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M002_Bat
objectReference: {fileID: 0}
+ - target: {fileID: 603666063910396448, guid: c942a945bbf795c4fb34c7c41ad3eba8,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 609361017181068230, guid: c942a945bbf795c4fb34c7c41ad3eba8,
type: 3}
propertyPath: m_LocalPosition.x
@@ -135057,6 +135150,116 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1016676386}
m_CullTransparentMesh: 1
+--- !u!1 &1017563961
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1017563964}
+ - component: {fileID: 1017563963}
+ - component: {fileID: 1017563962}
+ m_Layer: 0
+ m_Name: Backdrop_EerieVillage
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1017563962
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1017563961}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: c003c532857c2cf41aae9d30b0149229, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::EerieVillage.Background.LoopingBackdrop
+ parallax: 0.4
+ pixelsPerWorldUnit: 144.61617
+ anchorImageV: 0.10026
+ anchorWorldY: -3
+ verticalFollow: 0
+ heightCoverage: 1.08
+--- !u!212 &1017563963
+SpriteRenderer:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1017563961}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ 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:
+ - {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, 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: 0
+ 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: -100
+ m_MaskInteraction: 0
+ m_Sprite: {fileID: 21300000, guid: cf32ef17b2aef6d48b55a7bcc26457f7, type: 3}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 35.84, y: 15.36}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_SpriteSortPoint: 0
+--- !u!4 &1017563964
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1017563961}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: -15.137458, y: -3, z: 10}
+ 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!1 &1019271008
GameObject:
m_ObjectHideFlags: 0
@@ -136037,6 +136240,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M002_Bat
objectReference: {fileID: 0}
+ - target: {fileID: 603666063910396448, guid: c942a945bbf795c4fb34c7c41ad3eba8,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 609361017181068230, guid: c942a945bbf795c4fb34c7c41ad3eba8,
type: 3}
propertyPath: m_LocalPosition.x
@@ -136917,6 +137125,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M001_Wolf
objectReference: {fileID: 0}
+ - target: {fileID: 6504999383530317407, guid: 9c65c4487bc1dba448954dd4c349a574,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 6508303935943450553, guid: 9c65c4487bc1dba448954dd4c349a574,
type: 3}
propertyPath: m_LocalPosition.x
@@ -144734,7 +144947,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 1
+ m_IsActive: 0
--- !u!212 &1251841318
SpriteRenderer:
serializedVersion: 2
@@ -298328,6 +298541,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M003_ZombieM
objectReference: {fileID: 0}
+ - target: {fileID: 6888660251421648212, guid: 5166868e077e5a345bae2929e402f427,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -298712,6 +298930,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M005_Ghost
objectReference: {fileID: 0}
+ - target: {fileID: 7848113793813235637, guid: 6ff2339bdaf2e2f4799006c5fd6fb987,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 7853816376061787731, guid: 6ff2339bdaf2e2f4799006c5fd6fb987,
type: 3}
propertyPath: m_LocalPosition.x
@@ -301424,6 +301647,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M002_Bat
objectReference: {fileID: 0}
+ - target: {fileID: 603666063910396448, guid: c942a945bbf795c4fb34c7c41ad3eba8,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 609361017181068230, guid: c942a945bbf795c4fb34c7c41ad3eba8,
type: 3}
propertyPath: m_LocalPosition.x
@@ -306158,6 +306386,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M004_ZombieF
objectReference: {fileID: 0}
+ - target: {fileID: 188415537611797449, guid: 5d0e2b70bea8e7f4aae3b841903f1572,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -308264,6 +308497,116 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1769705767}
m_CullTransparentMesh: 1
+--- !u!1 &1770146875
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1770146878}
+ - component: {fileID: 1770146877}
+ - component: {fileID: 1770146876}
+ m_Layer: 0
+ m_Name: Backdrop_EerieVillage_Ground
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1770146876
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1770146875}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: c003c532857c2cf41aae9d30b0149229, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::EerieVillage.Background.LoopingBackdrop
+ parallax: 1
+ pixelsPerWorldUnit: 144.61617
+ anchorImageV: 0.89241
+ anchorWorldY: -3
+ verticalFollow: 0
+ heightCoverage: 1.08
+--- !u!212 &1770146877
+SpriteRenderer:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1770146875}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ 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:
+ - {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, 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: 0
+ 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: -99
+ m_MaskInteraction: 0
+ m_Sprite: {fileID: 21300000, guid: 73edcbbe2553d20408ee98c2065d29e6, type: 3}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 35.84, y: 3.16}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_SpriteSortPoint: 0
+--- !u!4 &1770146878
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1770146875}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: -15.137458, y: -3, z: 10}
+ 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!1 &1771039266
GameObject:
m_ObjectHideFlags: 0
@@ -310743,6 +311086,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M004_ZombieF
objectReference: {fileID: 0}
+ - target: {fileID: 188415537611797449, guid: 5d0e2b70bea8e7f4aae3b841903f1572,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -312719,6 +313067,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M003_ZombieM
objectReference: {fileID: 0}
+ - target: {fileID: 6888660251421648212, guid: 5166868e077e5a345bae2929e402f427,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -312774,6 +313127,11 @@ PrefabInstance:
propertyPath: m_Name
value: Enemy_M001_Wolf
objectReference: {fileID: 0}
+ - target: {fileID: 6504999383530317407, guid: 9c65c4487bc1dba448954dd4c349a574,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 6508303935943450553, guid: 9c65c4487bc1dba448954dd4c349a574,
type: 3}
propertyPath: m_LocalPosition.x
@@ -323549,6 +323907,9 @@ MonoBehaviour:
ActiveSlotMax: 6
PassiveSlotMax: 6
StartingCardIds: []
+ IsCloneFireActive: 0
+ CloneFireOrigin: {x: 0, y: 0}
+ CloneFireFacingX: 1
--- !u!114 &2082714491
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -325907,3 +326268,6 @@ SceneRoots:
- {fileID: 889757653}
- {fileID: 1952853428}
- {fileID: 120371127}
+ - {fileID: 1017563964}
+ - {fileID: 1770146878}
+ - {fileID: 910664599}
diff --git a/Assets/Scripts/Background/LoopingBackdrop.cs b/Assets/Scripts/Background/LoopingBackdrop.cs
new file mode 100644
index 0000000..4f9185c
--- /dev/null
+++ b/Assets/Scripts/Background/LoopingBackdrop.cs
@@ -0,0 +1,116 @@
+using UnityEngine;
+
+namespace EerieVillage.Background
+{
+ ///
+ /// 무한 가로 스크롤 배경 한 층(리뉴얼 2026-11-10 · PD 지시 「배경을 무한하게 스크롤 가능하게」).
+ ///
+ /// 좌우 끝이 맞물리는 그림 1장을 화면 폭을 덮을 만큼 나란히 깔고, 카메라 가로 이동에 맞춰 감아 돌린다.
+ /// 텍스처는 1장만 쓰고(사본은 같은 Sprite 공유) 오브젝트 수는 화면 폭에 맞춰 최소로 만든다.
+ ///
+ ///
+ /// 크기·높이: > 0 이면 「그림 px ÷ 월드 단위」 고정 배율로 키우고,
+ /// 그림 안 세로 위치 (아래 = 0) 를 월드 높이 에 맞춘다(그린 흙길 = 실제 땅).
+ /// 0 이하이면 화면 높이에 맞춰 키우고 화면에 붙어 다닌다.
+ ///
+ ///
+ [RequireComponent(typeof(SpriteRenderer))]
+ public class LoopingBackdrop : MonoBehaviour
+ {
+ [Tooltip("화면에서 이 층이 지나가는 속도(땅 = 1). 0 = 화면에 고정, 0.3~0.5 = 먼 배경, 1 = 땅과 같이.")]
+ [Range(0f, 1f)] public float parallax = 0.4f;
+
+ [Header("고정 배율 · 땅 맞춤 (pixelsPerWorldUnit > 0)")]
+ [Tooltip("그림 px ÷ 월드 단위. 여러 층이 같은 값을 써야 그림이 맞물린다. 0 이하 = 화면 높이 맞춤 모드.")]
+ public float pixelsPerWorldUnit = 0f;
+ [Tooltip("그림 아래 끝 = 0, 위 끝 = 1 기준으로 땅(발 디딤선)이 그려진 세로 위치.")]
+ [Range(0f, 1f)] public float anchorImageV = 0.1f;
+ [Tooltip("그 디딤선을 맞출 월드 높이(실제 땅 윗면).")]
+ public float anchorWorldY = 0f;
+ [Tooltip("카메라 세로 이동을 따라가는 비율. 0 = 땅에 붙어 있음(권장), 1 = 화면에 붙어 다님.")]
+ [Range(0f, 1f)] public float verticalFollow = 0f;
+
+ [Header("화면 높이 맞춤 모드 (pixelsPerWorldUnit <= 0)")]
+ [Tooltip("화면 높이 대비 배경 높이 배율.")]
+ public float heightCoverage = 1.08f;
+
+ Camera _cam;
+ SpriteRenderer _sr;
+ Transform[] _tiles;
+ float _tileWidth, _height;
+ float _lastOrtho = -1f, _lastAspect = -1f;
+ Vector3 _camStart;
+ Vector3 _rootStart;
+
+ void Start()
+ {
+ _cam = Camera.main;
+ _sr = GetComponent();
+ if (_cam == null || _sr.sprite == null)
+ {
+ Debug.LogWarning($"[LoopingBackdrop@{name}] 카메라 또는 Sprite 없음 — 꺼짐.");
+ enabled = false;
+ return;
+ }
+ _camStart = _cam.transform.position;
+ _rootStart = transform.position;
+ Rebuild();
+ }
+
+ void Rebuild()
+ {
+ float viewH = _cam.orthographicSize * 2f;
+ float viewW = viewH * _cam.aspect;
+ Vector2 spriteSize = _sr.sprite.bounds.size;
+ _height = pixelsPerWorldUnit > 0f ? _sr.sprite.rect.height / pixelsPerWorldUnit : viewH * heightCoverage;
+ float scale = _height / spriteSize.y;
+ transform.localScale = new Vector3(scale, scale, 1f);
+ _tileWidth = spriteSize.x * scale;
+
+ int need = Mathf.CeilToInt(viewW / _tileWidth) + 2; // 화면 폭 + 양옆 여유 1장씩
+ if (_tiles != null) foreach (var t in _tiles) if (t != null && t != transform) Destroy(t.gameObject);
+ _tiles = new Transform[need];
+ _tiles[0] = transform;
+ for (int i = 1; i < need; i++)
+ {
+ var go = new GameObject($"{name}_Tile{i}");
+ go.transform.SetParent(transform, false);
+ go.transform.localPosition = new Vector3(i * spriteSize.x, 0f, 0f);
+ var sr = go.AddComponent();
+ sr.sprite = _sr.sprite;
+ sr.sortingLayerID = _sr.sortingLayerID;
+ sr.sortingOrder = _sr.sortingOrder;
+ sr.color = _sr.color;
+ sr.sharedMaterial = _sr.sharedMaterial;
+ _tiles[i] = go.transform;
+ }
+ _lastOrtho = _cam.orthographicSize;
+ _lastAspect = _cam.aspect;
+ }
+
+ void LateUpdate()
+ {
+ if (_cam == null) return;
+ if (!Mathf.Approximately(_lastOrtho, _cam.orthographicSize) || !Mathf.Approximately(_lastAspect, _cam.aspect)) Rebuild();
+
+ Vector3 cam = _cam.transform.position;
+ float viewW = _cam.orthographicSize * 2f * _cam.aspect;
+
+ // 가로: 이 층은 카메라 이동의 (1 - parallax) 배를 따라간다 → 화면에서는 땅 속도의 parallax 배로 지나간다.
+ float leftEdge = cam.x - viewW * 0.5f;
+ float baseX = _rootStart.x + (cam.x - _camStart.x) * (1f - parallax); // 감기 전 첫 장 가운데
+ float firstLeft = baseX - _tileWidth * 0.5f;
+ // 첫 장 왼쪽 끝이 화면 왼쪽 끝 바로 왼쪽(한 장 이내)에 오도록 타일 폭 단위로 감는다(그림이 좌우로 이어져 끊김 없음).
+ float k = Mathf.Floor((leftEdge - firstLeft) / _tileWidth);
+ float x = baseX + k * _tileWidth;
+
+ float y;
+ if (pixelsPerWorldUnit > 0f)
+ // 스프라이트 기준점 = 가운데 → 가운데 높이 = 디딤선 높이 + (0.5 - 디딤선 비율) × 높이
+ y = anchorWorldY + (0.5f - anchorImageV) * _height + (cam.y - _camStart.y) * verticalFollow;
+ else
+ y = cam.y;
+ transform.position = new Vector3(x, y, transform.position.z);
+ }
+ }
+}
diff --git a/Assets/Scripts/Background/LoopingBackdrop.cs.meta b/Assets/Scripts/Background/LoopingBackdrop.cs.meta
new file mode 100644
index 0000000..2ef4985
--- /dev/null
+++ b/Assets/Scripts/Background/LoopingBackdrop.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c003c532857c2cf41aae9d30b0149229
\ No newline at end of file
diff --git a/Assets/Scripts/Gameplay/PlayerAttack.cs b/Assets/Scripts/Gameplay/PlayerAttack.cs
index c38ac32..34a33f9 100644
--- a/Assets/Scripts/Gameplay/PlayerAttack.cs
+++ b/Assets/Scripts/Gameplay/PlayerAttack.cs
@@ -15,6 +15,8 @@ namespace Platformer.Gameplay
{
public PlayerController player;
public Vector2 direction; // 플레이어 facing 방향 (±1, 0) — PlayerController.facing 기반
+ /// 리뉴얼 2026-11-10 — 근접 자동 공격이 타격을 직접 처리했으면 true (판정 박스 중복 타격 방지).
+ public bool strikeHandled;
public override void Execute()
{
@@ -34,10 +36,11 @@ namespace Platformer.Gameplay
}
// 플레이어 앞에 판정 박스 발생
- if (player.attackHitbox != null)
+ if (player.attackHitbox != null && !strikeHandled)
{
player.attackHitbox.Fire(direction);
}
+ strikeHandled = false; // 이벤트 객체 재사용(풀) 대비 초기화
// [BT5-Dev Hero1 2026-05-07] combatidle 5초 타이머 갱신 (PlayerStateTimer.NotifyAttackFired)
var stateTimer = player.GetComponent();
diff --git a/Assets/Scripts/Gameplay/PlayerAttackTicker.cs b/Assets/Scripts/Gameplay/PlayerAttackTicker.cs
index c356d28..5c27abc 100644
--- a/Assets/Scripts/Gameplay/PlayerAttackTicker.cs
+++ b/Assets/Scripts/Gameplay/PlayerAttackTicker.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using Platformer.Mechanics;
using UnityEngine;
using static Platformer.Core.Simulation;
@@ -5,35 +6,42 @@ using static Platformer.Core.Simulation;
namespace Platformer.Gameplay
{
///
- /// Periodic PlayerAttack event emitter — BT7-Plan PD 지시 2026-04-24 VS 순수형 자동 발동.
- /// Player GameObject에 부착되어 초마다 이벤트를 Schedule.
+ /// Player 기본 공격 발화기 — 이벤트를 Schedule 한다.
///
- /// 기획 balance/01 v0.2 확정 전 임시 기본값: 0.5초 간격 · Phase 3-B 튠 대상.
- /// 카드·특성 효과로 주기 수정이 필요해지면 외부에서 을 직접 조작하거나
- /// 를 통해 합산한다 (P13-1 공용 모듈 인터페이스 전략).
- ///
- ///
- /// 설계 근거: PlayerAttack.Execute는 이벤트 처리 로직, 본 컴포넌트는 발화 트리거.
- /// 단일 책임 원칙 + 범용성 (C11) — 타이머 컴포넌트만 교체하면 발화 방식 전환 가능.
+ /// 리뉴얼 2026-11-10 (PD 지시 「항상 달리고, 적이 근접하면 자동으로 공격 · 닿기 전에 공격 · 맞은 적은 밀려남」):
+ /// 가 켜져 있으면 진행 방향 앞, 같은 높이의 살아 있는 적이
+ /// 「접촉 거리 + 」 안에 들어오면 쿨타임이 끝나 있는 그 프레임에 바로 친다.
+ /// 살아남은 적은 「(달리기 속도 + 적이 다가오는 속도) × 쿨타임 + 여유」만큼 밀려나, 다음 공격 전에 닿지 않는다(PD 2026-11-10 참고 사항).
+ /// 꺼 두면 예전 BT7-Plan VS 순수형(주기마다 판정 박스 발동)으로 동작한다.
///
+ /// 카드·특성 효과로 주기 수정이 필요하면 를 쓴다 (P13-1 공용 모듈 인터페이스 전략).
///
[RequireComponent(typeof(PlayerController))]
public class PlayerAttackTicker : MonoBehaviour
{
- ///
- /// 공격 자동 발동 주기(초). balance/01 v0.2 확정 후 튠 대상.
- ///
- [Tooltip("공격 자동 발동 주기(초). 카드·특성으로 증감 가능.")]
+ /// 공격 쿨타임(초). balance/01 확정 후 튠 대상.
+ [Tooltip("공격 쿨타임(초). 카드·특성으로 증감 가능.")]
public float attackInterval = 0.5f;
- ///
- /// 게임 시작 직후 첫 발화까지 지연(초). 플레이어 소환 애니메이션 여유.
- ///
+ /// 게임 시작 직후 첫 발화까지 지연(초). 플레이어 소환 애니메이션 여유.
[Tooltip("게임 시작 직후 첫 발화까지의 지연(초). Spawn 애니메이션 여유.")]
public float startupDelay = 0.3f;
+ [Header("근접 자동 공격 (리뉴얼 2026-11-10)")]
+ [Tooltip("켜면 앞쪽 같은 높이의 적이 사거리 안에 있을 때만 공격한다.")]
+ public bool onlyWhenEnemyNear = true;
+ [Tooltip("적의 접촉 거리보다 이만큼 더 먼 곳에서 친다(월드). 닿기 전에 맞히기 위한 여유.")]
+ public float strikeLead = 0.5f;
+ [Tooltip("같은 높이로 보는 세로 허용 차(월드).")]
+ public float verticalTolerance = 1.0f;
+ [Tooltip("넉백 거리 계산에 더하는 여유(월드).")]
+ public float knockbackMargin = 0.3f;
+ [Tooltip("밀려나는 데 걸리는 시간(초).")]
+ public float knockbackDuration = 0.15f;
+
PlayerController player;
float attackTimer;
+ readonly List _targets = new List();
void Awake()
{
@@ -43,29 +51,95 @@ namespace Platformer.Gameplay
void Update()
{
- // 컨트롤 비활성 상태(마을 이동·메뉴 등)에서는 자동 공격 중단
- if (player == null || !player.controlEnabled)
- {
- return;
- }
+ // 컨트롤 비활성 상태(마을 이동·메뉴·사망 등)에서는 자동 공격 중단
+ if (player == null || !player.controlEnabled) return;
// 유효 간격이 0 이하이면 tick 중단 (디자이너 실수 방지)
- if (attackInterval <= 0f)
+ if (attackInterval <= 0f) return;
+
+ if (attackTimer > 0f) attackTimer -= Time.deltaTime;
+ if (attackTimer > 0f) return;
+
+ bool handled = false;
+ if (onlyWhenEnemyNear)
{
- return;
+ if (!FindTargets(_targets))
+ {
+ attackTimer = 0f; // 쿨타임은 끝난 채로 대기 → 적이 들어오면 즉시 발동
+ return;
+ }
+ float dir = player.Facing.x >= 0f ? 1f : -1f;
+ float kb = KnockbackDistance();
+ if (player.attackHitbox != null)
+ {
+ foreach (var e in _targets) player.attackHitbox.StrikeEnemy(e, dir, kb, knockbackDuration);
+ handled = true;
+ }
}
- attackTimer -= Time.deltaTime;
- if (attackTimer <= 0f)
- {
- attackTimer += attackInterval;
+ attackTimer = attackInterval;
+ var ev = Schedule();
+ ev.player = player;
+ ev.direction = player.Facing;
+ ev.strikeHandled = handled;
+ }
- var ev = Schedule();
- ev.player = player;
- ev.direction = player.Facing;
+ ///
+ /// 넉백 거리 = (달리기 속도 + 적이 다가오는 속도) × 쿨타임 + 여유.
+ /// 러너 모드 적은 제자리라 다가오는 속도 = 0.
+ ///
+ public float KnockbackDistance(float enemyApproachSpeed = 0f)
+ {
+ return (player.maxSpeed + enemyApproachSpeed) * attackInterval + knockbackMargin;
+ }
+
+ /// 적 1마리의 사거리 = 접촉 거리(중심 사이 · 그림 폭 기준 중 큰 쪽) + 앞 여유.
+ public float StrikeRange(EnemyController e)
+ {
+ float contact = Mathf.Max(e.contactDistance, e.VisualBounds.extents.x + player.Bounds.extents.x);
+ return contact + strikeLead;
+ }
+
+ /// 진행 방향 앞, 같은 높이, 사거리 안의 살아 있는 적을 모은다.
+ public bool FindTargets(List result)
+ {
+ result.Clear();
+ float dir = player.Facing.x >= 0f ? 1f : -1f;
+ Vector2 p = player.transform.position;
+ foreach (var e in EnemyRegistry)
+ {
+ if (e == null || !e.isActiveAndEnabled) continue;
+ var h = e.GetComponent();
+ if (h != null && !h.IsAlive) continue;
+ Vector2 q = e.transform.position;
+ float ahead = (q.x - p.x) * dir;
+ if (ahead < -0.2f) continue; // 이미 지나간 적은 제외
+ if (Mathf.Abs(e.VisualBounds.center.y - player.Bounds.center.y) > verticalTolerance + e.VisualBounds.extents.y) continue;
+ if (Vector2.Distance(p, q) <= StrikeRange(e)) result.Add(e);
+ }
+ return result.Count > 0;
+ }
+
+ // 적 목록: 매 프레임 FindObjectsByType 대신 캐시(적 수가 바뀔 때만 갱신)
+ static readonly List s_registry = new List();
+ static int s_frame = -1;
+ static List EnemyRegistry
+ {
+ get
+ {
+ if (s_frame != Time.frameCount && Time.frameCount % 10 == 0 || s_registry.Count == 0)
+ {
+ s_registry.Clear();
+ s_registry.AddRange(Object.FindObjectsByType(FindObjectsSortMode.None));
+ s_frame = Time.frameCount;
+ }
+ return s_registry;
}
}
+ /// 앞에 칠 수 있는 적이 있는가(디버그·외부 확인용).
+ public bool EnemyAhead() => FindTargets(_targets);
+
///
/// 카드·특성 효과가 공격 주기를 배수로 조정할 때 사용하는 편의 API.
///
diff --git a/Assets/Scripts/Mechanics/AttackHitbox.cs b/Assets/Scripts/Mechanics/AttackHitbox.cs
index 6c3c32a..88e6d86 100644
--- a/Assets/Scripts/Mechanics/AttackHitbox.cs
+++ b/Assets/Scripts/Mechanics/AttackHitbox.cs
@@ -78,6 +78,25 @@ namespace Platformer.Mechanics
}
}
+ ///
+ /// 리뉴얼 2026-11-10 — 근접 자동 공격 1타: 지정한 적에게 를 주고(무적 시간 무시 · 피격 모션),
+ /// 살아남으면 dir 방향으로 밀어낸다. 죽으면 EnemyDeath 체인. 반환 = 처치 여부.
+ ///
+ public bool StrikeEnemy(EnemyController enemy, float dir, float knockbackDistance, float knockbackDuration)
+ {
+ if (enemy == null) return false;
+ var health = enemy.GetComponent();
+ if (health == null || !health.IsAlive) return false;
+ health.DecrementBypassInvulnWithHit(damage);
+ if (!health.IsAlive)
+ {
+ Schedule().enemy = enemy;
+ return true;
+ }
+ enemy.Knockback(dir, knockbackDistance, knockbackDuration);
+ return false;
+ }
+
// Scene view 가시화 — 활성 상태에서 박스 표시
void OnDrawGizmos()
{
diff --git a/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs b/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs
new file mode 100644
index 0000000..00b5a1e
--- /dev/null
+++ b/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs
@@ -0,0 +1,112 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Platformer.Mechanics
+{
+ ///
+ /// 무한 스크롤 적 생성기(리뉴얼 2026-11-10 · PD 지시 「무한 스크롤하는 동안 적은 항상 새롭게 스크롤되는 화면에 랜덤으로 등장」).
+ ///
+ /// 카메라 오른쪽 끝이 다음 생성 지점에 닿으면 그 지점(화면 밖 바로 오른쪽)에 적 프리팹을 만들고,
+ /// 다음 지점은 ~ 사이 무작위로 정한다. 종류는 프리팹의 MonsterRandomizer 가 무작위로 고른다.
+ /// 생성된 적은 러너 모드(제자리 · 캐릭터 발 높이 · 맞으면 밀려남)이며, 화면 왼쪽 뒤로 지나가면 지운다.
+ ///
+ /// 체력: 몬스터마다 무작위 ~ 회 공격으로 처치(PD 2026-11-10 「임시로 1~3회」).
+ ///
+ public class EndlessEnemySpawner : MonoBehaviour
+ {
+ [Tooltip("생성할 적 프리팹 목록(종류별) — 매번 무작위로 하나를 고른다.")]
+ public GameObject[] enemyPrefabs;
+ [Tooltip("적 사이 최소 간격(월드).")]
+ public float minGap = 5f;
+ [Tooltip("적 사이 최대 간격(월드).")]
+ public float maxGap = 10f;
+ [Tooltip("첫 적이 나타날 거리(플레이어 시작 위치 기준 · 월드).")]
+ public float firstSpawnDistance = 12f;
+ [Tooltip("화면 오른쪽 끝에서 이만큼 바깥에 만든다(월드) — 스크롤되며 화면에 들어온다.")]
+ public float spawnOutsideMargin = 1.5f;
+ [Tooltip("화면 왼쪽 끝에서 이만큼 뒤로 지나간 적은 지운다(월드).")]
+ public float despawnBehindMargin = 4f;
+ [Header("임시 체력 (PD 2026-11-10 「임시로 몬스터마다 랜덤 1~3회 공격으로 처치」)")]
+ public int minHits = 1;
+ public int maxHits = 3;
+
+ Camera _cam;
+ PlayerController _player;
+ float _nextSpawnX;
+ float _feetY;
+ bool _feetYReady;
+ Transform _staging; // 꺼진 보관 자리: Awake 전에 설정을 넣기 위해 여기서 만든 뒤 꺼낸다
+ readonly List _alive = new List();
+
+ void Start()
+ {
+ _cam = Camera.main;
+ _player = FindFirstObjectByType();
+ if (_cam == null || _player == null || enemyPrefabs == null || enemyPrefabs.Length == 0)
+ {
+ Debug.LogWarning("[EndlessEnemySpawner] 카메라·플레이어·적 프리팹 중 없음 — 꺼짐.");
+ enabled = false;
+ return;
+ }
+ var st = new GameObject("_SpawnStaging");
+ st.SetActive(false);
+ st.transform.SetParent(transform, false);
+ _staging = st.transform;
+ _nextSpawnX = _player.transform.position.x + firstSpawnDistance;
+ }
+
+ void LateUpdate()
+ {
+ // 캐릭터 발 높이 = 땅에 선 플레이어 콜라이더 바닥(새 캐릭터 그림의 발 = 콜라이더 바닥)
+ if (_player.IsGrounded)
+ {
+ _feetY = _player.Bounds.min.y;
+ _feetYReady = true;
+ }
+ if (!_feetYReady) return;
+
+ float halfW = _cam.orthographicSize * _cam.aspect;
+ float camRight = _cam.transform.position.x + halfW;
+ float camLeft = _cam.transform.position.x - halfW;
+
+ // 다음 생성 지점이 화면 오른쪽 끝 바깥 여유 안으로 들어오면 만든다(한 프레임에 여러 마리 가능)
+ int guard = 0;
+ while (camRight + spawnOutsideMargin >= _nextSpawnX && guard++ < 8)
+ {
+ Spawn(Mathf.Max(_nextSpawnX, camRight + spawnOutsideMargin));
+ _nextSpawnX += Random.Range(minGap, maxGap);
+ }
+
+ for (int i = _alive.Count - 1; i >= 0; i--)
+ {
+ var e = _alive[i];
+ if (e == null) { _alive.RemoveAt(i); continue; }
+ if (e.transform.position.x < camLeft - despawnBehindMargin)
+ {
+ Destroy(e.gameObject);
+ _alive.RemoveAt(i);
+ }
+ else e.runnerFeetY = _feetY;
+ }
+ }
+
+ void Spawn(float x)
+ {
+ var prefab = enemyPrefabs[Random.Range(0, enemyPrefabs.Length)];
+ var go = Instantiate(prefab, new Vector3(x, _feetY + 1f, 0f), Quaternion.identity, _staging);
+ var ec = go.GetComponent();
+ ec.runnerMode = true;
+ ec.runnerFeetY = _feetY;
+ ec.flyingYOffset = 0f; // 날으는 몬스터도 같은 높이(PD 「몬스터 y = 캐릭터 y」)
+ var h = go.GetComponent();
+ if (h != null)
+ {
+ int dmg = _player.attackHitbox != null ? Mathf.Max(1, _player.attackHitbox.damage) : 1;
+ int hits = Random.Range(minHits, maxHits + 1);
+ h.RandomMaxHPRange = new Vector2Int(hits * dmg, hits * dmg); // Awake 에서 maxHP 로 반영
+ }
+ go.transform.SetParent(null, true); // 켜진 곳으로 꺼냄 → 여기서 Awake(종류 무작위 · 체력) 실행
+ _alive.Add(ec);
+ }
+ }
+}
diff --git a/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs.meta b/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs.meta
new file mode 100644
index 0000000..488a08a
--- /dev/null
+++ b/Assets/Scripts/Mechanics/EndlessEnemySpawner.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a64a5b45504ee0f448c65f4419271acd
\ No newline at end of file
diff --git a/Assets/Scripts/Mechanics/EnemyController.cs b/Assets/Scripts/Mechanics/EnemyController.cs
index 68bdbad..fe479ff 100644
--- a/Assets/Scripts/Mechanics/EnemyController.cs
+++ b/Assets/Scripts/Mechanics/EnemyController.cs
@@ -60,7 +60,8 @@ namespace Platformer.Mechanics
internal Collider2D _collider;
internal AudioSource _audio;
SpriteRenderer spriteRenderer;
- Rigidbody2D _body; // BT96: KinematicObject body 영역 직접 set 위해 캐싱
+ Rigidbody2D _body; // BT96: KinematicObject body 직접 set 위해 캐싱
+ Health _health; // 리뉴얼 2026-11-10: 죽은 적 접촉 피해 차단용
public Bounds Bounds => _collider.bounds;
@@ -73,6 +74,57 @@ namespace Platformer.Mechanics
PlayerController _cachedPlayer;
bool _ignoreCollisionApplied;
+ [Header("리뉴얼 2026-11-10 — 러너 모드 (PD 지시: 자동 달리기 · 랜덤 생성 · 같은 높이 · 밀려남)")]
+ [Tooltip("켜면 순찰·떨어짐 복귀를 하지 않고 제자리에서 플레이어(왼쪽)를 바라보며, 그림 아래 끝을 runnerFeetY 에 맞춘다.")]
+ public bool runnerMode = false;
+ [Tooltip("러너 모드에서 그림 아래 끝(발)을 맞출 월드 높이 = 캐릭터 발 높이.")]
+ public float runnerFeetY = 0f;
+ [Tooltip("플레이어 접촉 피해 거리(중심 사이). 예전 상수 1.5 를 값으로 꺼냄 — 플레이어 근접 공격 사거리 계산에도 쓴다.")]
+ public float contactDistance = 1.5f;
+
+ float _knockStartX, _knockDist, _knockStartTime, _knockDuration;
+ /// 밀려나는 중인가 (밀려나는 동안은 접촉 피해를 주지 않는다).
+ public bool IsKnockedBack => Time.time < _knockStartTime + _knockDuration;
+
+ ///
+ /// 맞고 밀려남(리뉴얼 2026-11-10). dir 방향(±1)으로 distance 만큼 duration 동안 감속하며 이동.
+ ///
+ public void Knockback(float dir, float distance, float duration)
+ {
+ _knockStartX = transform.position.x;
+ _knockDist = Mathf.Sign(dir) * Mathf.Max(0f, distance);
+ _knockStartTime = Time.time;
+ _knockDuration = Mathf.Max(0.01f, duration);
+ if (control != null) { control.move.x = 0f; control.velocity = Vector2.zero; }
+ }
+
+ void UpdateRunner()
+ {
+ if (control != null)
+ {
+ control.move.x = 0f;
+ control.gravityModifier = 0f;
+ control.velocity = Vector2.zero;
+ }
+ if (spriteRenderer != null) spriteRenderer.flipX = false; // 원본 그림 = 왼쪽(플레이어 쪽)을 봄
+ var p = transform.position;
+ if (_knockDuration > 0f)
+ {
+ float t = Mathf.Clamp01((Time.time - _knockStartTime) / _knockDuration);
+ float ease = 1f - (1f - t) * (1f - t); // 처음 빠르고 끝에서 멈춤
+ p.x = _knockStartX + _knockDist * ease;
+ if (t >= 1f) _knockDuration = 0f;
+ }
+ // 그림 아래 끝 = 캐릭터 발 높이 (프레임마다 잘린 사각형 가운데가 기준점이라 매 프레임 맞춘다)
+ if (spriteRenderer != null && spriteRenderer.sprite != null)
+ {
+ var s = spriteRenderer.sprite;
+ p.y = runnerFeetY + s.pivot.y / s.pixelsPerUnit * transform.lossyScale.y;
+ }
+ transform.position = p;
+ if (_body != null) _body.position = p;
+ }
+
void Awake()
{
control = GetComponent();
@@ -80,6 +132,7 @@ namespace Platformer.Mechanics
_audio = GetComponent();
spriteRenderer = GetComponent();
_body = GetComponent();
+ _health = GetComponent();
// BT5-Dev #21 — Awake 시점 fallback 추가 (Player tag 영역 미설정 영역 대비)
var playerObj = GameObject.FindGameObjectWithTag("Player");
@@ -410,14 +463,16 @@ namespace Platformer.Mechanics
void Update()
{
- // BT89 — 자동 patrol + 즉시 벽 검출 + 1~3초 대기 영역
- UpdatePatrol();
+ // 리뉴얼 2026-11-10 — 러너 모드: 순찰 대신 제자리 · 같은 높이 · 밀려남 처리
+ if (runnerMode) UpdateRunner();
+ // BT89 — 자동 patrol + 즉시 벽 검출 + 1~3초 대기
+ else UpdatePatrol();
- // BT102 — 떨어짐 검출 영역: y < _startY - fallThreshold 시 = 시작 위치 텔레포트 복귀
+ // BT102 — 떨어짐 검출: y < _startY - fallThreshold 시 = 시작 위치 텔레포트 복귀
// PD 명시 (2026-05-08): 투명벽 폐기·떨어짐 차단 다른 방법
- // 단순·근본 방법 — 떨어진 후 검출 영역 즉시 복귀 (영구 떨어짐 X)
- // PD 지시 2026-05-15 — 날으는 몬스터 영역 떨어짐 검출 skip (공중 patrol 정상)
- if (_isInitialized && !IsFlying && transform.position.y < _startY - fallThreshold)
+ // 단순·근본 방법 — 떨어진 후 검출 즉시 복귀 (영구 떨어짐 X)
+ // PD 지시 2026-05-15 — 날으는 몬스터는 떨어짐 검출 skip (공중 patrol 정상)
+ if (!runnerMode && _isInitialized && !IsFlying && transform.position.y < _startY - fallThreshold)
{
Vector3 safe = new Vector3(_startX, _startY, transform.position.z);
transform.position = safe;
@@ -443,12 +498,14 @@ namespace Platformer.Mechanics
if (pgo != null) _cachedPlayer = pgo.GetComponent();
if (_cachedPlayer == null) _cachedPlayer = Object.FindFirstObjectByType();
}
- if (_cachedPlayer != null && _cachedPlayer.health != null && _cachedPlayer.health.IsAlive)
+ // 리뉴얼 2026-11-10 — 밀려나는 중(맞은 직후)·죽은 적은 접촉 피해 없음
+ bool selfAlive = _health == null || _health.IsAlive;
+ if (_cachedPlayer != null && _cachedPlayer.health != null && _cachedPlayer.health.IsAlive && selfAlive && !IsKnockedBack)
{
- // PD 지시 2026-05-13 — VisualBounds.Intersects OR distance < 1.5f 단일 조건·ground·공중 무관 피격
+ // PD 지시 2026-05-13 — VisualBounds.Intersects OR distance < contactDistance(예전 1.5f) 단일 조건·ground·공중 무관 피격
float dist = Vector2.Distance(transform.position, _cachedPlayer.transform.position);
bool boundsHit = VisualBounds.Intersects(_cachedPlayer.Bounds);
- bool distHit = dist < 1.5f;
+ bool distHit = dist < contactDistance;
if ((boundsHit || distHit) && !_cachedPlayer.health.IsInvulnerable)
{
_cachedPlayer.health.Decrement();
diff --git a/Assets/Scripts/Mechanics/PlayerController.cs b/Assets/Scripts/Mechanics/PlayerController.cs
index ac7ce21..4cf3046 100644
--- a/Assets/Scripts/Mechanics/PlayerController.cs
+++ b/Assets/Scripts/Mechanics/PlayerController.cs
@@ -61,7 +61,14 @@ namespace Platformer.Mechanics
public Health health;
public bool controlEnabled = true;
+ [Header("리뉴얼 2026-11-10 — 자동 달리기 · 터치 점프 (PD 지시)")]
+ [Tooltip("켜면 이동 입력 없이 항상 달리고, 화면 터치(마우스 클릭)는 점프만 한다.")]
+ public bool autoRun = true;
+ [Tooltip("자동 달리기 방향 (+1 = 오른쪽, -1 = 왼쪽).")]
+ public float autoRunDirection = 1f;
+
bool jump;
+ bool _pointerJumpHeld; // 터치·클릭으로 시작한 점프를 누르고 있는 중 (떼면 점프 감속)
Vector2 move;
SpriteRenderer spriteRenderer;
internal Animator animator;
@@ -152,12 +159,18 @@ namespace Platformer.Mechanics
if (controlEnabled)
{
Vector2 moveInput = m_MoveAction.ReadValue();
- move.x = moveInput.x;
+ // 리뉴얼 2026-11-10 — 자동 달리기: 이동 입력을 쓰지 않고 항상 한 방향으로 달린다.
+ move.x = autoRun ? Mathf.Sign(autoRunDirection) : moveInput.x;
+
+ bool pointerPressed = autoRun && PointerJumpPressedThisFrame();
+ bool pointerReleased = autoRun && _pointerJumpHeld && PointerReleasedThisFrame();
+ if (pointerPressed) _pointerJumpHeld = true;
+ if (pointerReleased) _pointerJumpHeld = false;
// PD 결정 §15-2 (2026-05-18) — 이중 점프 + 사선 점프.
- // 사선 점프 = 점프 + move.x 입력 동시 (KinematicObject ComputeVelocity 영역 velocity.y·targetVelocity.x 동시 set 영역 자연 정합).
- // 이중 점프 = Grounded 1차 점프 후 공중 영역 2차 점프 (_jumpCount < maxJumps 영역).
- if (m_JumpAction.WasPressedThisFrame())
+ // 사선 점프 = 점프 + move.x 입력 동시 (KinematicObject ComputeVelocity 의 velocity.y·targetVelocity.x 동시 설정).
+ // 이중 점프 = Grounded 1차 점프 후 공중 2차 점프 (_jumpCount < maxJumps).
+ if (m_JumpAction.WasPressedThisFrame() || pointerPressed)
{
bool downHeld = moveInput.y < -0.5f;
bool onJumpThroughPlatform = false;
@@ -186,7 +199,7 @@ namespace Platformer.Mechanics
jumpState = JumpState.PrepareToJump;
}
}
- else if (m_JumpAction.WasReleasedThisFrame())
+ else if (m_JumpAction.WasReleasedThisFrame() || pointerReleased)
{
stopJump = true;
Schedule().player = this;
@@ -208,6 +221,29 @@ namespace Platformer.Mechanics
if (IsGrounded) LastGroundedPosition = transform.position;
}
+ ///
+ /// 화면 터치(또는 에디터·PC 의 마우스 왼쪽 클릭)가 이번 프레임에 눌렸는가. UI 위를 누른 것은 제외.
+ ///
+ bool PointerJumpPressedThisFrame()
+ {
+ bool pressed = false;
+ var touch = Touchscreen.current;
+ if (touch != null && touch.primaryTouch.press.wasPressedThisFrame) pressed = true;
+ var mouse = Mouse.current;
+ if (!pressed && mouse != null && mouse.leftButton.wasPressedThisFrame) pressed = true;
+ if (!pressed) return false;
+ var es = UnityEngine.EventSystems.EventSystem.current;
+ return es == null || !es.IsPointerOverGameObject();
+ }
+
+ bool PointerReleasedThisFrame()
+ {
+ var touch = Touchscreen.current;
+ if (touch != null && touch.primaryTouch.press.wasReleasedThisFrame) return true;
+ var mouse = Mouse.current;
+ return mouse != null && mouse.leftButton.wasReleasedThisFrame;
+ }
+
// Drop-Through Layer (Foreground·AutoForeground GameObject Layer 16).
// KinematicObject body.Cast의 contactFilter는 Start() 시점 캐싱되므로 Drop-Through는 SetLayerMask 동적 갱신으로 처리.
const int JUMP_THROUGH_LAYER = 16;
diff --git a/Assets/Scripts/Progression/PlayerProgression.cs b/Assets/Scripts/Progression/PlayerProgression.cs
index ffc6e3e..4c51723 100644
--- a/Assets/Scripts/Progression/PlayerProgression.cs
+++ b/Assets/Scripts/Progression/PlayerProgression.cs
@@ -16,6 +16,13 @@ namespace EerieVillage.Progression
/// 레벨업 발화 — int = new Level. LevelUpManager 구독 hook.
public event System.Action OnLevelUp;
+ ///
+ /// [임시 2026-11-10 · PD 지시 「내가 지시하기 전까지 레벨업은 하지 않도록」] false 면 XP 를 받지 않아 레벨업(기술 선택 창)이 없다.
+ /// PD 가 다시 켜라고 지시하면 기본값을 true 로 되돌리고 이 주석을 지운다.
+ ///
+ [Tooltip("임시(PD 2026-11-10): 꺼져 있으면 경험치·레벨업 없음.")]
+ public bool levelUpEnabled = false;
+
void Awake()
{
XPToNextLevel = LevelXPTableLoader.GetXPToNextLevel(Level);
@@ -25,6 +32,7 @@ namespace EerieVillage.Progression
public void GainXP(int amount)
{
if (amount <= 0) return;
+ if (!levelUpEnabled) return; // 임시(PD 2026-11-10): 레벨업 끔
CurrentXP += amount;
Debug.Log($"[PlayerProgression] GainXP +{amount} → Lv.{Level} {CurrentXP}/{XPToNextLevel}");
while (CurrentXP >= XPToNextLevel)
diff --git a/Packages/manifest.json b/Packages/manifest.json
index 3897c47..441086a 100644
--- a/Packages/manifest.json
+++ b/Packages/manifest.json
@@ -8,6 +8,7 @@
"com.unity.feature.development": "1.0.2",
"com.unity.inputsystem": "1.19.0",
"com.unity.multiplayer.center": "1.0.1",
+ "com.unity.pipeline": "0.10.0-exp.1",
"com.unity.render-pipelines.universal": "17.3.0",
"com.unity.test-framework": "1.6.0",
"com.unity.timeline": "1.8.12",
diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json
index 7e22e53..3d94263 100644
--- a/Packages/packages-lock.json
+++ b/Packages/packages-lock.json
@@ -11,11 +11,11 @@
"hash": "73eb27aeccfa8e0676eaf3304136e9b85953d913"
},
"com.unity.2d.animation": {
- "version": "13.0.4",
+ "version": "13.0.6",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.2",
+ "com.unity.2d.common": "12.0.4",
"com.unity.2d.sprite": "1.0.0",
"com.unity.collections": "2.4.3",
"com.unity.modules.animation": "1.0.0",
@@ -24,11 +24,11 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.aseprite": {
- "version": "3.0.1",
+ "version": "3.0.2",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.1",
+ "com.unity.2d.common": "12.0.3",
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0",
"com.unity.mathematics": "1.2.6",
@@ -37,7 +37,7 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.common": {
- "version": "12.0.2",
+ "version": "12.0.4",
"depth": 2,
"source": "registry",
"dependencies": {
@@ -61,11 +61,11 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.psdimporter": {
- "version": "12.0.1",
+ "version": "12.0.2",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.1",
+ "com.unity.2d.common": "12.0.3",
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0"
},
@@ -98,7 +98,7 @@
}
},
"com.unity.2d.tilemap.extras": {
- "version": "6.0.1",
+ "version": "6.0.3",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -109,11 +109,11 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.tooling": {
- "version": "1.0.2",
+ "version": "1.0.4",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.2",
+ "com.unity.2d.common": "12.0.4",
"com.unity.modules.uielements": "1.0.0"
},
"url": "https://packages.unity.com"
@@ -135,7 +135,7 @@
"url": "https://packages.unity.com"
},
"com.unity.burst": {
- "version": "1.8.29",
+ "version": "1.8.30",
"depth": 2,
"source": "registry",
"dependencies": {
@@ -155,11 +155,11 @@
"url": "https://packages.unity.com"
},
"com.unity.collections": {
- "version": "2.6.5",
+ "version": "2.6.8",
"depth": 2,
"source": "registry",
"dependencies": {
- "com.unity.burst": "1.8.27",
+ "com.unity.burst": "1.8.29",
"com.unity.mathematics": "1.3.2",
"com.unity.test-framework": "1.4.6",
"com.unity.nuget.mono-cecil": "1.11.6",
@@ -178,7 +178,7 @@
"url": "https://packages.unity.com"
},
"com.unity.editorcoroutines": {
- "version": "1.0.1",
+ "version": "1.1.0",
"depth": 1,
"source": "registry",
"dependencies": {},
@@ -195,15 +195,15 @@
"depth": 0,
"source": "builtin",
"dependencies": {
- "com.unity.2d.animation": "13.0.4",
+ "com.unity.2d.animation": "13.0.6",
"com.unity.2d.pixel-perfect": "5.1.1",
- "com.unity.2d.psdimporter": "12.0.1",
+ "com.unity.2d.psdimporter": "12.0.2",
"com.unity.2d.sprite": "1.0.0",
"com.unity.2d.spriteshape": "13.0.0",
"com.unity.2d.tilemap": "1.0.0",
- "com.unity.2d.tilemap.extras": "6.0.1",
- "com.unity.2d.aseprite": "3.0.1",
- "com.unity.2d.tooling": "1.0.2"
+ "com.unity.2d.tilemap.extras": "6.0.3",
+ "com.unity.2d.aseprite": "3.0.2",
+ "com.unity.2d.tooling": "1.0.4"
}
},
"com.unity.feature.development": {
@@ -212,15 +212,15 @@
"source": "builtin",
"dependencies": {
"com.unity.ide.visualstudio": "2.0.26",
- "com.unity.ide.rider": "3.0.39",
- "com.unity.editorcoroutines": "1.0.1",
- "com.unity.performance.profile-analyzer": "1.3.3",
+ "com.unity.ide.rider": "3.0.40",
+ "com.unity.editorcoroutines": "1.1.0",
+ "com.unity.performance.profile-analyzer": "1.4.0",
"com.unity.test-framework": "1.6.0",
"com.unity.testtools.codecoverage": "1.3.0"
}
},
"com.unity.ide.rider": {
- "version": "3.0.39",
+ "version": "3.0.40",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -263,7 +263,7 @@
},
"com.unity.nuget.mono-cecil": {
"version": "1.11.6",
- "depth": 3,
+ "depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
@@ -276,12 +276,26 @@
"url": "https://packages.unity.com"
},
"com.unity.performance.profile-analyzer": {
- "version": "1.3.3",
+ "version": "1.4.0",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
+ "com.unity.pipeline": {
+ "version": "0.10.0-exp.1",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.test-framework": "1.1.33",
+ "com.unity.nuget.mono-cecil": "1.11.6",
+ "com.unity.modules.uielements": "1.0.0",
+ "com.unity.modules.jsonserialize": "1.0.0",
+ "com.unity.modules.screencapture": "1.0.0",
+ "com.unity.nuget.newtonsoft-json": "3.0.2"
+ },
+ "url": "https://packages.unity.com"
+ },
"com.unity.profiling.core": {
"version": "1.0.3",
"depth": 1,
@@ -332,7 +346,7 @@
"url": "https://packages.unity.com"
},
"com.unity.searcher": {
- "version": "4.9.4",
+ "version": "4.9.5",
"depth": 2,
"source": "registry",
"dependencies": {},
@@ -355,7 +369,7 @@
}
},
"com.unity.splines": {
- "version": "2.8.4",
+ "version": "2.9.0",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -376,7 +390,7 @@
}
},
"com.unity.test-framework.performance": {
- "version": "3.4.0",
+ "version": "3.5.0",
"depth": 3,
"source": "registry",
"dependencies": {
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 42d7113..f67cb98 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -66,6 +66,9 @@ PlayerSettings:
useOSAutorotation: 1
use32BitDisplayBuffer: 1
preserveFramebufferAlpha: 0
+ adjustIOSFPSUsingThermalState: 1
+ thermalStateSeriousIOSFPS: 30
+ thermalStateCriticalIOSFPS: 15
disableDepthAndStencilBuffers: 0
androidStartInFullscreen: 1
androidRenderOutsideSafeArea: 0
diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt
index 065e90f..5c6ad6f 100644
--- a/ProjectSettings/ProjectVersion.txt
+++ b/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.3.13f1
-m_EditorVersionWithRevision: 6000.3.13f1 (8c4f11e4fb20)
+m_EditorVersion: 6000.3.23f1
+m_EditorVersionWithRevision: 6000.3.23f1 (09d2ecc7fb28)