0227 작업물

This commit is contained in:
윤기주_playm 2026-02-27 09:44:52 +09:00
parent 824282216e
commit da4f34398d
83 changed files with 1314254 additions and 372 deletions

BIN
.plastic/plastic.changes Normal file

Binary file not shown.

Binary file not shown.

View File

@ -67992,6 +67992,18 @@ PrefabInstance:
propertyPath: elementDamage propertyPath: elementDamage
value: 2 value: 2
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 123676116441231771, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
propertyPath: m_LocalScale.x
value: 0.54129
objectReference: {fileID: 0}
- target: {fileID: 123676116441231771, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
propertyPath: m_LocalScale.y
value: 0.54129
objectReference: {fileID: 0}
- target: {fileID: 123676116441231771, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
propertyPath: m_LocalScale.z
value: 0.54129
objectReference: {fileID: 0}
- target: {fileID: 123676116441231771, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3} - target: {fileID: 123676116441231771, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
propertyPath: m_LocalPosition.x propertyPath: m_LocalPosition.x
value: 21 value: 21
@ -101067,74 +101079,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4554651407926660, guid: f940b3e284ebded4a9ccb11d60513792, type: 3} m_CorrespondingSourceObject: {fileID: 4554651407926660, guid: f940b3e284ebded4a9ccb11d60513792, type: 3}
m_PrefabInstance: {fileID: 929237969} m_PrefabInstance: {fileID: 929237969}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1001 &929255795
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1241920339287432, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_Name
value: ghoul
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalPosition.x
value: -0.79343855
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalPosition.y
value: 1.7618549
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalPosition.z
value: 3.0698614
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4964254056573066, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 95296637409255414, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
propertyPath: m_WarningMessage
value: "\nBinding warning: Some generic clip(s) animate transforms that are
already bound by a Humanoid avatar. These transforms can only be changed
by Humanoid clips.\n\tTransform 'chin'\n\tTransform 'pelvis'\n\tTransform
'index_03_l'\n\tTransform 'lowerarm_l'\n\tTransform 'chin'\n\tTransform 'neck_01'\n\tTransform
'clavicle_l'\n\tTransform 'ring_02_l'\n\tTransform 'ball_l'\n\tTransform
'hand_l'\n\tand more ...\n\tFrom animation clip 'idle'\n\tFrom animation
clip 'run'\n\tFrom animation clip 'ghoul_walk'\n\tFrom animation clip 'ghoul_die'\n\tFrom
animation clip 'ghoul_gethit'\n\tFrom animation clip 'ghoul_attack'"
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: adc113aafa4de4eb09c485edf6340d36, type: 3}
--- !u!1001 &929795111 --- !u!1001 &929795111
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -137294,75 +137238,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4151394138186306, guid: 6d708b24bc794f34ca00923ae7199a7c, type: 3} m_CorrespondingSourceObject: {fileID: 4151394138186306, guid: 6d708b24bc794f34ca00923ae7199a7c, type: 3}
m_PrefabInstance: {fileID: 1258269170} m_PrefabInstance: {fileID: 1258269170}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1001 &1258785557
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 121798, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_Name
value: FireballMissilePink 1
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalScale.x
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalScale.y
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalScale.z
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalPosition.x
value: 21.452522
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalPosition.y
value: 9.083
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalPosition.z
value: 15.671434
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 453390, guid: 9114871a5af053448bc045ecc1767950, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9114871a5af053448bc045ecc1767950, type: 3}
--- !u!1001 &1259034079 --- !u!1001 &1259034079
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -143214,67 +143089,6 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 50b1a042562fa4748af3c47a83313192, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 50b1a042562fa4748af3c47a83313192, type: 3}
--- !u!1001 &1328838015
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalPosition.x
value: 37.897335
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalPosition.y
value: 6.712
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalPosition.z
value: 26.37195
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalRotation.w
value: 0.7071068
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalRotation.x
value: -0.7071068
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -7511558181221131132, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: 64a9b9efd1c7f2b4f86fb36b73f3bbcf, type: 2}
- target: {fileID: 919132149155446097, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
propertyPath: m_Name
value: "Meshy_AI_\uB0A1\uC740_\uC774\uC815\uD45C_0223070448_texture"
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: e421dfa610dac7f4aacd23d9357106db, type: 3}
--- !u!4 &1329168731 stripped --- !u!4 &1329168731 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 4327119661961120, guid: dd1af51d83686be418be9aed0ae273a8, type: 3} m_CorrespondingSourceObject: {fileID: 4327119661961120, guid: dd1af51d83686be418be9aed0ae273a8, type: 3}
@ -154720,13 +154534,13 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5e83fc0b9397abb45a43cae29a8b1546, type: 3} m_Script: {fileID: 11500000, guid: 5e83fc0b9397abb45a43cae29a8b1546, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
bow_draw: {fileID: 0} bow_draw: {fileID: 8300000, guid: 8a8e2351a6095de4294daca520ecfe2e, type: 3}
bow_charge_loop: {fileID: 0} bow_charge_loop: {fileID: 0}
bow_release: {fileID: 0} bow_release: {fileID: 8300000, guid: e2caed16c688baa4297a3a8bd0f3471d, type: 3}
arrow_hit_flesh: {fileID: 0} arrow_hit_flesh: {fileID: 0}
arrow_hit_wall: {fileID: 0} arrow_hit_wall: {fileID: 0}
player_footsteps: player_footsteps:
- {fileID: 8300000, guid: 1cd590c1f2829254cba6ee3550613ff9, type: 3} - {fileID: 0}
player_dash: {fileID: 0} player_dash: {fileID: 0}
player_hit: {fileID: 0} player_hit: {fileID: 0}
player_death: {fileID: 0} player_death: {fileID: 0}
@ -154788,7 +154602,7 @@ AudioSource:
m_Curve: m_Curve:
- serializedVersion: 3 - serializedVersion: 3
time: 0 time: 0
value: 0 value: 1
inSlope: 0 inSlope: 0
outSlope: 0 outSlope: 0
tangentMode: 0 tangentMode: 0
@ -154851,13 +154665,21 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: da568e865ed998148bc68f348847077e, type: 3} m_Script: {fileID: 11500000, guid: da568e865ed998148bc68f348847077e, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
zzzRoot: {fileID: 1883510400} zzzRoot: {fileID: 0}
zzzRotateSpeed: 90 zzzRotateSpeed: 90
zzzOffset: {x: 0, y: 2.2, z: 0} zzzOffset: {x: 0, y: 2.2, z: 0}
staggerUIRoot: {fileID: 0} staggerUIRoot: {fileID: 0}
staggerIcon: {fileID: 0} staggerIcon: {fileID: 0}
staggerCooldownFill: {fileID: 0} staggerCooldownFill: {fileID: 0}
movement: {fileID: 1432447548} movement: {fileID: 1432447548}
--- !u!81 &1432447556
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 886442913}
m_Enabled: 1
--- !u!1001 &1432860901 --- !u!1001 &1432860901
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -200360,11 +200182,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4612679721586470, guid: 4aed18d080f49b545b42000641a42078, type: 3} m_CorrespondingSourceObject: {fileID: 4612679721586470, guid: 4aed18d080f49b545b42000641a42078, type: 3}
m_PrefabInstance: {fileID: 1882633986} m_PrefabInstance: {fileID: 1882633986}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1 &1883510400 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 791703799912573729, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
m_PrefabInstance: {fileID: 615584948}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &1883942996 --- !u!1001 &1883942996
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -211812,6 +211629,7 @@ GameObject:
- component: {fileID: 2004000787} - component: {fileID: 2004000787}
- component: {fileID: 2004000786} - component: {fileID: 2004000786}
- component: {fileID: 2004000785} - component: {fileID: 2004000785}
- component: {fileID: 2004000788}
m_Layer: 0 m_Layer: 0
m_Name: Terrain m_Name: Terrain
m_TagString: Untagged m_TagString: Untagged
@ -211894,6 +211712,102 @@ Transform:
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!82 &2004000788
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2004000784}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 8300000, guid: e2caed16c688baa4297a3a8bd0f3471d, type: 3}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1001 &2004639778 --- !u!1001 &2004639778
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -229280,6 +229194,14 @@ PrefabInstance:
propertyPath: baseMaxHealth propertyPath: baseMaxHealth
value: 5000 value: 5000
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 395629277865203624, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: baseMoveSpeed
value: 2
objectReference: {fileID: 0}
- target: {fileID: 395629277865203624, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: runSpeedMultiplier
value: 2.5
objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalPosition.x propertyPath: m_LocalPosition.x
value: 21.57 value: 21.57
@ -229294,7 +229216,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalRotation.w propertyPath: m_LocalRotation.w
value: 1 value: 0.9460604
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalRotation.x propertyPath: m_LocalRotation.x
@ -229302,7 +229224,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalRotation.y propertyPath: m_LocalRotation.y
value: -0 value: -0.32399026
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalRotation.z propertyPath: m_LocalRotation.z
@ -229314,7 +229236,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalEulerAnglesHint.y propertyPath: m_LocalEulerAnglesHint.y
value: 0 value: -37.809
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 647200136043690535, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_LocalEulerAnglesHint.z propertyPath: m_LocalEulerAnglesHint.z
@ -229324,6 +229246,14 @@ PrefabInstance:
propertyPath: statsUI propertyPath: statsUI
value: value:
objectReference: {fileID: 1241367434} objectReference: {fileID: 1241367434}
- target: {fileID: 3721895507182937193, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_CastShadows
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3721895507182937193, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: m_ReceiveShadows
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5716216512842242005, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 5716216512842242005, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: rotationRoot propertyPath: rotationRoot
value: value:
@ -229372,6 +229302,26 @@ PrefabInstance:
propertyPath: m_SlopeLimit propertyPath: m_SlopeLimit
value: 47.82 value: 47.82
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 8653713996665278697, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: walkVolume
value: 0.488
objectReference: {fileID: 0}
- target: {fileID: 8653713996665278697, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: playerMovement
value:
objectReference: {fileID: 1432447548}
- target: {fileID: 8653713996665278697, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: footstepCooldown
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 8653713996665278697, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: footstepParticlePrefab
value:
objectReference: {fileID: 135720, guid: efbd9c58ba892da4ca3fa50dcfcd894d, type: 3}
- target: {fileID: 8653713996665278697, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: landingVelocityThreshold
value: -0.005
objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: soundFX propertyPath: soundFX
value: value:
@ -229396,6 +229346,10 @@ PrefabInstance:
propertyPath: weaponHitBox propertyPath: weaponHitBox
value: value:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: enableAutoAim
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: aimPlaneHeight propertyPath: aimPlaneHeight
value: 1.2 value: 1.2
@ -229428,7 +229382,8 @@ PrefabInstance:
propertyPath: staggerIndicator propertyPath: staggerIndicator
value: value:
objectReference: {fileID: 1432447555} objectReference: {fileID: 1432447555}
m_RemovedComponents: [] m_RemovedComponents:
- {fileID: 8931947805467145927, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
m_RemovedGameObjects: [] m_RemovedGameObjects: []
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: m_AddedComponents:
@ -229441,6 +229396,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 265854990890279069, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - targetCorrespondingSourceObject: {fileID: 265854990890279069, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 1432447542} addedObject: {fileID: 1432447542}
- targetCorrespondingSourceObject: {fileID: 265854990890279069, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
insertIndex: -1
addedObject: {fileID: 1432447556}
m_SourcePrefab: {fileID: 100100000, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} m_SourcePrefab: {fileID: 100100000, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
--- !u!222 &4975164876745863026 --- !u!222 &4975164876745863026
CanvasRenderer: CanvasRenderer:
@ -230302,12 +230260,9 @@ SceneRoots:
- {fileID: 200768984} - {fileID: 200768984}
- {fileID: 1759137305} - {fileID: 1759137305}
- {fileID: 198901434} - {fileID: 198901434}
- {fileID: 929255795}
- {fileID: 1844125250} - {fileID: 1844125250}
- {fileID: 7311604695488881352} - {fileID: 7311604695488881352}
- {fileID: 1081393079} - {fileID: 1081393079}
- {fileID: 48215575} - {fileID: 48215575}
- {fileID: 721161536} - {fileID: 721161536}
- {fileID: 1922480046} - {fileID: 1922480046}
- {fileID: 1328838015}
- {fileID: 1258785557}

View File

@ -9592,7 +9592,7 @@ GameObject:
- component: {fileID: 2698307081393268883} - component: {fileID: 2698307081393268883}
- component: {fileID: 212108620057977221} - component: {fileID: 212108620057977221}
m_Layer: 0 m_Layer: 0
m_Name: FireballMissileFire 1 m_Name: FireArror_E
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -14452,7 +14452,7 @@ AudioSource:
m_Enabled: 1 m_Enabled: 1
serializedVersion: 4 serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0} OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 8300000, guid: 561b6a4e69f38a745939dfa7fd2befab, type: 3} m_audioClip: {fileID: 8300000, guid: e2caed16c688baa4297a3a8bd0f3471d, type: 3}
m_PlayOnAwake: 1 m_PlayOnAwake: 1
m_Volume: 1 m_Volume: 1
m_Pitch: 1 m_Pitch: 1

View File

@ -4787,7 +4787,7 @@ GameObject:
- component: {fileID: 74059094911014232} - component: {fileID: 74059094911014232}
- component: {fileID: 3513839098640783816} - component: {fileID: 3513839098640783816}
m_Layer: 0 m_Layer: 0
m_Name: FireballMissilePink 1 m_Name: NomalArrow_E
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -9647,7 +9647,7 @@ AudioSource:
m_Enabled: 1 m_Enabled: 1
serializedVersion: 4 serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0} OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 8300000, guid: 561b6a4e69f38a745939dfa7fd2befab, type: 3} m_audioClip: {fileID: 8300000, guid: 2c4dd8f77a17e024583d251f4ba0ac99, type: 3}
m_PlayOnAwake: 1 m_PlayOnAwake: 1
m_Volume: 1 m_Volume: 1
m_Pitch: 1 m_Pitch: 1

View File

@ -1249,6 +1249,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 8979112332026629722} addedObject: {fileID: 8979112332026629722}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
insertIndex: -1
addedObject: {fileID: 8653713996665278697}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 395629277865203624} addedObject: {fileID: 395629277865203624}
@ -1264,6 +1267,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 3231090147156875595} addedObject: {fileID: 3231090147156875595}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
insertIndex: -1
addedObject: {fileID: 8931947805467145927}
m_SourcePrefab: {fileID: 100100000, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
--- !u!1 &265854990890279069 stripped --- !u!1 &265854990890279069 stripped
GameObject: GameObject:
@ -1386,13 +1392,13 @@ MonoBehaviour:
damageMult: 2.5 damageMult: 2.5
rangeMult: 1.5 rangeMult: 1.5
enableAutoAim: 1 enableAutoAim: 1
aimPlaneHeight: 1
autoAimRange: 15 autoAimRange: 15
autoAimAngle: 45 autoAimAngle: 45
aimAssistStrength: 0.4 aimAssistStrength: 0.4
enemyLayer: enemyLayer:
serializedVersion: 2 serializedVersion: 2
m_Bits: 0 m_Bits: 0
onlyMaxCharge: 1
defaultProjectilePrefab: {fileID: 0} defaultProjectilePrefab: {fileID: 0}
--- !u!114 &7686364893196566162 --- !u!114 &7686364893196566162
MonoBehaviour: MonoBehaviour:
@ -1437,6 +1443,41 @@ MonoBehaviour:
staggerDuration: 0.8 staggerDuration: 0.8
staggerIndicator: {fileID: 0} staggerIndicator: {fileID: 0}
animSmoothSpeed: 8 animSmoothSpeed: 8
--- !u!114 &8653713996665278697
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 265854990890279069}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 340cc097d528ea14ea52211fd54cf9fd, type: 3}
m_Name:
m_EditorClassIdentifier:
leftFootBoneName: foot.l
rightFootBoneName: foot.r
landingVelocityThreshold: -0.002
maxFootHeight: 0.25
minSpeedThreshold: 0.1
runSpeedThreshold: 4
footstepCooldown: 0.1
walkFootsteps:
- {fileID: 8300000, guid: bcd89a8edde309143ae183be1f4a786f, type: 3}
walkVolume: 0.35
runFootsteps: []
runVolume: 0.5
groundRayDistance: 0.3
groundLayerMask:
serializedVersion: 2
m_Bits: 4294967295
surfaceFootsteps: []
pitchMin: 0.93
pitchMax: 1.07
volumeVariation: 0.05
footstepParticlePrefab: {fileID: 0}
particleDestroyTime: 2
playerMovement: {fileID: 0}
--- !u!114 &395629277865203624 --- !u!114 &395629277865203624
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1538,6 +1579,102 @@ CapsuleCollider:
m_Height: 1.81 m_Height: 1.81
m_Direction: 1 m_Direction: 1
m_Center: {x: 0, y: 0.9, z: 0} m_Center: {x: 0, y: 0.9, z: 0}
--- !u!82 &8931947805467145927
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 265854990890279069}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!4 &642015492957721826 stripped --- !u!4 &642015492957721826 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 547484039116769582, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} m_CorrespondingSourceObject: {fileID: 547484039116769582, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}

View File

@ -930,6 +930,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 400032, guid: 74236a73e891a4540a264993ac8d337b, type: 3} - targetCorrespondingSourceObject: {fileID: 400032, guid: 74236a73e891a4540a264993ac8d337b, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 1946310677813001208} addedObject: {fileID: 1946310677813001208}
- targetCorrespondingSourceObject: {fileID: 400032, guid: 74236a73e891a4540a264993ac8d337b, type: 3}
insertIndex: -1
addedObject: {fileID: 6471947453838429977}
m_AddedComponents: m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 100032, guid: 74236a73e891a4540a264993ac8d337b, type: 3} - targetCorrespondingSourceObject: {fileID: 100032, guid: 74236a73e891a4540a264993ac8d337b, type: 3}
insertIndex: -1 insertIndex: -1
@ -1000,6 +1003,11 @@ MonoBehaviour:
showDebugGizmos: 1 showDebugGizmos: 1
hitSound: {fileID: 0} hitSound: {fileID: 0}
deathSound: {fileID: 0} deathSound: {fileID: 0}
attackSound: {fileID: 0}
footstepSounds: []
footstepVolume: 0.5
slashEffectPrefabs: []
slashSpawnPoint: {fileID: 0}
deathEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0}
hitEffect: {fileID: 19827894, guid: 9edc33f62cf3ae849badc4cc12fe5f8a, type: 3} hitEffect: {fileID: 19827894, guid: 9edc33f62cf3ae849badc4cc12fe5f8a, type: 3}
impactSpawnPoint: {fileID: 0} impactSpawnPoint: {fileID: 0}
@ -1037,3 +1045,81 @@ CapsuleCollider:
m_Height: 2.22 m_Height: 2.22
m_Direction: 1 m_Direction: 1
m_Center: {x: 0, y: 0.8, z: 0} m_Center: {x: 0, y: 0.8, z: 0}
--- !u!1001 &6471947453838848443
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 6300812397143730918}
m_Modifications:
- target: {fileID: 196072, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_Name
value: BombFuse
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalPosition.x
value: -0.177
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalPosition.y
value: 1.537
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalPosition.z
value: -0.239
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalRotation.w
value: 0.7071068
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalRotation.x
value: -0.7071068
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: -90
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 19914164, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_Materials.Array.size
value: 1
objectReference: {fileID: 0}
- target: {fileID: 19960006, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_Materials.Array.size
value: 1
objectReference: {fileID: 0}
- target: {fileID: 19968302, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_Materials.Array.size
value: 1
objectReference: {fileID: 0}
- target: {fileID: 19992606, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
propertyPath: m_Materials.Array.size
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
--- !u!4 &6471947453838429977 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 425634, guid: 0b4ea991852d6984aab98759fa8d4ebb, type: 3}
m_PrefabInstance: {fileID: 6471947453838848443}
m_PrefabAsset: {fileID: 0}

View File

@ -890,8 +890,14 @@ MonoBehaviour:
attackRestDuration: 1.5 attackRestDuration: 1.5
detectionRange: 10 detectionRange: 10
showDebugGizmos: 1 showDebugGizmos: 1
hitSound: {fileID: 0} hitSound: {fileID: 8300000, guid: f0b5cf5db7e8d794b87d7768fae8148d, type: 3}
deathSound: {fileID: 0} deathSound: {fileID: 8300000, guid: 25715791032849143acec6b619e395a6, type: 3}
attackSound: {fileID: 8300000, guid: feec35b8934041b42889d03ff6d8c73e, type: 3}
footstepSounds:
- {fileID: 8300000, guid: 5d2f88ab97e13694e9c8eec9e92fa6bf, type: 3}
footstepVolume: 0.5
slashEffectPrefabs: []
slashSpawnPoint: {fileID: 0}
deathEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0}
hitEffect: {fileID: 0} hitEffect: {fileID: 0}
impactSpawnPoint: {fileID: 0} impactSpawnPoint: {fileID: 0}
@ -900,9 +906,15 @@ MonoBehaviour:
chargeDuration: 2 chargeDuration: 2
chargeDelay: 3 chargeDelay: 3
prepareTime: 3 prepareTime: 3
chargeTrackingSpeed: 5
chargeAnim: Run-run chargeAnim: Run-run
prepareAnim: Run-wait prepareAnim: Run-wait
walkAnim: Run-walk walkAnim: Run-walk
growlSound: {fileID: 8300000, guid: 96aac212c180db7489c10ff5d871a613, type: 3}
chargeSound: {fileID: 8300000, guid: 5d2f88ab97e13694e9c8eec9e92fa6bf, type: 3}
impactSound: {fileID: 0}
chargeFootstepSounds: []
chargeFootstepVolume: 0.6
showChargeDebugLog: 1 showChargeDebugLog: 1
--- !u!54 &8964470652111950350 --- !u!54 &8964470652111950350
Rigidbody: Rigidbody:

View File

@ -1906,13 +1906,13 @@ Transform:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5291722251081738114} m_GameObject: {fileID: 5291722251081738114}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0.6870603, y: -0, z: -0, w: 0.72660035}
m_LocalPosition: {x: -0.013, y: 0.923, z: 0.728} m_LocalPosition: {x: -0.013, y: 0.923, z: 0.728}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 8892907556271350198} m_Father: {fileID: 8892907556271350198}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 86.796, y: 0, z: 0}
--- !u!1 &5441857239707455192 --- !u!1 &5441857239707455192
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1959,6 +1959,8 @@ GameObject:
- component: {fileID: 8274003280596335008} - component: {fileID: 8274003280596335008}
- component: {fileID: 3230568340763030921} - component: {fileID: 3230568340763030921}
- component: {fileID: -3738201542468800832} - component: {fileID: -3738201542468800832}
- component: {fileID: -5246553538145643479}
- component: {fileID: 6957788938015121824}
m_Layer: 6 m_Layer: 6
m_Name: SwordMonster m_Name: SwordMonster
m_TagString: Enemy m_TagString: Enemy
@ -2000,7 +2002,7 @@ Animator:
m_Controller: {fileID: 9100000, guid: 0e7254c70951b4d5fb0831717917abf2, type: 2} m_Controller: {fileID: 9100000, guid: 0e7254c70951b4d5fb0831717917abf2, type: 2}
m_CullingMode: 0 m_CullingMode: 0
m_UpdateMode: 0 m_UpdateMode: 0
m_ApplyRootMotion: 1 m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0 m_LinearVelocityBlending: 0
m_StabilizeFeet: 0 m_StabilizeFeet: 0
m_WarningMessage: m_WarningMessage:
@ -2035,9 +2037,10 @@ MonoBehaviour:
showDebugGizmos: 1 showDebugGizmos: 1
hitSound: {fileID: 0} hitSound: {fileID: 0}
deathSound: {fileID: 0} deathSound: {fileID: 0}
attackSound: {fileID: 0}
deathEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0}
hitEffect: {fileID: 19820634, guid: 2d051abfebeda054eac2b6a15edf6d4e, type: 3} hitEffect: {fileID: 19820634, guid: 2d051abfebeda054eac2b6a15edf6d4e, type: 3}
impactSpawnPoint: {fileID: 351339871207031370} impactSpawnPoint: {fileID: 0}
attackRange: 2 attackRange: 2
attackDelay: 1.5 attackDelay: 1.5
dropItemPrefabs: dropItemPrefabs:
@ -2120,6 +2123,143 @@ Rigidbody:
m_Interpolate: 0 m_Interpolate: 0
m_Constraints: 80 m_Constraints: 80
m_CollisionDetection: 0 m_CollisionDetection: 0
--- !u!114 &-5246553538145643479
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5674935864780053661}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 023a477747491df409d7cce43725baed, type: 3}
m_Name:
m_EditorClassIdentifier:
hitSounds:
- {fileID: 8300000, guid: f0b5cf5db7e8d794b87d7768fae8148d, type: 3}
deathSound: {fileID: 8300000, guid: 25715791032849143acec6b619e395a6, type: 3}
attackSounds:
- {fileID: 8300000, guid: 7acdd2563ba58d84a9485bb23fda3af7, type: 3}
- {fileID: 8300000, guid: d441b85a31eee4645b0bd6c25df3d5b4, type: 3}
defaultFootsteps:
- {fileID: 8300000, guid: 5d2f88ab97e13694e9c8eec9e92fa6bf, type: 3}
footstepVolume: 0.351
pitchMin: 0.743
pitchMax: 1.194
volumeVariation: 0.181
groundCheckDistance: 0.3
groundLayerMask:
serializedVersion: 2
m_Bits: 4294967295
surfaceFootsteps: []
hitEffect: {fileID: 0}
hitEffectPrefabs: []
deathEffectPrefab: {fileID: 0}
slashEffectPrefabs:
- {fileID: 1576508625749478, guid: a619fc9eccbe6d242a5a7f82bbb584be, type: 3}
- {fileID: 171468, guid: 9bb3c2595cddc25468a1fccc3b563ae4, type: 3}
effectSpawnPoint: {fileID: 351339871207031370}
enableKnockback: 1
knockbackForce: 1.5
knockbackDuration: 0.15
enableStunOnHit: 0
stunDuration: 0.5
--- !u!82 &6957788938015121824
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5674935864780053661}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_PlayOnAwake: 1
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 3
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1 &5783887718245941704 --- !u!1 &5783887718245941704
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -1456,6 +1456,7 @@ GameObject:
- component: {fileID: -5927759587507764226} - component: {fileID: -5927759587507764226}
- component: {fileID: 1514289710616282544} - component: {fileID: 1514289710616282544}
- component: {fileID: 5769769960016074036} - component: {fileID: 5769769960016074036}
- component: {fileID: -5542430048221739178}
m_Layer: 6 m_Layer: 6
m_Name: ThrowMonster m_Name: ThrowMonster
m_TagString: Enemy m_TagString: Enemy
@ -1577,6 +1578,7 @@ MonoBehaviour:
showDebugGizmos: 1 showDebugGizmos: 1
hitSound: {fileID: 0} hitSound: {fileID: 0}
deathSound: {fileID: 0} deathSound: {fileID: 0}
attackSound: {fileID: 0}
deathEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0}
hitEffect: {fileID: 0} hitEffect: {fileID: 0}
impactSpawnPoint: {fileID: 0} impactSpawnPoint: {fileID: 0}
@ -1640,6 +1642,44 @@ CapsuleCollider:
m_Height: 3.39 m_Height: 3.39
m_Direction: 1 m_Direction: 1
m_Center: {x: 0, y: 0.94, z: 0} m_Center: {x: 0, y: 0.94, z: 0}
--- !u!114 &-5542430048221739178
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3587750552762439828}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 023a477747491df409d7cce43725baed, type: 3}
m_Name:
m_EditorClassIdentifier:
hitSounds:
- {fileID: 8300000, guid: f0b5cf5db7e8d794b87d7768fae8148d, type: 3}
deathSound: {fileID: 8300000, guid: 25715791032849143acec6b619e395a6, type: 3}
attackSounds:
- {fileID: 8300000, guid: 5476ee29b8817e145b3a6e5c75df1b74, type: 3}
defaultFootsteps:
- {fileID: 8300000, guid: 5d2f88ab97e13694e9c8eec9e92fa6bf, type: 3}
footstepVolume: 0.5
pitchMin: 0.9
pitchMax: 1.1
volumeVariation: 0.1
groundCheckDistance: 0.3
groundLayerMask:
serializedVersion: 2
m_Bits: 4294967295
surfaceFootsteps: []
hitEffect: {fileID: 0}
hitEffectPrefabs: []
deathEffectPrefab: {fileID: 0}
slashEffectPrefabs: []
effectSpawnPoint: {fileID: 0}
enableKnockback: 1
knockbackForce: 1.5
knockbackDuration: 0.15
enableStunOnHit: 0
stunDuration: 0.5
--- !u!1 &3881770281504482781 --- !u!1 &3881770281504482781
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

Binary file not shown.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 1cd590c1f2829254cba6ee3550613ff9 guid: 8a07abab90f85bf469a0648e0c509a53
AudioImporter: AudioImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 7 serializedVersion: 7

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 5d2f88ab97e13694e9c8eec9e92fa6bf
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 25715791032849143acec6b619e395a6
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: f0b5cf5db7e8d794b87d7768fae8148d
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 7acdd2563ba58d84a9485bb23fda3af7
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: feec35b8934041b42889d03ff6d8c73e
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 96aac212c180db7489c10ff5d871a613
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: d441b85a31eee4645b0bd6c25df3d5b4
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
fileFormatVersion: 2
guid: 5476ee29b8817e145b3a6e5c75df1b74
AudioImporter:
externalObjects: {}
serializedVersion: 6
defaultSettings:
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
preloadAudioData: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 57772
packageName: Epic Toon FX
packageVersion: 1.81
assetPath: Assets/Epic Toon FX/Sound/etfx_shoot_fireball2.wav
uploadId: 567564

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: de907f9c9053d5c4eb81812b2d79bf6a
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: bcd89a8edde309143ae183be1f4a786f
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 8a8e2351a6095de4294daca520ecfe2e
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: bbea83134daad1841994526833befc2a
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: e2caed16c688baa4297a3a8bd0f3471d
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 1
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -83,5 +83,5 @@ Material:
m_Colors: m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SilhouetteColor: {r: 1, g: 0, b: 0.06054926, a: 1} - _SilhouetteColor: {r: 1, g: 0, b: 0.060549237, a: 0.6509804}
m_BuildTextureStacks: [] m_BuildTextureStacks: []

View File

@ -83,5 +83,5 @@ Material:
m_Colors: m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SilhouetteColor: {r: 0, g: 0.7, b: 1, a: 1} - _SilhouetteColor: {r: 0, g: 0.78720564, b: 1, a: 0.50980395}
m_BuildTextureStacks: [] m_BuildTextureStacks: []

View File

@ -300,7 +300,7 @@ AnimatorState:
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: root_Aim m_Name: root_Aim
m_Speed: 1 m_Speed: 1.2
m_CycleOffset: 0 m_CycleOffset: 0
m_Transitions: m_Transitions:
- {fileID: -1120746595662440390} - {fileID: -1120746595662440390}
@ -342,7 +342,7 @@ AnimatorStateMachine:
m_Position: {x: 410, y: 240, z: 0} m_Position: {x: 410, y: 240, z: 0}
- serializedVersion: 1 - serializedVersion: 1
m_State: {fileID: 5685718804930466242} m_State: {fileID: 5685718804930466242}
m_Position: {x: 373.32153, y: 331.04327, z: 0} m_Position: {x: 370, y: 330, z: 0}
- serializedVersion: 1 - serializedVersion: 1
m_State: {fileID: -6348460053703279695} m_State: {fileID: -6348460053703279695}
m_Position: {x: 380, y: 420, z: 0} m_Position: {x: 380, y: 420, z: 0}
@ -392,10 +392,10 @@ BlendTree:
m_Name: Walk m_Name: Walk
m_Childs: m_Childs:
- serializedVersion: 2 - serializedVersion: 2
m_Motion: {fileID: -8589176688227795177, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} m_Motion: {fileID: 7400000, guid: 7bde795c29ea0ef499b1170d942349dd, type: 2}
m_Threshold: 0 m_Threshold: 0
m_Position: {x: 0, y: 0} m_Position: {x: 0, y: 0}
m_TimeScale: 2 m_TimeScale: 1.5
m_CycleOffset: 0 m_CycleOffset: 0
m_DirectBlendParameter: Speed m_DirectBlendParameter: Speed
m_Mirror: 0 m_Mirror: 0
@ -547,7 +547,7 @@ BlendTree:
m_Motion: {fileID: -203655887218126122, guid: 7c15252a2eba2c04ba99493345d5d0b3, type: 3} m_Motion: {fileID: -203655887218126122, guid: 7c15252a2eba2c04ba99493345d5d0b3, type: 3}
m_Threshold: 0 m_Threshold: 0
m_Position: {x: 0, y: 0} m_Position: {x: 0, y: 0}
m_TimeScale: 2 m_TimeScale: 1.2
m_CycleOffset: 0 m_CycleOffset: 0
m_DirectBlendParameter: Speed m_DirectBlendParameter: Speed
m_Mirror: 0 m_Mirror: 0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5a8eeec8fae9ce149be149f618060b8d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -85,6 +85,20 @@ ModelImporter:
floatParameter: 0 floatParameter: 0
intParameter: 0 intParameter: 0
messageOptions: 0 messageOptions: 0
- time: 0.24569547
functionName: OnAttackSound
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.42422637
functionName: OnAttackSound
data:
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
transformMask: [] transformMask: []
maskType: 3 maskType: 3
maskSource: {instanceID: 0} maskSource: {instanceID: 0}

View File

@ -29357,4 +29357,18 @@ AnimationClip:
m_EulerEditorCurves: [] m_EulerEditorCurves: []
m_HasGenericRootTransform: 0 m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 1 m_HasMotionFloatCurves: 1
m_Events: [] m_Events:
- time: 0.23333333
functionName: OnFootstep
data:
objectReferenceParameter: {fileID: 5674935864780053661, guid: 50c1bf70f87f8124baeacfb51b165d44, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.56666666
functionName: OnFootstep
data:
objectReferenceParameter: {fileID: 5674935864780053661, guid: 50c1bf70f87f8124baeacfb51b165d44, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0

View File

@ -88,5 +88,5 @@ Material:
m_Colors: m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0.84051716, g: 1.5, b: 0.7047413, a: 1} - _EmissionColor: {r: 0.84051716, g: 1.5, b: 0.7047413, a: 1}
- _SilhouetteColor: {r: 0, g: 0.5, b: 1, a: 0.3} - _SilhouetteColor: {r: 1, g: 0, b: 0.047118187, a: 0.44705883}
m_BuildTextureStacks: [] m_BuildTextureStacks: []

View File

@ -52,32 +52,6 @@ AnimatorState:
m_MirrorParameter: m_MirrorParameter:
m_CycleOffsetParameter: m_CycleOffsetParameter:
m_TimeParameter: m_TimeParameter:
--- !u!1102 &-3389239410898933574
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ghoul_attack
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 9067093048684652814, guid: 3da633fdc8224f244a7cd59ebf8ee979, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!91 &9100000 --- !u!91 &9100000
AnimatorController: AnimatorController:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -159,9 +133,6 @@ AnimatorStateMachine:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: Base Layer m_Name: Base Layer
m_ChildStates: m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -3389239410898933574}
m_Position: {x: 260, y: 400, z: 0}
- serializedVersion: 1 - serializedVersion: 1
m_State: {fileID: 4817866092193183352} m_State: {fileID: 4817866092193183352}
m_Position: {x: 140, y: 190, z: 0} m_Position: {x: 140, y: 190, z: 0}
@ -177,6 +148,9 @@ AnimatorStateMachine:
- serializedVersion: 1 - serializedVersion: 1
m_State: {fileID: 6957203282615137037} m_State: {fileID: 6957203282615137037}
m_Position: {x: 270, y: 450, z: 0} m_Position: {x: 270, y: 450, z: 0}
- serializedVersion: 1
m_State: {fileID: 2739066917218413003}
m_Position: {x: 260, y: 400, z: 0}
m_ChildStateMachines: [] m_ChildStateMachines: []
m_AnyStateTransitions: [] m_AnyStateTransitions: []
m_EntryTransitions: [] m_EntryTransitions: []
@ -187,6 +161,32 @@ AnimatorStateMachine:
m_ExitPosition: {x: 800, y: 120, z: 0} m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 4817866092193183352} m_DefaultState: {fileID: 4817866092193183352}
--- !u!1102 &2739066917218413003
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ghoul_attack
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 5a8eeec8fae9ce149be149f618060b8d, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &4817866092193183352 --- !u!1102 &4817866092193183352
AnimatorState: AnimatorState:
serializedVersion: 6 serializedVersion: 6

View File

@ -89,5 +89,5 @@ Material:
m_Colors: m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 1.5, g: 1.2069767, b: 0.5302325, a: 1} - _EmissionColor: {r: 1.5, g: 1.2069767, b: 0.5302325, a: 1}
- _SilhouetteColor: {r: 0, g: 0.5, b: 1, a: 0.3} - _SilhouetteColor: {r: 1, g: 0.06177143, b: 0, a: 0.42745098}
m_BuildTextureStacks: [] m_BuildTextureStacks: []

View File

@ -71,4 +71,3 @@ Material:
- _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0}
- _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5} - _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@ -2,13 +2,18 @@
%TAG !u! tag:unity3d.com,2011: %TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000 --- !u!21 &2100000
Material: Material:
serializedVersion: 6 serializedVersion: 8
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: skull_love_AB m_Name: skull_love_AB
m_Shader: {fileID: 211, guid: 0000000000000000f000000000000000, type: 0} m_Shader: {fileID: 211, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords: _ALPHABLEND_ON m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _ALPHABLEND_ON
m_InvalidKeywords: []
m_LightmapFlags: 0 m_LightmapFlags: 0
m_EnableInstancingVariants: 0 m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
@ -16,7 +21,8 @@ Material:
stringTagMap: stringTagMap:
RenderType: Transparent RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- ALWAYS - GRABPASS
m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
m_TexEnvs: m_TexEnvs:
@ -32,6 +38,7 @@ Material:
m_Texture: {fileID: 2800000, guid: 529f928ce594e144ba6b086b892cfd98, type: 3} m_Texture: {fileID: 2800000, guid: 529f928ce594e144ba6b086b892cfd98, type: 3}
m_Scale: {x: 1, y: 1} m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0} m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats: m_Floats:
- _BlendOp: 0 - _BlendOp: 0
- _BumpScale: 1 - _BumpScale: 1
@ -63,3 +70,4 @@ Material:
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0}
- _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5} - _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5}
m_BuildTextureStacks: []

Binary file not shown.

BIN
Assets/KS_Barefoot_1.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: a1d3284c1e4510d4da998cd7d30bef20
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,7 +6,7 @@ AnimationClip:
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: root_Aim m_Name: p_walk
serializedVersion: 7 serializedVersion: 7
m_Legacy: 0 m_Legacy: 0
m_Compressed: 0 m_Compressed: 0
@ -1043395,6 +1043395,13 @@ AnimationClip:
m_HasGenericRootTransform: 0 m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0 m_HasMotionFloatCurves: 0
m_Events: m_Events:
- time: 0.6166667
functionName: OnBowDraw
data:
objectReferenceParameter: {fileID: 265854990890279069, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0
- time: 0.96666664 - time: 0.96666664
functionName: OnShootArrow functionName: OnShootArrow
data: data:

View File

@ -922218,4 +922218,11 @@ AnimationClip:
flags: 0 flags: 0
m_HasGenericRootTransform: 0 m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0 m_HasMotionFloatCurves: 0
m_Events: [] m_Events:
- time: 0.81666666
functionName: OnBowDraw
data:
objectReferenceParameter: {fileID: 265854990890279069, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
floatParameter: 0
intParameter: 0
messageOptions: 0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7bde795c29ea0ef499b1170d942349dd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -107,9 +107,8 @@ public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 ->
return; return;
} }
// 이펙트/소리만 (애니/상태 변화 없음) // 피격 사운드/이펙트는 MonsterBehaviour가 OnHitEvent 구독해서 처리
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 피격 이펙트를 InvokeHitEvent((transform.position - (playerTransform != null ? playerTransform.position : transform.position)).normalized); // 발생시킬거에요 -> 피격 이벤트를
if (hitSound != null && audioSource != null) audioSource.PlayOneShot(hitSound); // 재생할거에요 -> 소리를
return; return;
} }
@ -133,6 +132,13 @@ public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 ->
private Coroutine _chargeCoroutine; // 변수를 선언할거에요 -> 돌진 코루틴 핸들을 private Coroutine _chargeCoroutine; // 변수를 선언할거에요 -> 돌진 코루틴 핸들을
[Header("=== 사운드 ===")] // 인스펙터 제목을 달거에요 -> 돌진 몬스터 전용 사운드를
[SerializeField] private AudioClip growlSound; // 변수를 선언할거에요 -> 돌진 준비 시 으르렁/포효 소리를
[SerializeField] private AudioClip chargeSound; // 변수를 선언할거에요 -> 돌진 시작 시 휙/쿵 소리를
[SerializeField] private AudioClip impactSound; // 변수를 선언할거에요 -> 플레이어 충돌 시 타격음을
[SerializeField] protected AudioClip[] chargeFootstepSounds; // 배열을 선언할거에요 -> 돌진 중 발소리를 (여러 개 넣으면 랜덤)
[SerializeField][Range(0f, 1f)] private float chargeFootstepVolume = 0.6f; // 변수를 선언할거에요 -> 돌진 발소리 볼륨을
[Header("=== 디버그 ===")] // 인스펙터 제목을 달거에요 -> 디버그 설정을 [Header("=== 디버그 ===")] // 인스펙터 제목을 달거에요 -> 디버그 설정을
[SerializeField] private bool showChargeDebugLog = true; // 변수를 선언할거에요 -> 디버그 로그 on/off를 [SerializeField] private bool showChargeDebugLog = true; // 변수를 선언할거에요 -> 디버그 로그 on/off를
@ -208,6 +214,7 @@ public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 ->
if (showChargeDebugLog) Debug.Log($"[ChargeMonster] ⏳ 돌진 준비 시작"); // 출력할거에요 if (showChargeDebugLog) Debug.Log($"[ChargeMonster] ⏳ 돌진 준비 시작"); // 출력할거에요
animator.Play(prepareAnim, 0, 0f); // 재생할거에요 -> 준비 애니를 animator.Play(prepareAnim, 0, 0f); // 재생할거에요 -> 준비 애니를
yield return new WaitForSeconds(prepareTime); // 기다릴거에요 -> 준비 시간만큼 yield return new WaitForSeconds(prepareTime); // 기다릴거에요 -> 준비 시간만큼
// 준비 중 피격으로 isPreparing이 false가 됐으면 종료 // 준비 중 피격으로 isPreparing이 false가 됐으면 종료
@ -280,6 +287,8 @@ public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 ->
IDamageable t = col.gameObject.GetComponent<IDamageable>(); // 가져올거에요 -> 데미지 인터페이스를 IDamageable t = col.gameObject.GetComponent<IDamageable>(); // 가져올거에요 -> 데미지 인터페이스를
if (t != null) t.TakeDamage(attackDamage); // 입힐거에요 -> 데미지를 if (t != null) t.TakeDamage(attackDamage); // 입힐거에요 -> 데미지를
// 충돌 타격음은 MonsterBehaviour가 OnHitEvent 구독해서 처리
// ⭐ 경직 적용 — 돌진 충돌 시 플레이어를 n초 동안 움직이지 못하게 // ⭐ 경직 적용 — 돌진 충돌 시 플레이어를 n초 동안 움직이지 못하게
PlayerMovement pm = col.gameObject.GetComponent<PlayerMovement>(); // 가져올거에요 -> 플레이어 이동 스크립트를 PlayerMovement pm = col.gameObject.GetComponent<PlayerMovement>(); // 가져올거에요 -> 플레이어 이동 스크립트를
if (pm != null) pm.ApplyStagger(); // 적용할거에요 -> 경직을 (PlayerMovement.staggerDuration 값 사용) if (pm != null) pm.ApplyStagger(); // 적용할거에요 -> 경직을 (PlayerMovement.staggerDuration 값 사용)
@ -289,6 +298,10 @@ public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 ->
// 디버그 기즈모 // 디버그 기즈모
// ───────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────
// 애니메이션 이벤트
// ─────────────────────────────────────────────────────────
protected override void OnDrawGizmosSelected() // 함수를 선언할거에요 -> 기즈모 오버라이드를 protected override void OnDrawGizmosSelected() // 함수를 선언할거에요 -> 기즈모 오버라이드를
{ {
base.OnDrawGizmosSelected(); // 실행할거에요 -> 부모 기즈모를 먼저 base.OnDrawGizmosSelected(); // 실행할거에요 -> 부모 기즈모를 먼저

View File

@ -89,8 +89,8 @@ public class ExplodeMonster : MonsterClass // 클래스를 선언할거에요 ->
ApplyDamageOnly(amount); // 실행할거에요 -> 체력 감소와 UI만 (StartHit 호출 없음) ApplyDamageOnly(amount); // 실행할거에요 -> 체력 감소와 UI만 (StartHit 호출 없음)
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 피격 이펙트를 // 피격 사운드/이펙트는 MonsterBehaviour가 OnHitEvent 구독해서 처리
if (hitSound != null && audioSource != null) audioSource.PlayOneShot(hitSound); // 재생할거에요 -> 소리 InvokeHitEvent((transform.position - (playerTransform != null ? playerTransform.position : transform.position)).normalized); // 발생시킬거에요 -> 피격 이벤트
if (currentHP <= 0) // 조건이 맞으면 실행할거에요 -> 사망했으면 if (currentHP <= 0) // 조건이 맞으면 실행할거에요 -> 사망했으면
{ {

View File

@ -0,0 +1,362 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를
using System; // 시스템 기능을 사용할거에요 -> System을
// ============================================================
// MonsterBehaviour v2
//
// 역할: 몬스터의 사운드 / 이펙트 / 넉백 / 스턴을
// MonsterClass 코드를 건드리지 않고 Inspector에서 조합
//
// v2 추가 기능:
// ① 바닥 재질(Tag/PhysicMaterial)별 발소리 자동 전환
// ② 발소리 Pitch/Volume 랜덤 → 반복 이질감 제거
// ③ 연속 동일 클립 방지 (마지막 재생 클립 기억)
//
// 투사체 충돌음은 ProjectileImpactSound 컴포넌트 사용
// (투사체 프리팹에 별도 부착)
// ============================================================
// ─────────────────────────────────────────────────────────────
// MonsterBehaviour 본체
// SurfaceType, SurfaceFootstep → SurfaceFootstep.cs 참조
// ─────────────────────────────────────────────────────────────
public class MonsterBehaviour : MonoBehaviour // 클래스를 선언할거에요 -> MonsterBehaviour를
{
// ─────────────────────────────────────────────────────────
// 전투 사운드
// ─────────────────────────────────────────────────────────
[Header("=== 전투 사운드 ===")]
[Tooltip("피격 시 소리 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] hitSounds; // 배열을 선언할거에요 -> 피격 소리들을
[Tooltip("사망 시 소리")]
[SerializeField] private AudioClip deathSound; // 변수를 선언할거에요 -> 사망 소리를
[Tooltip("공격 시 소리 (애니메이션 이벤트 OnAttackSound)")]
[SerializeField] private AudioClip[] attackSounds; // 배열을 선언할거에요 -> 공격 소리들을
// ─────────────────────────────────────────────────────────
// 발소리 — 기본
// ─────────────────────────────────────────────────────────
[Header("=== 발소리 — 기본 ===")]
[Tooltip("바닥 재질 매칭 실패 시 사용할 기본 발소리")]
[SerializeField] private AudioClip[] defaultFootsteps; // 배열을 선언할거에요 -> 기본 발소리들을
[Tooltip("발소리 기본 볼륨")]
[SerializeField][Range(0f, 1f)] private float footstepVolume = 0.5f; // 변수를 선언할거에요 -> 발소리 볼륨을
[Tooltip("Pitch 최솟값 (이 값~최댓값 랜덤 → 반복 이질감 제거)")]
[SerializeField][Range(0.5f, 1.5f)] private float pitchMin = 0.9f; // 변수를 선언할거에요 -> 피치 최솟값을
[Tooltip("Pitch 최댓값")]
[SerializeField][Range(0.5f, 1.5f)] private float pitchMax = 1.1f; // 변수를 선언할거에요 -> 피치 최댓값을
[Tooltip("Volume 랜덤 범위 (footstepVolume ± 이 값)")]
[SerializeField][Range(0f, 0.3f)] private float volumeVariation = 0.1f; // 변수를 선언할거에요 -> 볼륨 변동 범위를
// ─────────────────────────────────────────────────────────
// 발소리 — 바닥 재질별
// ─────────────────────────────────────────────────────────
[Header("=== 발소리 — 바닥 재질별 ===")]
[Tooltip("바닥 감지 Raycast 거리")]
[SerializeField] private float groundCheckDistance = 0.3f; // 변수를 선언할거에요 -> 바닥 감지 거리를
[Tooltip("바닥 감지 LayerMask (Ground 레이어 등)")]
[SerializeField] private LayerMask groundLayerMask = ~0; // 변수를 선언할거에요 -> 감지 레이어를 (기본 전체)
[Tooltip("재질별 발소리 목록\n" +
"바닥 오브젝트 Tag 또는 PhysicMaterial 이름으로 자동 매칭\n" +
"예: Tag = 'Stone' → SurfaceType.Stone 클립 재생")]
[SerializeField] private SurfaceFootstep[] surfaceFootsteps; // 배열을 선언할거에요 -> 재질별 발소리 묶음들을
// ─────────────────────────────────────────────────────────
// 이펙트
// ─────────────────────────────────────────────────────────
[Header("=== 이펙트 ===")]
[Tooltip("피격 시 파티클 (오브젝트에 붙은 ParticleSystem)")]
[SerializeField] private ParticleSystem hitEffect; // 변수를 선언할거에요 -> 피격 파티클을
[Tooltip("피격 시 생성할 이펙트 프리팹 (여러 개 = 랜덤)")]
[SerializeField] private GameObject[] hitEffectPrefabs; // 배열을 선언할거에요 -> 피격 이펙트 프리팹들을
[Tooltip("사망 시 생성할 이펙트 프리팹")]
[SerializeField] private GameObject deathEffectPrefab; // 변수를 선언할거에요 -> 사망 이펙트 프리팹을
[Tooltip("공격/슬래쉬 이펙트 프리팹 (여러 개 = 랜덤)")]
[SerializeField] private GameObject[] slashEffectPrefabs; // 배열을 선언할거에요 -> 슬래쉬 이펙트 프리팹들을
[Tooltip("이펙트 생성 위치 (칼 끝, 손 등) — 없으면 몬스터 위치")]
[SerializeField] private Transform effectSpawnPoint; // 변수를 선언할거에요 -> 이펙트 생성 위치를
// ─────────────────────────────────────────────────────────
// 넉백
// ─────────────────────────────────────────────────────────
[Header("=== 넉백 ===")]
[Tooltip("넉백 사용 여부")]
[SerializeField] private bool enableKnockback = true; // 변수를 선언할거에요 -> 넉백 사용 여부를
[Tooltip("넉백 거리")]
[SerializeField] private float knockbackForce = 1.5f; // 변수를 선언할거에요 -> 넉백 힘을
[Tooltip("넉백 지속 시간 (초)")]
[SerializeField] private float knockbackDuration = 0.15f; // 변수를 선언할거에요 -> 넉백 지속 시간을
// ─────────────────────────────────────────────────────────
// 스턴
// ─────────────────────────────────────────────────────────
[Header("=== 스턴 ===")]
[Tooltip("피격 시 스턴 사용 여부")]
[SerializeField] private bool enableStunOnHit = false; // 변수를 선언할거에요 -> 피격 스턴 여부를
[Tooltip("스턴 지속 시간 (초)")]
[SerializeField] private float stunDuration = 0.5f; // 변수를 선언할거에요 -> 스턴 시간을
// ─────────────────────────────────────────────────────────
// 내부 변수
// ─────────────────────────────────────────────────────────
private MonsterClass _monster; // 변수를 선언할거에요 -> 연결된 MonsterClass를
private AudioSource _audioSource; // 변수를 선언할거에요 -> AudioSource를
private Coroutine _stunCoroutine; // 변수를 선언할거에요 -> 스턴 코루틴 핸들을
private AudioClip _lastFootstepClip; // 변수를 선언할거에요 -> 마지막 발소리 클립을 (연속 동일 방지)
private float _originalPitch; // 변수를 선언할거에요 -> 원래 AudioSource Pitch를 (복원용)
// ─────────────────────────────────────────────────────────
// 초기화
// ─────────────────────────────────────────────────────────
private void Awake() // 함수를 실행할거에요 -> 초기화를
{
_monster = GetComponent<MonsterClass>(); // 가져올거에요 -> MonsterClass를
_audioSource = GetComponent<AudioSource>(); // 가져올거에요 -> AudioSource를
if (_audioSource != null) // 조건이 맞으면 실행할거에요 -> AudioSource가 있으면
_originalPitch = _audioSource.pitch; // 저장할거에요 -> 원래 Pitch를
if (_monster == null) // 조건이 맞으면 실행할거에요 -> MonsterClass가 없으면
{
Debug.LogError($"[MonsterBehaviour] {gameObject.name}에 MonsterClass가 없어요!"); // 오류를 출력할거에요
return; // 중단할거에요
}
_monster.OnHitEvent += HandleHit; // 등록할거에요 -> 피격 이벤트를
_monster.OnDeadEvent += HandleDead; // 등록할거에요 -> 사망 이벤트를
}
private void OnDestroy() // 함수를 실행할거에요 -> 파괴 시 이벤트 해제를
{
if (_monster == null) return; // 중단할거에요
_monster.OnHitEvent -= HandleHit; // 해제할거에요 -> 피격 이벤트 구독을
_monster.OnDeadEvent -= HandleDead; // 해제할거에요 -> 사망 이벤트 구독을
}
// ─────────────────────────────────────────────────────────
// 이벤트 핸들러
// ─────────────────────────────────────────────────────────
private void HandleHit(Vector3 hitDirection) // 함수를 선언할거에요 -> 피격 처리를
{
PlayRandomSound(hitSounds); // 재생할거에요 -> 피격 소리를
SpawnHitEffect(); // 생성할거에요 -> 피격 이펙트를
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 피격 파티클을
if (enableKnockback) // 조건이 맞으면 실행할거에요 -> 넉백 켜져있으면
_monster.ApplyKnockback(hitDirection, knockbackForce, knockbackDuration); // 적용할거에요 -> 넉백을
if (enableStunOnHit) // 조건이 맞으면 실행할거에요 -> 스턴 켜져있으면
ApplyStun(stunDuration); // 적용할거에요 -> 스턴을
}
private void HandleDead() // 함수를 선언할거에요 -> 사망 처리를
{
if (deathSound != null && _audioSource != null) // 조건이 맞으면 실행할거에요 -> 사망 소리 있으면
_audioSource.PlayOneShot(deathSound); // 재생할거에요 -> 사망 소리를
SpawnDeathEffect(); // 생성할거에요 -> 사망 이펙트를
}
// ─────────────────────────────────────────────────────────
// 애니메이션 이벤트
// ─────────────────────────────────────────────────────────
public void OnAttackSound() // 함수를 선언할거에요 -> 공격 소리 재생을 (애니메이션 이벤트)
{
PlayRandomSound(attackSounds); // 재생할거에요 -> 랜덤 공격 소리를
}
public void OnFootstep() // 함수를 선언할거에요 -> 발소리 재생을 (애니메이션 이벤트)
{
if (_audioSource == null) return; // 중단할거에요 -> AudioSource 없으면
// ① 바닥 재질에 맞는 클립 배열 가져오기
AudioClip[] clips = GetFootstepClips(); // 가져올거에요 -> 현재 바닥 재질 클립 배열을
if (clips == null || clips.Length == 0) return; // 중단할거에요 -> 클립 없으면
// ② 직전 클립과 다른 클립 선택 (연속 동일 방지)
AudioClip clip = PickNonRepeat(clips); // 뽑을거에요 -> 직전과 다른 클립을
if (clip == null) return; // 중단할거에요 -> null이면
// ③ Pitch 랜덤 적용 → 같은 소리도 매번 다르게
_audioSource.pitch = UnityEngine.Random.Range(pitchMin, pitchMax); // 설정할거에요 -> 랜덤 Pitch를
// ④ Volume 랜덤 적용 → 약간씩 다른 세기
float vol = Mathf.Clamp( // 계산할거에요 -> 0~1 범위로 제한한 랜덤 볼륨을
footstepVolume + UnityEngine.Random.Range(-volumeVariation, volumeVariation),
0f, 1f
);
_audioSource.PlayOneShot(clip, vol); // 재생할거에요 -> 발소리를
// ⑤ Pitch 복원 (다른 소리에 영향 안 주게)
_audioSource.pitch = _originalPitch; // 복원할거에요 -> 원래 Pitch로
_lastFootstepClip = clip; // 저장할거에요 -> 마지막 클립을
}
public void OnSlashEffect() // 함수를 선언할거에요 -> 슬래쉬 이펙트 생성을 (애니메이션 이벤트)
{
SpawnEffect(slashEffectPrefabs); // 생성할거에요 -> 슬래쉬 이펙트를
}
// ─────────────────────────────────────────────────────────
// 바닥 재질 감지
// ─────────────────────────────────────────────────────────
private AudioClip[] GetFootstepClips() // 함수를 선언할거에요 -> 바닥 재질에 맞는 클립 배열을 반환하는 GetFootstepClips를
{
if (surfaceFootsteps == null || surfaceFootsteps.Length == 0) // 조건이 맞으면 실행할거에요 -> 재질별 설정 없으면
return defaultFootsteps; // 반환할거에요 -> 기본 발소리를
// 발 위치(약간 위)에서 아래로 Raycast
Vector3 origin = transform.position + Vector3.up * 0.1f; // 계산할거에요 -> 레이 시작 위치를
if (!Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCheckDistance + 0.1f, groundLayerMask)) // 조건이 맞으면 실행할거에요 -> 바닥 못 찾으면
return defaultFootsteps; // 반환할거에요 -> 기본 발소리를
// Tag로 재질 판별
SurfaceType surface = TagToSurface(hit.collider.tag); // 변환할거에요 -> Tag를 SurfaceType으로
// Tag 실패 시 PhysicMaterial 이름으로 판별
if (surface == SurfaceType.Default && hit.collider.sharedMaterial != null) // 조건이 맞으면 실행할거에요 -> Tag 매칭 실패하고 PhysicMaterial 있으면
surface = NameToSurface(hit.collider.sharedMaterial.name); // 변환할거에요 -> PhysicMaterial 이름으로
// 해당 SurfaceType 클립 배열 검색
foreach (SurfaceFootstep sf in surfaceFootsteps) // 반복할거에요 -> 재질별 설정 순회를
{
if (sf.surfaceType == surface && sf.clips != null && sf.clips.Length > 0) // 조건이 맞으면 실행할거에요 -> 타입 일치하고 클립 있으면
return sf.clips; // 반환할거에요 -> 해당 재질 클립 배열을
}
return defaultFootsteps; // 반환할거에요 -> 매칭 실패 시 기본 발소리를
}
private SurfaceType TagToSurface(string tag) // 함수를 선언할거에요 -> Tag를 SurfaceType으로 변환하는 TagToSurface를
{
// Unity Tag에 Stone / Dirt / Wood / Metal / Grass / Water 추가해서 사용
switch (tag) // 분기할거에요 -> Tag 값에 따라
{
case "Stone": return SurfaceType.Stone; // 반환할거에요 -> 돌 타입을
case "Dirt": return SurfaceType.Dirt; // 반환할거에요 -> 흙 타입을
case "Wood": return SurfaceType.Wood; // 반환할거에요 -> 나무 타입을
case "Metal": return SurfaceType.Metal; // 반환할거에요 -> 금속 타입을
case "Grass": return SurfaceType.Grass; // 반환할거에요 -> 풀 타입을
case "Water": return SurfaceType.Water; // 반환할거에요 -> 물 타입을
default: return SurfaceType.Default; // 반환할거에요 -> 기본 타입을
}
}
private SurfaceType NameToSurface(string materialName) // 함수를 선언할거에요 -> PhysicMaterial 이름을 SurfaceType으로 변환하는 NameToSurface를
{
string lower = materialName.ToLower(); // 변환할거에요 -> 소문자로 (대소문자 무시)
if (lower.Contains("stone") || lower.Contains("concrete") || lower.Contains("rock")) return SurfaceType.Stone;
if (lower.Contains("dirt") || lower.Contains("sand") || lower.Contains("soil")) return SurfaceType.Dirt;
if (lower.Contains("wood") || lower.Contains("plank")) return SurfaceType.Wood;
if (lower.Contains("metal") || lower.Contains("iron") || lower.Contains("steel")) return SurfaceType.Metal;
if (lower.Contains("grass") || lower.Contains("lawn")) return SurfaceType.Grass;
if (lower.Contains("water") || lower.Contains("puddle")) return SurfaceType.Water;
return SurfaceType.Default; // 반환할거에요 -> 매칭 실패 시 기본을
}
private AudioClip PickNonRepeat(AudioClip[] clips) // 함수를 선언할거에요 -> 직전 클립과 다른 클립을 뽑는 PickNonRepeat를
{
if (clips.Length == 1) return clips[0]; // 반환할거에요 -> 1개뿐이면 그냥 반환
AudioClip picked = clips[UnityEngine.Random.Range(0, clips.Length)]; // 뽑을거에요 -> 랜덤 클립을
if (picked == _lastFootstepClip) // 조건이 맞으면 실행할거에요 -> 직전과 같으면
{
int idx = Array.IndexOf(clips, picked); // 찾을거에요 -> 현재 인덱스를
picked = clips[(idx + 1) % clips.Length]; // 뽑을거에요 -> 다음 인덱스 클립으로
}
return picked; // 반환할거에요 -> 선택된 클립을
}
// ─────────────────────────────────────────────────────────
// 스턴
// ─────────────────────────────────────────────────────────
public void ApplyStun(float duration) // 함수를 선언할거에요 -> 스턴을 적용하는 ApplyStun을
{
if (_stunCoroutine != null) StopCoroutine(_stunCoroutine); // 취소할거에요 -> 이전 스턴 코루틴을
_stunCoroutine = StartCoroutine(StunRoutine(duration)); // 시작할거에요 -> 스턴 코루틴을
}
private IEnumerator StunRoutine(float duration) // 코루틴을 정의할거에요 -> 스턴 처리를
{
yield return new WaitForSeconds(duration); // 기다릴거에요 -> 스턴 시간만큼
_stunCoroutine = null; // 초기화할거에요 -> 핸들을
}
// ─────────────────────────────────────────────────────────
// 내부 유틸
// ─────────────────────────────────────────────────────────
private void PlayRandomSound(AudioClip[] clips) // 함수를 선언할거에요 -> 랜덤 소리 재생을
{
if (clips == null || clips.Length == 0 || _audioSource == null) return; // 중단할거에요 -> 소리 없으면
int idx = UnityEngine.Random.Range(0, clips.Length); // 뽑을거에요 -> 랜덤 인덱스를
if (clips[idx] != null) _audioSource.PlayOneShot(clips[idx]); // 재생할거에요 -> 랜덤 소리를
}
private void SpawnHitEffect() // 함수를 선언할거에요 -> 피격 이펙트 생성을
{
SpawnEffect(hitEffectPrefabs); // 생성할거에요 -> 피격 이펙트를
}
private void SpawnDeathEffect() // 함수를 선언할거에요 -> 사망 이펙트 생성을
{
if (deathEffectPrefab == null) return; // 중단할거에요 -> 프리팹 없으면
Vector3 pos = effectSpawnPoint != null ? effectSpawnPoint.position : transform.position; // 결정할거에요 -> 생성 위치를
GameObject fx = Instantiate(deathEffectPrefab, pos, transform.rotation); // 생성할거에요 -> 사망 이펙트를
Destroy(fx, 3f); // 예약할거에요 -> 3초 후 제거를
}
private void SpawnEffect(GameObject[] prefabs) // 함수를 선언할거에요 -> 이펙트 프리팹 랜덤 생성을
{
if (prefabs == null || prefabs.Length == 0) return; // 중단할거에요 -> 프리팹 없으면
int idx = UnityEngine.Random.Range(0, prefabs.Length); // 뽑을거에요 -> 랜덤 인덱스를
if (prefabs[idx] == null) return; // 중단할거에요 -> 비어있으면
Vector3 pos = effectSpawnPoint != null ? effectSpawnPoint.position : transform.position; // 결정할거에요 -> 생성 위치를
Quaternion rot = effectSpawnPoint != null ? effectSpawnPoint.rotation : transform.rotation; // 결정할거에요 -> 생성 방향을
GameObject fx = Instantiate(prefabs[idx], pos, rot); // 생성할거에요 -> 이펙트를
ParticleSystem ps = fx.GetComponent<ParticleSystem>(); // 가져올거에요 -> 파티클 시스템을
float destroyTime = ps != null ? ps.main.duration + ps.main.startLifetime.constantMax : 2f; // 계산할거에요 -> 제거 시간을
Destroy(fx, destroyTime); // 예약할거에요 -> 자동 제거를
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 023a477747491df409d7cce43725baed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -53,6 +53,14 @@ public abstract class MonsterClass : MonoBehaviour, IDamageable // 추상 클래
public static Action<int> OnMonsterKilled; // 이벤트를 선언할거에요 -> 사망 전역 알림을 public static Action<int> OnMonsterKilled; // 이벤트를 선언할거에요 -> 사망 전역 알림을
// ⭐ MonsterBehaviour 연동용 이벤트
// MonsterBehaviour가 구독해서 사운드/이펙트/넉백/스턴 처리
public event Action<Vector3> OnHitEvent; // 이벤트를 선언할거에요 -> 피격 시 알림 (방향 전달)
public event Action OnDeadEvent; // 이벤트를 선언할거에요 -> 사망 시 알림
// 자식 클래스에서 이벤트 발생용 protected 메서드
protected void InvokeHitEvent(Vector3 dir) => OnHitEvent?.Invoke(dir); // 함수를 선언할거에요 -> 피격 이벤트 발생을 (자식 클래스용)
[Header("사운드/이펙트")] // 인스펙터 제목을 달거에요 -> 효과 설정을 [Header("사운드/이펙트")] // 인스펙터 제목을 달거에요 -> 효과 설정을
[SerializeField] protected AudioClip hitSound, deathSound; // 변수를 선언할거에요 -> 효과음들을 [SerializeField] protected AudioClip hitSound, deathSound; // 변수를 선언할거에요 -> 효과음들을
[SerializeField] protected AudioClip attackSound; // [NEW] 변수를 선언할거에요 -> 공격 효과음을 [SerializeField] protected AudioClip attackSound; // [NEW] 변수를 선언할거에요 -> 공격 효과음을
@ -252,9 +260,19 @@ public abstract class MonsterClass : MonoBehaviour, IDamageable // 추상 클래
if (agent != null && agent.isOnNavMesh) if (agent != null && agent.isOnNavMesh)
{ agent.isStopped = true; agent.velocity = Vector3.zero; } // 멈출거에요 -> 이동을 { agent.isStopped = true; agent.velocity = Vector3.zero; } // 멈출거에요 -> 이동을
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 이펙트를 // ⭐ MonsterBehaviour가 없을 때만 직접 처리 (하위 호환)
if (hitSound != null && audioSource != null) audioSource.PlayOneShot(hitSound); // 재생할거에요 -> 피격 소리를 if (GetComponent<MonsterBehaviour>() == null) // 조건이 맞으면 실행할거에요 -> MonsterBehaviour가 없으면
if (visualFX != null) visualFX.Flash(); // [NEW] 실행할거에요 -> 피격 깜빡임 효과를 {
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 이펙트를
if (hitSound != null && audioSource != null) audioSource.PlayOneShot(hitSound); // 재생할거에요 -> 피격 소리를
}
if (visualFX != null) visualFX.Flash(); // 실행할거에요 -> 피격 깜빡임 효과를
// ⭐ MonsterBehaviour에 피격 이벤트 발생 (방향 전달)
Vector3 hitDir = playerTransform != null // 계산할거에요 -> 피격 방향을
? (transform.position - playerTransform.position).normalized // 플레이어 반대 방향 (뒤로 튕기게)
: -transform.forward; // 없으면 정면 반대
OnHitEvent?.Invoke(hitDir); // 발생시킬거에요 -> 피격 이벤트를
// 피격 코루틴 시작 — 애니 재생 + 클립 길이 후 자동 OnHitEnd() // 피격 코루틴 시작 — 애니 재생 + 클립 길이 후 자동 OnHitEnd()
_hitCoroutine = StartCoroutine(HitRoutine()); // 시작할거에요 -> 피격 코루틴을 _hitCoroutine = StartCoroutine(HitRoutine()); // 시작할거에요 -> 피격 코루틴을
@ -375,7 +393,12 @@ public abstract class MonsterClass : MonoBehaviour, IDamageable // 추상 클래
{ agent.isStopped = true; agent.velocity = Vector3.zero; } // 멈출거에요 -> 이동을 { agent.isStopped = true; agent.velocity = Vector3.zero; } // 멈출거에요 -> 이동을
if (animator != null) animator.Play(Monster_Die, 0, 0f); // 재생할거에요 -> 사망 애니를 if (animator != null) animator.Play(Monster_Die, 0, 0f); // 재생할거에요 -> 사망 애니를
if (deathSound != null && audioSource != null) audioSource.PlayOneShot(deathSound); // 재생할거에요 -> 사망 소리를
// ⭐ MonsterBehaviour가 없을 때만 직접 처리 (하위 호환)
if (GetComponent<MonsterBehaviour>() == null) // 조건이 맞으면 실행할거에요 -> MonsterBehaviour가 없으면
if (deathSound != null && audioSource != null) audioSource.PlayOneShot(deathSound); // 재생할거에요 -> 사망 소리를
OnDeadEvent?.Invoke(); // 발생시킬거에요 -> 사망 이벤트를
// [NEW] 시각 효과가 있으면 페이드아웃으로 처리, 없으면 기존 방식 // [NEW] 시각 효과가 있으면 페이드아웃으로 처리, 없으면 기존 방식
if (visualFX != null) // 조건이 맞으면 실행할거에요 -> 시각 효과 스크립트가 있다면 if (visualFX != null) // 조건이 맞으면 실행할거에요 -> 시각 효과 스크립트가 있다면

View File

@ -0,0 +1,173 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
// ============================================================
// ProjectileImpactSound
//
// 역할: 투사체(돌, 화염병 등)가 충돌했을 때
// 대상(플레이어 / 바닥 / 벽)에 따라 다른 소리 재생
//
// 사용법:
// 1. 투사체 프리팹에 이 컴포넌트 Add Component
// 2. Inspector에서 소리 슬롯 연결
// 3. 투사체의 OnCollisionEnter 또는 OnTriggerEnter에서
// HandleImpact(other.gameObject) 호출
// (또는 이 컴포넌트가 직접 감지)
//
// 충돌 대상 판별 순서:
// Player Tag → Enemy Tag → Ground Layer → Wall/Default
// ============================================================
[RequireComponent(typeof(AudioSource))] // 필수 컴포넌트를 지정할거에요 -> AudioSource를
public class ProjectileImpactSound : MonoBehaviour // 클래스를 선언할거에요 -> 투사체 충돌 사운드를
{
// ─────────────────────────────────────────────────────────
// 사운드 슬롯
// ─────────────────────────────────────────────────────────
[Header("=== 충돌 대상별 소리 ===")]
[Tooltip("플레이어에 맞았을 때 소리 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] hitPlayerSounds; // 배열을 선언할거에요 -> 플레이어 타격음들을
[Tooltip("적 몬스터에 맞았을 때 소리 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] hitEnemySounds; // 배열을 선언할거에요 -> 적 타격음들을
[Tooltip("바닥에 맞았을 때 소리 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] hitGroundSounds; // 배열을 선언할거에요 -> 바닥 충돌음들을
[Tooltip("벽/장애물에 맞았을 때 소리 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] hitWallSounds; // 배열을 선언할거에요 -> 벽 충돌음들을
[Tooltip("매칭 실패 시 기본 충돌음 (여러 개 = 랜덤)")]
[SerializeField] private AudioClip[] defaultImpactSounds; // 배열을 선언할거에요 -> 기본 충돌음들을
[Header("=== 충돌 감지 설정 ===")]
[Tooltip("바닥으로 판별할 LayerMask (Ground 레이어 등)")]
[SerializeField] private LayerMask groundLayer; // 변수를 선언할거에요 -> 바닥 레이어를
[Tooltip("벽으로 판별할 LayerMask (Wall 레이어 등)")]
[SerializeField] private LayerMask wallLayer; // 변수를 선언할거에요 -> 벽 레이어를
[Tooltip("충돌 감지 방식 선택\n" +
"Collision: OnCollisionEnter (Rigidbody 있는 투사체)\n" +
"Trigger: OnTriggerEnter (IsTrigger 켠 투사체)")]
[SerializeField] private ImpactDetectMode detectMode = ImpactDetectMode.Collision; // 변수를 선언할거에요 -> 감지 방식을
[Tooltip("충돌 후 오브젝트 자동 제거 여부")]
[SerializeField] private bool destroyOnImpact = false; // 변수를 선언할거에요 -> 충돌 후 제거 여부를 (투사체 자체 파괴는 투사체 스크립트에서)
// ─────────────────────────────────────────────────────────
// 감지 방식 열거형
// ─────────────────────────────────────────────────────────
public enum ImpactDetectMode // 열거형을 선언할거에요 -> 충돌 감지 방식을
{
Collision, // OnCollisionEnter 사용
Trigger, // OnTriggerEnter 사용
Manual, // 외부에서 HandleImpact() 직접 호출
}
// ─────────────────────────────────────────────────────────
// 내부 변수
// ─────────────────────────────────────────────────────────
private AudioSource _audioSource; // 변수를 선언할거에요 -> AudioSource를
private bool _hasImpacted = false; // 변수를 선언할거에요 -> 이미 충돌 처리됐는지를 (중복 방지)
// ─────────────────────────────────────────────────────────
// 초기화
// ─────────────────────────────────────────────────────────
private void Awake() // 함수를 실행할거에요 -> 초기화를
{
_audioSource = GetComponent<AudioSource>(); // 가져올거에요 -> AudioSource를
_audioSource.playOnAwake = false; // 끌거에요 -> 자동 재생을
}
private void OnEnable() // 함수를 실행할거에요 -> 오브젝트 활성화 시 (풀 재사용 대비)
{
_hasImpacted = false; // 초기화할거에요 -> 충돌 상태를
}
// ─────────────────────────────────────────────────────────
// 충돌 감지 — Collision 방식
// ─────────────────────────────────────────────────────────
private void OnCollisionEnter(Collision col) // 함수를 실행할거에요 -> 충돌 시
{
if (detectMode != ImpactDetectMode.Collision) return; // 중단할거에요 -> Collision 모드 아니면
HandleImpact(col.gameObject, col.contacts[0].point); // 처리할거에요 -> 충돌 대상과 충돌 지점으로
}
// ─────────────────────────────────────────────────────────
// 충돌 감지 — Trigger 방식
// ─────────────────────────────────────────────────────────
private void OnTriggerEnter(Collider other) // 함수를 실행할거에요 -> 트리거 진입 시
{
if (detectMode != ImpactDetectMode.Trigger) return; // 중단할거에요 -> Trigger 모드 아니면
HandleImpact(other.gameObject, other.ClosestPoint(transform.position)); // 처리할거에요 -> 충돌 대상과 가장 가까운 지점으로
}
// ─────────────────────────────────────────────────────────
// 충돌 처리 — 외부에서도 호출 가능 (Manual 모드)
// ─────────────────────────────────────────────────────────
public void HandleImpact(GameObject hitObject, Vector3 hitPoint) // 함수를 선언할거에요 -> 충돌 처리를 (외부 호출 가능)
{
if (_hasImpacted) return; // 중단할거에요 -> 이미 처리됐으면 (중복 방지)
_hasImpacted = true; // 설정할거에요 -> 처리됨으로
// 대상 판별 → 소리 선택
AudioClip[] clips = DetermineClips(hitObject); // 결정할거에요 -> 대상에 맞는 클립 배열을
PlayImpactSound(clips, hitPoint); // 재생할거에요 -> 충돌음을
}
// ─────────────────────────────────────────────────────────
// 충돌 대상 판별
// ─────────────────────────────────────────────────────────
private AudioClip[] DetermineClips(GameObject hitObject) // 함수를 선언할거에요 -> 충돌 대상에 맞는 클립 배열을 반환하는 DetermineClips를
{
// 1순위: 플레이어
if (hitObject.CompareTag("Player")) // 조건이 맞으면 실행할거에요 -> 플레이어이면
return hitPlayerSounds.Length > 0 ? hitPlayerSounds : defaultImpactSounds; // 반환할거에요 -> 플레이어 타격음을
// 2순위: 적 몬스터
if (hitObject.CompareTag("Enemy")) // 조건이 맞으면 실행할거에요 -> 적이면
return hitEnemySounds.Length > 0 ? hitEnemySounds : defaultImpactSounds; // 반환할거에요 -> 적 타격음을
// 3순위: 바닥 레이어
if (IsInLayerMask(hitObject.layer, groundLayer)) // 조건이 맞으면 실행할거에요 -> 바닥 레이어이면
return hitGroundSounds.Length > 0 ? hitGroundSounds : defaultImpactSounds; // 반환할거에요 -> 바닥 충돌음을
// 4순위: 벽 레이어
if (IsInLayerMask(hitObject.layer, wallLayer)) // 조건이 맞으면 실행할거에요 -> 벽 레이어이면
return hitWallSounds.Length > 0 ? hitWallSounds : defaultImpactSounds; // 반환할거에요 -> 벽 충돌음을
// 기본: defaultImpactSounds
return defaultImpactSounds; // 반환할거에요 -> 기본 충돌음을
}
private bool IsInLayerMask(int layer, LayerMask mask) // 함수를 선언할거에요 -> 레이어가 마스크에 포함됐는지 확인하는 IsInLayerMask를
{
return mask == (mask | (1 << layer)); // 반환할거에요 -> 비트 연산으로 포함 여부를
}
// ─────────────────────────────────────────────────────────
// 충돌음 재생
// ─────────────────────────────────────────────────────────
private void PlayImpactSound(AudioClip[] clips, Vector3 position) // 함수를 선언할거에요 -> 충돌음 재생을
{
if (clips == null || clips.Length == 0) return; // 중단할거에요 -> 클립 없으면
int idx = UnityEngine.Random.Range(0, clips.Length); // 뽑을거에요 -> 랜덤 인덱스를
if (clips[idx] == null) return; // 중단할거에요 -> 클립 null이면
// AudioSource.PlayClipAtPoint: 오브젝트가 사라져도 소리는 끝까지 재생됨
// 3D 위치에서 재생 → 거리에 따라 자연스럽게 들림
AudioSource.PlayClipAtPoint(clips[idx], position); // 재생할거에요 -> 충돌 위치에서 소리를
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c6031c26873b3db45bb70ac277b6fea4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
using System; // 시스템 기능을 사용할거에요 -> System을
// ============================================================
// SurfaceType / SurfaceFootstep
// 바닥 재질 열거형과 재질별 발소리 묶음 데이터 클래스
// MonsterBehaviour.cs에서 사용
// ============================================================
public enum SurfaceType // 열거형을 선언할거에요 -> 바닥 재질 종류를
{
Default, // 기본 (설정 없을 때)
Stone, // 돌/콘크리트
Dirt, // 흙/모래
Wood, // 나무
Metal, // 금속
Grass, // 풀
Water, // 물
}
[Serializable] // 직렬화할거에요 -> Inspector에서 편집 가능하게
public class SurfaceFootstep // 클래스를 선언할거에요 -> 재질별 발소리 묶음을
{
public SurfaceType surfaceType; // 변수를 선언할거에요 -> 재질 타입을
public AudioClip[] clips; // 배열을 선언할거에요 -> 해당 재질 발소리 클립들을
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c86067452391761469246dd8b85b70ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -35,5 +35,15 @@ public class PlayerAnimator : MonoBehaviour // 클래스를 선언할거에요 -
public void UpdateMove(float speedValue) => anim.SetFloat("Speed", speedValue); // 값을 전달할거에요 -> 애니메이터의 Speed 파라미터에 public void UpdateMove(float speedValue) => anim.SetFloat("Speed", speedValue); // 값을 전달할거에요 -> 애니메이터의 Speed 파라미터에
// public void TriggerAttack() => anim.SetTrigger("Attack"); // public void TriggerAttack() => anim.SetTrigger("Attack");
public void TriggerThrow() => anim.SetTrigger("Throw"); // 신호를 보낼거에요 -> 애니메이터의 Throw 트리거에 public void TriggerThrow() => anim.SetTrigger("Throw"); // 신호를 보낼거에요 -> 애니메이터의 Throw 트리거에
// ─────────────────────────────────────────────────────────
// ⭐ 애니메이션 이벤트 전달자 — 활 관련 사운드
// FBX Throw 애니메이션 Events에 아래 함수 이름으로 등록해줘요
// ─────────────────────────────────────────────────────────
public void OnBowDraw() // 함수를 선언할거에요 -> 활 당기는 순간 소리 재생을 (애니메이션 이벤트)
{
if (attack != null) attack.PlayBowDrawSound(); // 실행할거에요 -> 활 당기는 소리를
}
public void SetCharging(bool isCharging) => anim.SetBool("isCharging", isCharging); // 값을 설정할거에요 -> 애니메이터의 isCharging 불리언에 public void SetCharging(bool isCharging) => anim.SetBool("isCharging", isCharging); // 값을 설정할거에요 -> 애니메이터의 isCharging 불리언에
} }

View File

@ -84,9 +84,12 @@ public class PlayerArrow : MonoBehaviour // 클래스를 선언할거에요 -> M
private Vector3 previousPosition; // 변수를 선언할거에요 -> 이전 위치 previousPosition을 private Vector3 previousPosition; // 변수를 선언할거에요 -> 이전 위치 previousPosition을
private Rigidbody rb; // 변수를 선언할거에요 -> 물리 컴포넌트 rb를 private Rigidbody rb; // 변수를 선언할거에요 -> 물리 컴포넌트 rb를
private AudioSource _arrowAudioSource; // 변수를 선언할거에요 -> 화살 자체의 AudioSource를 (날아가는 소리용)
private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 Awake를 private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 Awake를
{ {
rb = GetComponent<Rigidbody>(); // 컴포넌트를 가져올거에요 -> 리지드바디를 rb = GetComponent<Rigidbody>(); // 컴포넌트를 가져올거에요 -> 리지드바디를
_arrowAudioSource = GetComponent<AudioSource>(); // 가져올거에요 -> 화살 오브젝트의 AudioSource를 (날아가는 소리)
} }
private void Start() // 함수를 실행할거에요 -> 활성화 시 Start를 private void Start() // 함수를 실행할거에요 -> 활성화 시 Start를
@ -251,6 +254,10 @@ public class PlayerArrow : MonoBehaviour // 클래스를 선언할거에요 -> M
if (hasHit) return; // 조건이 맞으면 중단할거에요 -> 이미 충돌 처리되었다면 if (hasHit) return; // 조건이 맞으면 중단할거에요 -> 이미 충돌 처리되었다면
hasHit = true; // 상태를 바꿀거에요 -> 충돌 처리됨으로 hasHit = true; // 상태를 바꿀거에요 -> 충돌 처리됨으로
// ⭐ 날아가는 소리 즉시 정지 — 충돌 순간 끊기지 않게
// 임팩트 소리("팍")는 _soundFX.PlayArrowHitFlesh()에서 별도 재생됨
if (_arrowAudioSource != null) _arrowAudioSource.Stop(); // 정지할거에요 -> 날아가는 소리를
// 적 감지 (Tag 또는 Layer) // 적 감지 (Tag 또는 Layer)
bool isEnemy = hitCollider.CompareTag("Enemy"); // 조건을 확인할거에요 -> 적 태그인지 bool isEnemy = hitCollider.CompareTag("Enemy"); // 조건을 확인할거에요 -> 적 태그인지

View File

@ -167,7 +167,7 @@ public class PlayerAttack : MonoBehaviour // 클래스를 선언할거에요 ->
_chargeTimer = 0f; // 값을 초기화할거에요 -> 차징 타이머를 0으로 _chargeTimer = 0f; // 값을 초기화할거에요 -> 차징 타이머를 0으로
if (pAnim != null) pAnim.SetCharging(true); // 실행할거에요 -> 애니메이터에 차징 시작을 알리기를 if (pAnim != null) pAnim.SetCharging(true); // 실행할거에요 -> 애니메이터에 차징 시작을 알리기를
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true); // 조건이 맞으면 실행할거에요 -> 카메라 줌 효과를 켜기를 if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true); // 조건이 맞으면 실행할거에요 -> 카메라 줌 효과를 켜기를
if (soundFX != null) soundFX.PlayBowDraw(); // [NEW] 실행할거에요 -> 활 시위 당기기 + 차징 루프 소리를 // 활 당기는 소리는 애니메이션 이벤트 OnBowDraw에서 재생
} }
private void ResetChargingEffects() // 함수를 선언할거에요 -> 차징 효과를 초기화하는 ResetChargingEffects를 private void ResetChargingEffects() // 함수를 선언할거에요 -> 차징 효과를 초기화하는 ResetChargingEffects를
@ -179,6 +179,11 @@ public class PlayerAttack : MonoBehaviour // 클래스를 선언할거에요 ->
if (soundFX != null) soundFX.StopChargeLoop(); // [NEW] 실행할거에요 -> 차징 루프 소리 정지를 if (soundFX != null) soundFX.StopChargeLoop(); // [NEW] 실행할거에요 -> 차징 루프 소리 정지를
} }
public void PlayBowDrawSound() // 함수를 선언할거에요 -> 활 당기는 소리를 재생하는 PlayBowDrawSound를 (PlayerAnimator에서 호출)
{
if (soundFX != null) soundFX.PlayBowDraw(); // 실행할거에요 -> 활 당기는 소리를
}
public void CancelCharging() // 함수를 선언할거에요 -> 차징을 취소하는 CancelCharging을 public void CancelCharging() // 함수를 선언할거에요 -> 차징을 취소하는 CancelCharging을
{ {
ResetChargingEffects(); // 함수를 실행할거에요 -> 차징 효과 초기화를 ResetChargingEffects(); // 함수를 실행할거에요 -> 차징 효과 초기화를

View File

@ -0,0 +1,194 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를
// ============================================================
// AudioManager
//
// 역할: BGM 전환을 크로스페이드로 처리하는 싱글톤 매니저
//
// 사용법:
// AudioManager.Instance.PlayBGM(clip); // 즉시 전환
// AudioManager.Instance.PlayBGM(clip, 1.5f); // 1.5초 페이드
// AudioManager.Instance.StopBGM(); // 정지
// AudioManager.Instance.StopBGM(1.0f); // 1초 페이드아웃
//
// 구조:
// AudioSource A ─┐
// ├─ 크로스페이드 (한쪽 올리고 한쪽 내리기)
// AudioSource B ─┘
// ============================================================
public class AudioManager : MonoBehaviour // 클래스를 선언할거에요 -> AudioManager를
{
// ─────────────────────────────────────────────────────────
// 싱글톤
// ─────────────────────────────────────────────────────────
public static AudioManager Instance { get; private set; } // 프로퍼티를 선언할거에요 -> 싱글톤 인스턴스를
// ─────────────────────────────────────────────────────────
// Inspector 설정
// ─────────────────────────────────────────────────────────
[Header("=== BGM 설정 ===")]
[Tooltip("BGM 기본 볼륨 (0~1)")]
[SerializeField] [Range(0f, 1f)] private float bgmVolume = 0.5f; // 변수를 선언할거에요 -> BGM 볼륨을
[Tooltip("기본 페이드 시간 (초)")]
[SerializeField] private float defaultFadeDuration = 1.0f; // 변수를 선언할거에요 -> 기본 페이드 시간을
[Tooltip("씬 시작 시 재생할 기본 BGM (없으면 무음)")]
[SerializeField] private AudioClip defaultBGM; // 변수를 선언할거에요 -> 시작 BGM을
// ─────────────────────────────────────────────────────────
// 내부 변수
// ─────────────────────────────────────────────────────────
private AudioSource _sourceA; // 변수를 선언할거에요 -> BGM 채널 A를
private AudioSource _sourceB; // 변수를 선언할거에요 -> BGM 채널 B를
private bool _isAActive = true; // 변수를 선언할거에요 -> 현재 활성 채널이 A인지를
private Coroutine _fadeCoroutine; // 변수를 선언할거에요 -> 진행 중인 페이드 코루틴 핸들을
private AudioClip _currentClip; // 변수를 선언할거에요 -> 현재 재생 중인 클립을
// ─────────────────────────────────────────────────────────
// 초기화
// ─────────────────────────────────────────────────────────
private void Awake() // 함수를 실행할거에요 -> 초기화를
{
// 싱글톤 중복 방지
if (Instance != null && Instance != this) // 조건이 맞으면 실행할거에요 -> 이미 인스턴스가 있으면
{
Destroy(gameObject); // 제거할거에요 -> 중복 오브젝트를
return; // 중단할거에요
}
Instance = this; // 설정할거에요 -> 싱글톤 인스턴스를
DontDestroyOnLoad(gameObject); // 유지할거에요 -> 씬 전환해도 파괴되지 않게
// BGM 채널 A 생성
_sourceA = gameObject.AddComponent<AudioSource>(); // 추가할거에요 -> AudioSource A를
_sourceA.loop = true; // 설정할거에요 -> 루프 재생으로
_sourceA.playOnAwake = false; // 끌거에요 -> 자동 재생을
_sourceA.volume = 0f; // 설정할거에요 -> 초기 볼륨을 0으로
// BGM 채널 B 생성
_sourceB = gameObject.AddComponent<AudioSource>(); // 추가할거에요 -> AudioSource B를
_sourceB.loop = true; // 설정할거에요 -> 루프 재생으로
_sourceB.playOnAwake = false; // 끌거에요 -> 자동 재생을
_sourceB.volume = 0f; // 설정할거에요 -> 초기 볼륨을 0으로
}
private void Start() // 함수를 실행할거에요 -> 시작 시
{
if (defaultBGM != null) // 조건이 맞으면 실행할거에요 -> 기본 BGM이 있으면
PlayBGM(defaultBGM, defaultFadeDuration); // 재생할거에요 -> 기본 BGM을 페이드로
}
// ─────────────────────────────────────────────────────────
// 공개 API
// ─────────────────────────────────────────────────────────
/// <summary> BGM 전환 (페이드 시간 생략 시 기본값 사용) </summary>
public void PlayBGM(AudioClip clip, float fadeDuration = -1f) // 함수를 선언할거에요 -> BGM을 재생하는 PlayBGM을
{
if (clip == null) return; // 중단할거에요 -> 클립 없으면
// 이미 같은 클립이 재생 중이면 무시
if (_currentClip == clip) return; // 중단할거에요 -> 동일 클립이면
float duration = fadeDuration < 0f ? defaultFadeDuration : fadeDuration; // 결정할거에요 -> 페이드 시간을
_currentClip = clip; // 저장할거에요 -> 현재 클립을
// 진행 중인 페이드 취소
if (_fadeCoroutine != null) // 조건이 맞으면 실행할거에요 -> 페이드 중이면
{
StopCoroutine(_fadeCoroutine); // 취소할거에요 -> 이전 페이드를
_fadeCoroutine = null; // 초기화할거에요 -> 핸들을
}
_fadeCoroutine = StartCoroutine(CrossFadeRoutine(clip, duration)); // 시작할거에요 -> 크로스페이드 코루틴을
}
/// <summary> BGM 정지 </summary>
public void StopBGM(float fadeDuration = -1f) // 함수를 선언할거에요 -> BGM을 정지하는 StopBGM을
{
float duration = fadeDuration < 0f ? defaultFadeDuration : fadeDuration; // 결정할거에요 -> 페이드 시간을
_currentClip = null; // 초기화할거에요 -> 현재 클립을
if (_fadeCoroutine != null) StopCoroutine(_fadeCoroutine); // 취소할거에요 -> 이전 페이드를
_fadeCoroutine = StartCoroutine(FadeOutRoutine(duration)); // 시작할거에요 -> 페이드아웃 코루틴을
}
/// <summary> BGM 볼륨 변경 </summary>
public void SetVolume(float volume) // 함수를 선언할거에요 -> 볼륨을 변경하는 SetVolume을
{
bgmVolume = Mathf.Clamp01(volume); // 저장할거에요 -> 0~1로 제한한 볼륨을
ActiveSource.volume = bgmVolume; // 적용할거에요 -> 현재 활성 채널에
}
// ─────────────────────────────────────────────────────────
// 크로스페이드 코루틴
// ─────────────────────────────────────────────────────────
private IEnumerator CrossFadeRoutine(AudioClip newClip, float duration) // 코루틴을 정의할거에요 -> 크로스페이드를
{
AudioSource incoming = InactiveSource; // 가져올거에요 -> 새 클립 재생할 채널을 (현재 비활성 채널)
AudioSource outgoing = ActiveSource; // 가져올거에요 -> 페이드아웃할 채널을 (현재 활성 채널)
// 새 채널 준비
incoming.clip = newClip; // 설정할거에요 -> 새 클립을
incoming.volume = 0f; // 설정할거에요 -> 볼륨을 0으로
incoming.Play(); // 재생할거에요 -> 새 BGM을
_isAActive = !_isAActive; // 전환할거에요 -> 활성 채널을
float elapsed = 0f; // 초기화할거에요 -> 경과 시간을
float outgoingStart = outgoing.volume; // 저장할거에요 -> 기존 채널 시작 볼륨을
while (elapsed < duration) // 반복할거에요 -> 페이드 시간 동안
{
elapsed += Time.deltaTime; // 더할거에요 -> 경과 시간을
float t = Mathf.Clamp01(elapsed / duration); // 계산할거에요 -> 진행률을 (0~1)
incoming.volume = Mathf.Lerp(0f, bgmVolume, t); // 올릴거에요 -> 새 채널 볼륨을
outgoing.volume = Mathf.Lerp(outgoingStart, 0f, t); // 내릴거에요 -> 기존 채널 볼륨을
yield return null; // 대기할거에요 -> 다음 프레임까지
}
incoming.volume = bgmVolume; // 고정할거에요 -> 최종 볼륨을
outgoing.volume = 0f; // 고정할거에요 -> 기존 채널을 0으로
outgoing.Stop(); // 정지할거에요 -> 기존 채널을
outgoing.clip = null; // 초기화할거에요 -> 기존 클립을
_fadeCoroutine = null; // 초기화할거에요 -> 핸들을
}
private IEnumerator FadeOutRoutine(float duration) // 코루틴을 정의할거에요 -> 페이드아웃을
{
AudioSource active = ActiveSource; // 가져올거에요 -> 활성 채널을
float startVolume = active.volume; // 저장할거에요 -> 시작 볼륨을
float elapsed = 0f; // 초기화할거에요 -> 경과 시간을
while (elapsed < duration) // 반복할거에요 -> 페이드 시간 동안
{
elapsed += Time.deltaTime; // 더할거에요 -> 경과 시간을
active.volume = Mathf.Lerp(startVolume, 0f, elapsed / duration); // 내릴거에요 -> 볼륨을
yield return null; // 대기할거에요 -> 다음 프레임까지
}
active.volume = 0f; // 고정할거에요 -> 0으로
active.Stop(); // 정지할거에요 -> 채널을
active.clip = null; // 초기화할거에요 -> 클립을
_fadeCoroutine = null; // 초기화할거에요 -> 핸들을
}
// ─────────────────────────────────────────────────────────
// 내부 유틸
// ─────────────────────────────────────────────────────────
private AudioSource ActiveSource => _isAActive ? _sourceA : _sourceB; // 프로퍼티를 선언할거에요 -> 현재 활성 채널을
private AudioSource InactiveSource => _isAActive ? _sourceB : _sourceA; // 프로퍼티를 선언할거에요 -> 현재 비활성 채널을
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d73e7efaebf58e04a8f5cd4b8abb3003
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,4 +1,4 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
/// <summary> /// <summary>
/// 플레이어 사운드 관리 /// 플레이어 사운드 관리
@ -31,14 +31,17 @@ public class PlayerSoundFX : MonoBehaviour // 클래스를 선언할거에요 ->
[Range(0f, 1f)] [Range(0f, 1f)]
[SerializeField] private float footstepVolume = 0.3f; // 변수를 선언할거에요 -> 발걸음 볼륨을 [SerializeField] private float footstepVolume = 0.3f; // 변수를 선언할거에요 -> 발걸음 볼륨을
private AudioSource _audioSource; // 변수를 선언할거에요 -> 오디오 소스를 private AudioSource _audioSource; // 변수를 선언할거에요 -> 오디오 소스를
private AudioSource _loopSource; // 변수를 선언할거에요 -> 루프 전용 소스를 (차징 루프용) private AudioSource _loopSource; // 변수를 선언할거에요 -> 루프 전용 소스를 (차징 루프용)
private void Awake() // 함수를 실행할거에요 -> 초기화를 private void Awake() // 함수를 실행할거에요 -> 초기화를
{ {
_audioSource = GetComponent<AudioSource>(); // 가져올거에요 -> 기본 오디오 소스를 _audioSource = GetComponent<AudioSource>(); // 가져올거에요 -> 기본 오디오 소스를
_audioSource.playOnAwake = false; // 설정할거에요 -> 자동 재생 끄기로 _audioSource.playOnAwake = false; // 설정할거에요 -> 자동 재생 끄기로
// 루프 전용 AudioSource 추가 (차징 소리가 원샷과 겹치지 않게) // 루프 전용 AudioSource 추가 (차징 소리가 원샷과 겹치지 않게)
_loopSource = gameObject.AddComponent<AudioSource>(); // 추가할거에요 -> 루프 전용 채널을 _loopSource = gameObject.AddComponent<AudioSource>(); // 추가할거에요 -> 루프 전용 채널을
_loopSource.loop = true; // 설정할거에요 -> 루프로 _loopSource.loop = true; // 설정할거에요 -> 루프로
@ -98,21 +101,8 @@ public class PlayerSoundFX : MonoBehaviour // 클래스를 선언할거에요 ->
// 발걸음 — 애니메이션 이벤트에서 호출 // 발걸음 — 애니메이션 이벤트에서 호출
// ============================================ // ============================================
/// <summary> // 발소리는 PlayerFootstep 컴포넌트에서 처리
/// 걷기/달리기 애니메이션에 이벤트로 추가 // 애니메이션 이벤트 함수명: OnFootstep → PlayerFootstep.OnFootstep()
/// 애니메이션 창 → 발이 닿는 프레임에 이벤트 추가 → 함수명: PlayFootstep
/// </summary>
public void PlayFootstep() // 함수를 선언할거에요 -> 발걸음 소리를
{
if (player_footsteps == null || player_footsteps.Length == 0) return; // 조건이 맞으면 중단할거에요 -> 클립이 없으면
// 랜덤 변형으로 반복감 감소
int index = Random.Range(0, player_footsteps.Length); // 뽑을거에요 -> 랜덤 인덱스를
if (player_footsteps[index] != null) // 조건이 맞으면 실행할거에요 -> 클립이 있다면
{
_audioSource.PlayOneShot(player_footsteps[index], footstepVolume); // 재생할거에요 -> 랜덤 발걸음을
}
}
// ============================================ // ============================================
// 대시 — PlayerMovement.DashRoutine에서 호출 // 대시 — PlayerMovement.DashRoutine에서 호출
@ -146,4 +136,4 @@ public class PlayerSoundFX : MonoBehaviour // 클래스를 선언할거에요 ->
if (clip != null && _audioSource != null) // 조건이 맞으면 실행할거에요 -> 둘 다 있다면 if (clip != null && _audioSource != null) // 조건이 맞으면 실행할거에요 -> 둘 다 있다면
_audioSource.PlayOneShot(clip, sfxVolume); // 재생할거에요 -> 효과음을 _audioSource.PlayOneShot(clip, sfxVolume); // 재생할거에요 -> 효과음을
} }
} }

View File

@ -0,0 +1,420 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
using System; // 시스템 기능을 사용할거에요 -> Array.IndexOf용
// ============================================================
// PlayerFootstep v3
//
// 방식: 발 본(foot.l / foot.r)의 월드 Y 좌표를 매 프레임 추적
// 발이 아래로 내려오다가 멈추는 순간 = 실제 접지 순간
// → 그 순간에 발소리 + 파티클 재생
//
// 장점:
// - 콜라이더 / 물리 설정 불필요
// - 애니메이션 이벤트 등록 불필요
// - 어떤 애니메이션에도 자동 대응
// - 발바닥이 실제로 멈추는 순간을 정확히 감지
//
// 필요 설정:
// 1. Player 오브젝트에 Add Component → PlayerFootstep
// 2. 발소리 클립 슬롯 채우기
// 3. (선택) 발자국 파티클 프리팹 연결
// ============================================================
[RequireComponent(typeof(AudioSource))] // 컴포넌트를 강제 추가할거에요 -> AudioSource를
public class PlayerFootstep : MonoBehaviour // 클래스를 선언할거에요 -> 플레이어 발소리를
{
// ─────────────────────────────────────────────────────────
// 발 본 설정
// ─────────────────────────────────────────────────────────
[Header("=== 발 본 설정 ===")]
[Tooltip("왼발 본 이름 (Hierarchy에서 확인)")]
[SerializeField] private string leftFootBoneName = "foot.l"; // 변수를 선언할거에요 -> 왼발 본 이름을
[Tooltip("오른발 본 이름 (Hierarchy에서 확인)")]
[SerializeField] private string rightFootBoneName = "foot.r"; // 변수를 선언할거에요 -> 오른발 본 이름을
[Tooltip("접지 판정 Y속도 임계값 (음수)\n발이 내려오다 이 속도 이하가 되면 접지로 판정\n기본 -0.002 / 너무 예민하면 -0.005로 낮춰요")]
[SerializeField] private float landingVelocityThreshold = -0.002f; // 변수를 선언할거에요 -> 접지 판정 Y속도 임계값을
[Tooltip("발 높이 최대값 (루트 기준)\n이 높이 이상에서는 발소리 무시 → 점프 중 오감지 방지\n기본 0.25")]
[SerializeField] private float maxFootHeight = 0.25f; // 변수를 선언할거에요 -> 공중 판정 발 높이를
// ─────────────────────────────────────────────────────────
// 이동 속도 설정
// ─────────────────────────────────────────────────────────
[Header("=== 이동 속도 설정 ===")]
[Tooltip("이 속도 이하면 발소리 재생 안 함 (제자리 애니메이션 방지)")]
[SerializeField] private float minSpeedThreshold = 0.1f; // 변수를 선언할거에요 -> 최소 속도를
[Tooltip("이 속도 이상이면 달리기 발소리 세트 사용")]
[SerializeField] private float runSpeedThreshold = 4.0f; // 변수를 선언할거에요 -> 달리기 판정 속도를
[Tooltip("발소리 재생 쿨타임 (초)\n양발 동시 감지 중복 방지 / 기본 0.1")]
[SerializeField] private float footstepCooldown = 0.1f; // 변수를 선언할거에요 -> 발소리 쿨타임을
// ─────────────────────────────────────────────────────────
// 발소리 — 걷기
// ─────────────────────────────────────────────────────────
[Header("=== 발소리 — 걷기 ===")]
[Tooltip("걷기 기본 발소리 클립 배열 (재질 매칭 실패 시 사용)")]
[SerializeField] private AudioClip[] walkFootsteps; // 배열을 선언할거에요 -> 걷기 발소리들을
[Tooltip("걷기 발소리 볼륨 (기본 0.35)")]
[SerializeField][Range(0f, 1f)] private float walkVolume = 0.35f; // 변수를 선언할거에요 -> 걷기 볼륨을
// ─────────────────────────────────────────────────────────
// 발소리 — 달리기
// ─────────────────────────────────────────────────────────
[Header("=== 발소리 — 달리기 ===")]
[Tooltip("달리기 발소리 클립 배열 (없으면 걷기 발소리 사용)")]
[SerializeField] private AudioClip[] runFootsteps; // 배열을 선언할거에요 -> 달리기 발소리들을
[Tooltip("달리기 발소리 볼륨 (기본 0.5)")]
[SerializeField][Range(0f, 1f)] private float runVolume = 0.5f; // 변수를 선언할거에요 -> 달리기 볼륨을
// ─────────────────────────────────────────────────────────
// 발소리 — 바닥 재질별
// ─────────────────────────────────────────────────────────
[Header("=== 발소리 — 바닥 재질별 ===")]
[Tooltip("바닥 감지 Raycast 거리 (발 아래로 쏘는 레이, 기본 0.3)")]
[SerializeField] private float groundRayDistance = 0.3f; // 변수를 선언할거에요 -> 바닥 감지 거리를
[Tooltip("바닥 감지 레이어 (Ground 레이어 선택)")]
[SerializeField] private LayerMask groundLayerMask = ~0; // 변수를 선언할거에요 -> 바닥 레이어를
[Tooltip("재질별 발소리 배열 (SurfaceFootstep.cs 공유)\nTag 또는 PhysicMaterial 이름으로 자동 매칭")]
[SerializeField] private SurfaceFootstep[] surfaceFootsteps; // 배열을 선언할거에요 -> 재질별 발소리 묶음들을
// ─────────────────────────────────────────────────────────
// Pitch / Volume 랜덤
// ─────────────────────────────────────────────────────────
[Header("=== Pitch / Volume 랜덤 ===")]
[Tooltip("Pitch 최솟값 (기본 0.93 → ±7% 범위)")]
[SerializeField][Range(0.5f, 1.5f)] private float pitchMin = 0.93f; // 변수를 선언할거에요 -> 피치 최솟값을
[Tooltip("Pitch 최댓값 (기본 1.07)")]
[SerializeField][Range(0.5f, 1.5f)] private float pitchMax = 1.07f; // 변수를 선언할거에요 -> 피치 최댓값을
[Tooltip("Volume 랜덤 범위 ± (기본 0.05 → ±5%)")]
[SerializeField][Range(0f, 0.2f)] private float volumeVariation = 0.05f; // 변수를 선언할거에요 -> 볼륨 변동 범위를
// ─────────────────────────────────────────────────────────
// 발자국 파티클
// ─────────────────────────────────────────────────────────
[Header("=== 발자국 파티클 ===")]
[Tooltip("발자국 파티클 프리팹 (없으면 파티클 생략)")]
[SerializeField] private GameObject footstepParticlePrefab; // 변수를 선언할거에요 -> 발자국 파티클 프리팹을
[Tooltip("파티클 자동 제거 시간 (초, 기본 2.0)")]
[SerializeField] private float particleDestroyTime = 2.0f; // 변수를 선언할거에요 -> 파티클 제거 시간을
// ─────────────────────────────────────────────────────────
// 참조
// ─────────────────────────────────────────────────────────
[Header("=== 참조 ===")]
[Tooltip("이동 속도 체크용 (비워두면 자동 캐싱)")]
[SerializeField] private PlayerMovement playerMovement; // 변수를 선언할거에요 -> 이동 속도 체크용을
// ─────────────────────────────────────────────────────────
// 내부 변수
// ─────────────────────────────────────────────────────────
private AudioSource _audioSource; // 변수를 선언할거에요 -> AudioSource를
private float _originalPitch; // 변수를 선언할거에요 -> 원래 Pitch를 (복원용)
private AudioClip _lastFootstepClip; // 변수를 선언할거에요 -> 마지막 재생 클립을 (반복 방지)
private float _lastFootstepTime; // 변수를 선언할거에요 -> 마지막 발소리 시간을 (쿨타임용)
private Transform _leftFootBone; // 변수를 선언할거에요 -> 왼발 본 Transform을
private Transform _rightFootBone; // 변수를 선언할거에요 -> 오른발 본 Transform을
private float _leftFootPrevY; // 변수를 선언할거에요 -> 이전 프레임 왼발 Y를 (Y속도 계산용)
private float _rightFootPrevY; // 변수를 선언할거에요 -> 이전 프레임 오른발 Y를 (Y속도 계산용)
private bool _leftFootGrounded; // 변수를 선언할거에요 -> 왼발 현재 접지 상태를 (연속 감지 방지)
private bool _rightFootGrounded; // 변수를 선언할거에요 -> 오른발 현재 접지 상태를 (연속 감지 방지)
// ─────────────────────────────────────────────────────────
// 초기화
// ─────────────────────────────────────────────────────────
private void Awake() // 함수를 실행할거에요 -> 초기화를
{
_audioSource = GetComponent<AudioSource>(); // 가져올거에요 -> AudioSource를
_audioSource.playOnAwake = false; // 끌거에요 -> 자동 재생을
_originalPitch = _audioSource.pitch; // 저장할거에요 -> 원래 Pitch를
if (playerMovement == null) // 조건이 맞으면 실행할거에요 -> 연결 안 됐으면
playerMovement = GetComponent<PlayerMovement>(); // 가져올거에요 -> 자동 캐싱
_leftFootBone = FindBoneRecursive(transform, leftFootBoneName); // 찾을거에요 -> 왼발 본을
_rightFootBone = FindBoneRecursive(transform, rightFootBoneName); // 찾을거에요 -> 오른발 본을
if (_leftFootBone == null) // 조건이 맞으면 실행할거에요 -> 못 찾으면
Debug.LogWarning($"[PlayerFootstep] 왼발 본 '{leftFootBoneName}' 을 찾지 못했어요!"); // 경고를 출력할거에요
if (_rightFootBone == null) // 조건이 맞으면 실행할거에요 -> 못 찾으면
Debug.LogWarning($"[PlayerFootstep] 오른발 본 '{rightFootBoneName}' 을 찾지 못했어요!"); // 경고를 출력할거에요
}
private void Start() // 함수를 실행할거에요 -> 시작 시 초기 Y 저장
{
// 첫 프레임 오감지 방지용 초기 Y 저장
if (_leftFootBone != null) _leftFootPrevY = _leftFootBone.position.y; // 저장할거에요 -> 왼발 초기 Y를
if (_rightFootBone != null) _rightFootPrevY = _rightFootBone.position.y; // 저장할거에요 -> 오른발 초기 Y를
}
// ─────────────────────────────────────────────────────────
// 매 프레임 발 Y속도 감지
// ─────────────────────────────────────────────────────────
private void Update() // 함수를 실행할거에요 -> 매 프레임 발 접지 감지를
{
// 이동 속도가 너무 낮으면 감지 스킵 (성능 최적화 + 제자리 방지)
if (playerMovement != null && playerMovement.GetCurrentSpeed() < minSpeedThreshold) // 조건이 맞으면 실행할거에요 -> 거의 안 움직이면
{
_leftFootGrounded = false; // 초기화할거에요 -> 다음 걸음 감지 준비로
_rightFootGrounded = false; // 초기화할거에요 -> 다음 걸음 감지 준비로
return; // 중단할거에요
}
if (_leftFootBone != null) // 조건이 맞으면 실행할거에요 -> 왼발 본 있으면
CheckFootLanding(_leftFootBone, ref _leftFootPrevY, ref _leftFootGrounded); // 확인할거에요 -> 왼발 접지를
if (_rightFootBone != null) // 조건이 맞으면 실행할거에요 -> 오른발 본 있으면
CheckFootLanding(_rightFootBone, ref _rightFootPrevY, ref _rightFootGrounded); // 확인할거에요 -> 오른발 접지를
}
// ─────────────────────────────────────────────────────────
// 발 접지 감지 핵심 로직
// ─────────────────────────────────────────────────────────
private void CheckFootLanding(Transform footBone, ref float prevY, ref bool isGrounded) // 함수를 선언할거에요 -> 발 접지를 감지하는 CheckFootLanding을
{
float currentY = footBone.position.y; // 가져올거에요 -> 현재 발의 월드 Y 좌표를
// 루트 기준 발 높이 계산 → 너무 높으면 공중(점프 중) → 무시
float footHeightAboveRoot = currentY - transform.position.y; // 계산할거에요 -> 루트 기준 발 높이를
if (footHeightAboveRoot > maxFootHeight) // 조건이 맞으면 실행할거에요 -> 발이 너무 높으면 (공중)
{
prevY = currentY; // 갱신할거에요 -> 이전 Y를
isGrounded = false; // 초기화할거에요 -> 접지 상태를
return; // 중단할거에요 -> 공중이므로 무시
}
// Y속도 계산: (현재Y - 이전Y) / deltaTime
// → 양수 = 올라가는 중 / 음수 = 내려오는 중 / 0에 가까움 = 멈춤
float yVelocity = (currentY - prevY) / Time.deltaTime; // 계산할거에요 -> 발의 Y축 속도를
// ⭐ 핵심 감지:
// Y속도가 임계값 이하 (내려오다 멈추는 순간) + 아직 접지 아닐 때
// = 발바닥이 실제로 바닥에 닿는 바로 그 순간
if (yVelocity <= landingVelocityThreshold && !isGrounded) // 조건이 맞으면 실행할거에요 -> 발이 내려오다 멈추는 순간
{
isGrounded = true; // 설정할거에요 -> 접지 상태로
TryPlayFootstep(footBone.position); // 재생할거에요 -> 발소리를
}
// 발이 다시 올라가기 시작하면 접지 해제 → 다음 스텝 감지 준비
else if (yVelocity > 0.001f && isGrounded) // 조건이 맞으면 실행할거에요 -> 발이 다시 올라가면
{
isGrounded = false; // 해제할거에요 -> 접지 상태를
}
prevY = currentY; // 갱신할거에요 -> 이전 Y를 현재 Y로 (다음 프레임 계산용)
}
// ─────────────────────────────────────────────────────────
// 발소리 재생
// ─────────────────────────────────────────────────────────
private void TryPlayFootstep(Vector3 footPosition) // 함수를 선언할거에요 -> 발소리 재생을 시도하는 TryPlayFootstep을
{
// 쿨타임 체크 (양발 동시 접지 시 중복 방지)
if (Time.time - _lastFootstepTime < footstepCooldown) return; // 중단할거에요 -> 쿨타임 중이면
// 현재 상태에 맞는 클립 세트 선택
AudioClip[] clips = GetCurrentClipSet(footPosition); // 가져올거에요 -> 클립 배열을
if (clips == null || clips.Length == 0) return; // 중단할거에요 -> 클립 없으면
// 직전 클립과 다른 클립 선택 (반복 방지)
AudioClip clip = PickNonRepeat(clips); // 뽑을거에요 -> 반복 없는 클립을
if (clip == null) return; // 중단할거에요 -> null이면
// 걷기/달리기에 따른 기본 볼륨 결정
float baseVolume = IsRunning() ? runVolume : walkVolume; // 결정할거에요 -> 볼륨을
// Pitch 랜덤 적용 (매번 다른 느낌)
_audioSource.pitch = UnityEngine.Random.Range(pitchMin, pitchMax); // 설정할거에요 -> 랜덤 Pitch를
// Volume 랜덤 적용
float vol = Mathf.Clamp( // 계산할거에요 -> 0~1 범위 랜덤 볼륨을
baseVolume + UnityEngine.Random.Range(-volumeVariation, volumeVariation),
0f, 1f
);
_audioSource.PlayOneShot(clip, vol); // 재생할거에요 -> 발소리를
_audioSource.pitch = _originalPitch; // 복원할거에요 -> 원래 Pitch로
_lastFootstepClip = clip; // 저장할거에요 -> 마지막 클립을
_lastFootstepTime = Time.time; // 저장할거에요 -> 마지막 재생 시간을
SpawnFootstepParticle(footPosition); // 생성할거에요 -> 발자국 파티클을
}
// ─────────────────────────────────────────────────────────
// 클립 세트 선택 (바닥 재질 + 이동 상태)
// ─────────────────────────────────────────────────────────
private AudioClip[] GetCurrentClipSet(Vector3 footPosition) // 함수를 선언할거에요 -> 현재 상태에 맞는 클립 배열을 반환하는 GetCurrentClipSet을
{
SurfaceType surface = DetectSurface(footPosition); // 감지할거에요 -> 바닥 재질을
// 재질별 클립 우선 반환
if (surfaceFootsteps != null) // 조건이 맞으면 실행할거에요 -> 재질별 설정 있으면
{
foreach (SurfaceFootstep sf in surfaceFootsteps) // 반복할거에요 -> 순회를
{
if (sf.surfaceType == surface && sf.clips != null && sf.clips.Length > 0) // 조건이 맞으면 실행할거에요 -> 일치하면
return sf.clips; // 반환할거에요 -> 재질 클립을
}
}
// 달리기 / 걷기 기본 세트
if (IsRunning() && runFootsteps != null && runFootsteps.Length > 0) // 조건이 맞으면 실행할거에요 -> 달리기 중이고 클립 있으면
return runFootsteps; // 반환할거에요 -> 달리기 클립을
return walkFootsteps; // 반환할거에요 -> 걷기 클립을
}
private SurfaceType DetectSurface(Vector3 position) // 함수를 선언할거에요 -> 바닥 재질을 감지하는 DetectSurface를
{
if (!Physics.Raycast(position + Vector3.up * 0.1f, Vector3.down, out RaycastHit hit, groundRayDistance, groundLayerMask)) // 조건이 맞으면 실행할거에요 -> 바닥 못 찾으면
return SurfaceType.Default; // 반환할거에요 -> 기본 타입을
SurfaceType surface = TagToSurface(hit.collider.tag); // 변환할거에요 -> Tag로 재질을
if (surface == SurfaceType.Default && hit.collider.sharedMaterial != null) // 조건이 맞으면 실행할거에요 -> Tag 실패 시 PhysicMaterial로
surface = NameToSurface(hit.collider.sharedMaterial.name); // 변환할거에요 -> 이름으로 재질을
return surface; // 반환할거에요 -> 감지된 재질을
}
// ─────────────────────────────────────────────────────────
// 발자국 파티클
// ─────────────────────────────────────────────────────────
private void SpawnFootstepParticle(Vector3 position) // 함수를 선언할거에요 -> 발자국 파티클을 생성하는 SpawnFootstepParticle을
{
if (footstepParticlePrefab == null) return; // 중단할거에요 -> 프리팹 없으면
Vector3 spawnPos = position; // 초기화할거에요 -> 생성 위치를
// Raycast로 정확한 바닥 표면 위치 찾기
if (Physics.Raycast(position + Vector3.up * 0.1f, Vector3.down, out RaycastHit hit, groundRayDistance, groundLayerMask)) // 조건이 맞으면 실행할거에요 -> 바닥 찾으면
spawnPos = hit.point; // 설정할거에요 -> 정확한 바닥 표면으로
GameObject particle = Instantiate(footstepParticlePrefab, spawnPos, Quaternion.identity); // 생성할거에요 -> 파티클 오브젝트를
Destroy(particle, particleDestroyTime); // 제거할거에요 -> 지정 시간 후 자동으로
}
// ─────────────────────────────────────────────────────────
// 유틸리티
// ─────────────────────────────────────────────────────────
private bool IsRunning() // 함수를 선언할거에요 -> 달리기 중인지 판별하는 IsRunning을
{
if (playerMovement == null) return false; // 반환할거에요 -> 참조 없으면 false를
return playerMovement.GetCurrentSpeed() >= runSpeedThreshold; // 반환할거에요 -> 속도 기준 이상이면 true를
}
private AudioClip PickNonRepeat(AudioClip[] clips) // 함수를 선언할거에요 -> 직전 클립과 다른 클립을 뽑는 PickNonRepeat를
{
if (clips.Length == 1) return clips[0]; // 반환할거에요 -> 1개뿐이면 그냥
AudioClip picked = clips[UnityEngine.Random.Range(0, clips.Length)]; // 뽑을거에요 -> 랜덤으로
if (picked == _lastFootstepClip) // 조건이 맞으면 실행할거에요 -> 직전과 같으면
{
int idx = Array.IndexOf(clips, picked); // 찾을거에요 -> 현재 인덱스를
picked = clips[(idx + 1) % clips.Length]; // 뽑을거에요 -> 다음 인덱스로
}
return picked; // 반환할거에요 -> 선택된 클립을
}
private Transform FindBoneRecursive(Transform parent, string boneName) // 함수를 선언할거에요 -> 본 이름으로 재귀 탐색하는 FindBoneRecursive를
{
if (parent.name == boneName) return parent; // 반환할거에요 -> 찾았으면 바로
foreach (Transform child in parent) // 반복할거에요 -> 모든 자식을
{
Transform found = FindBoneRecursive(child, boneName); // 탐색할거에요 -> 재귀로
if (found != null) return found; // 반환할거에요 -> 찾았으면
}
return null; // 반환할거에요 -> 없으면 null을
}
private SurfaceType TagToSurface(string tag) // 함수를 선언할거에요 -> Tag를 SurfaceType으로 변환하는 TagToSurface를
{
switch (tag)
{
case "Stone": return SurfaceType.Stone;
case "Dirt": return SurfaceType.Dirt;
case "Wood": return SurfaceType.Wood;
case "Metal": return SurfaceType.Metal;
case "Grass": return SurfaceType.Grass;
case "Water": return SurfaceType.Water;
default: return SurfaceType.Default;
}
}
private SurfaceType NameToSurface(string materialName) // 함수를 선언할거에요 -> PhysicMaterial 이름을 SurfaceType으로 변환하는 NameToSurface를
{
string lower = materialName.ToLower(); // 변환할거에요 -> 소문자로
if (lower.Contains("stone") || lower.Contains("concrete") || lower.Contains("rock")) return SurfaceType.Stone;
if (lower.Contains("dirt") || lower.Contains("sand") || lower.Contains("soil")) return SurfaceType.Dirt;
if (lower.Contains("wood") || lower.Contains("plank")) return SurfaceType.Wood;
if (lower.Contains("metal") || lower.Contains("iron") || lower.Contains("steel")) return SurfaceType.Metal;
if (lower.Contains("grass") || lower.Contains("lawn")) return SurfaceType.Grass;
if (lower.Contains("water") || lower.Contains("puddle")) return SurfaceType.Water;
return SurfaceType.Default;
}
// ─────────────────────────────────────────────────────────
// 에디터 디버그 (씬 뷰 시각화)
// ─────────────────────────────────────────────────────────
#if UNITY_EDITOR
private void OnDrawGizmos() // 함수를 실행할거에요 -> 씬 뷰 디버그를
{
if (!Application.isPlaying) return; // 중단할거에요 -> 실행 중 아니면
// 접지 상태에 따라 색상 변경 (초록 = 접지, 빨강 = 공중)
if (_leftFootBone != null) // 조건이 맞으면 실행할거에요 -> 왼발 본 있으면
{
Gizmos.color = _leftFootGrounded ? Color.green : Color.red; // 설정할거에요 -> 접지 여부 색상을
Gizmos.DrawWireSphere(_leftFootBone.position, 0.04f); // 그릴거에요 -> 왼발 위치 구를
}
if (_rightFootBone != null) // 조건이 맞으면 실행할거에요 -> 오른발 본 있으면
{
Gizmos.color = _rightFootGrounded ? Color.green : Color.red; // 설정할거에요 -> 접지 여부 색상을
Gizmos.DrawWireSphere(_rightFootBone.position, 0.04f); // 그릴거에요 -> 오른발 위치 구를
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 340cc097d528ea14ea52211fd54cf9fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,125 @@
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
// ============================================================
// ZoneBGMTrigger
//
// 역할: 플레이어가 트리거 존에 진입/이탈할 때
// AudioManager에 BGM 전환 요청
//
// 사용법:
// 1. 빈 오브젝트 생성
// 2. Collider 추가 → Is Trigger 체크
// 3. 이 컴포넌트 Add Component
// 4. Inspector에서 BGM 클립 연결
// 5. Player Tag = "Player" 확인
// ============================================================
[RequireComponent(typeof(Collider))] // 컴포넌트를 강제 추가할거에요 -> Collider를
public class ZoneBGMTrigger : MonoBehaviour // 클래스를 선언할거에요 -> ZoneBGMTrigger를
{
// ─────────────────────────────────────────────────────────
// Inspector 설정
// ─────────────────────────────────────────────────────────
[Header("=== 구역 설정 ===")]
[Tooltip("이 구역에서 재생할 BGM")]
[SerializeField] private AudioClip zoneBGM; // 변수를 선언할거에요 -> 이 구역 BGM을
[Tooltip("구역 이름 (디버그/식별용)")]
[SerializeField] private string zoneName = "Zone"; // 변수를 선언할거에요 -> 구역 이름을
[Header("=== 전환 설정 ===")]
[Tooltip("BGM 페이드 시간 (-1이면 AudioManager 기본값 사용)")]
[SerializeField] private float fadeDuration = -1f; // 변수를 선언할거에요 -> 페이드 시간을
[Tooltip("이 구역 이탈 시 BGM 정지 여부\n켜면: 이탈 시 BGM 정지\n꺼면: 이탈해도 BGM 유지 (다른 존 진입 전까지)")]
[SerializeField] private bool stopOnExit = false; // 변수를 선언할거에요 -> 이탈 시 정지 여부를
[Tooltip("진입 감지 Tag (기본 Player)")]
[SerializeField] private string playerTag = "Player"; // 변수를 선언할거에요 -> 플레이어 태그를
// ─────────────────────────────────────────────────────────
// 초기화
// ─────────────────────────────────────────────────────────
private void Awake() // 함수를 실행할거에요 -> 초기화를
{
// Collider가 Trigger로 설정됐는지 확인
Collider col = GetComponent<Collider>(); // 가져올거에요 -> Collider를
if (!col.isTrigger) // 조건이 맞으면 실행할거에요 -> Trigger가 아니면
{
col.isTrigger = true; // 설정할거에요 -> Trigger로
Debug.LogWarning($"[ZoneBGMTrigger] {gameObject.name}의 Collider를 자동으로 IsTrigger = true로 설정했어요."); // 경고를 출력할거에요
}
}
// ─────────────────────────────────────────────────────────
// 트리거 감지
// ─────────────────────────────────────────────────────────
private void OnTriggerEnter(Collider other) // 함수를 실행할거에요 -> 트리거 진입 시
{
if (!other.CompareTag(playerTag)) return; // 중단할거에요 -> 플레이어가 아니면
if (AudioManager.Instance == null) // 조건이 맞으면 실행할거에요 -> AudioManager 없으면
{
Debug.LogWarning("[ZoneBGMTrigger] AudioManager가 씬에 없어요!"); // 경고를 출력할거에요
return; // 중단할거에요
}
if (zoneBGM == null) // 조건이 맞으면 실행할거에요 -> BGM 클립 없으면
{
Debug.LogWarning($"[ZoneBGMTrigger] {zoneName}에 BGM 클립이 연결되지 않았어요!"); // 경고를 출력할거에요
return; // 중단할거에요
}
AudioManager.Instance.PlayBGM(zoneBGM, fadeDuration); // 재생할거에요 -> 이 구역 BGM을
Debug.Log($"[ZoneBGMTrigger] 구역 진입: {zoneName}"); // 출력할거에요 -> 진입 로그를
}
private void OnTriggerExit(Collider other) // 함수를 실행할거에요 -> 트리거 이탈 시
{
if (!other.CompareTag(playerTag)) return; // 중단할거에요 -> 플레이어가 아니면
if (!stopOnExit) return; // 중단할거에요 -> 이탈 시 정지 옵션이 꺼져있으면
if (AudioManager.Instance == null) return; // 중단할거에요 -> AudioManager 없으면
AudioManager.Instance.StopBGM(fadeDuration); // 정지할거에요 -> BGM을 페이드아웃으로
Debug.Log($"[ZoneBGMTrigger] 구역 이탈: {zoneName}"); // 출력할거에요 -> 이탈 로그를
}
// ─────────────────────────────────────────────────────────
// 에디터 디버그 (씬 뷰에서 트리거 영역 시각화)
// ─────────────────────────────────────────────────────────
private void OnDrawGizmos() // 함수를 실행할거에요 -> 씬 뷰 기즈모를
{
Collider col = GetComponent<Collider>(); // 가져올거에요 -> Collider를
if (col == null) return; // 중단할거에요 -> 없으면
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.2f); // 설정할거에요 -> 하늘색 반투명으로
Gizmos.matrix = transform.localToWorldMatrix; // 설정할거에요 -> 오브젝트 기준 행렬로
if (col is BoxCollider box) // 조건이 맞으면 실행할거에요 -> BoxCollider면
{
Gizmos.DrawCube(box.center, box.size); // 그릴거에요 -> 채워진 박스를
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.8f); // 설정할거에요 -> 불투명 테두리 색으로
Gizmos.DrawWireCube(box.center, box.size); // 그릴거에요 -> 테두리 박스를
}
else if (col is SphereCollider sphere) // 조건이 맞으면 실행할거에요 -> SphereCollider면
{
Gizmos.DrawSphere(sphere.center, sphere.radius); // 그릴거에요 -> 채워진 구를
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.8f); // 설정할거에요 -> 불투명 테두리 색으로
Gizmos.DrawWireSphere(sphere.center, sphere.radius); // 그릴거에요 -> 테두리 구를
}
#if UNITY_EDITOR
// 구역 이름 씬 뷰에 표시
UnityEditor.Handles.color = Color.cyan; // 설정할거에요 -> 하늘색으로
UnityEditor.Handles.Label(transform.position + Vector3.up * 1.5f, $"♪ {zoneName}"); // 출력할거에요 -> 구역 이름을
#endif
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 60b6051e965c38044a378f0dec6163e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -162,7 +162,8 @@ PlayerSettings:
resetResolutionOnWindowResize: 0 resetResolutionOnWindowResize: 0
androidSupportedAspectRatio: 1 androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1 androidMaxAspectRatio: 2.1
applicationIdentifier: {} applicationIdentifier:
Standalone: com.DefaultCompany.My-project
buildNumber: buildNumber:
Standalone: 0 Standalone: 0
VisionOS: 0 VisionOS: 0