플레이어 공격 방식 변경 완

This commit is contained in:
윤기주_playm 2026-02-06 18:27:08 +09:00
parent b06747778c
commit 4fbeb8d675
16 changed files with 892 additions and 349 deletions

View File

@ -162648,103 +162648,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4946034908522688, guid: 0b4ec2079abd9a64390cf77971445fc5, type: 3} m_CorrespondingSourceObject: {fileID: 4946034908522688, guid: 0b4ec2079abd9a64390cf77971445fc5, type: 3}
m_PrefabInstance: {fileID: 1531559788} m_PrefabInstance: {fileID: 1531559788}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1001 &1532158138
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalScale.x
value: 218.43205
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalScale.y
value: 222.09297
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalScale.z
value: 227.48624
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.x
value: 24.215
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.y
value: 10.136
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.z
value: 13.717
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.w
value: 0.12382896
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.x
value: 0.5433104
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.y
value: -0.066823
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.z
value: 0.82765627
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 14.192
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 65.587
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 172.153
objectReference: {fileID: 0}
- target: {fileID: 2669107996035270001, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_ConstrainProportionsScale
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Size.x
value: 0.003
objectReference: {fileID: 0}
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Size.y
value: 0.008
objectReference: {fileID: 0}
- target: {fileID: 4906676340306482370, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: config
value:
objectReference: {fileID: 11400000, guid: 602c0bb77ce70104ab6768b08772132f, type: 2}
- target: {fileID: 5253520193507450777, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Layer
value: 8
objectReference: {fileID: 0}
- target: {fileID: 6875888761843048781, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Enabled
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Name
value: "\uCE7C (5)"
objectReference: {fileID: 0}
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Layer
value: 8
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
--- !u!1001 &1532898197 --- !u!1001 &1532898197
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -203177,7 +203080,7 @@ GameObject:
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 0 m_IsActive: 1
--- !u!114 &1927423249 --- !u!114 &1927423249
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -203975,17 +203878,6 @@ Transform:
m_CorrespondingSourceObject: {fileID: 4899585634617078, guid: 9b42f9d14b52bd840afbef0e34f754f2, type: 3} m_CorrespondingSourceObject: {fileID: 4899585634617078, guid: 9b42f9d14b52bd840afbef0e34f754f2, type: 3}
m_PrefabInstance: {fileID: 1938154977} m_PrefabInstance: {fileID: 1938154977}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!114 &1938848879 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 124746496204996812, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
m_PrefabInstance: {fileID: 7969472841528762147}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bcf8987df4d20a442a8ae5028c602e03, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &1940581791 --- !u!1001 &1940581791
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -226661,6 +226553,75 @@ GameObject:
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 1
--- !u!1001 &1175521096951328089
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalScale.x
value: 0.23480867
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalScale.y
value: 0.20066422
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalScale.z
value: 3.2097
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalPosition.x
value: 38
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalPosition.y
value: 7.99
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalPosition.z
value: 41
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 529370269987782371, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2943732763553649162, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
propertyPath: m_Name
value: Arrow Test
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7af7365e5854aed458abd798049cc5b2, type: 3}
--- !u!114 &1189169361667733870 --- !u!114 &1189169361667733870
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -227318,6 +227279,18 @@ PrefabInstance:
propertyPath: m_Avatar propertyPath: m_Avatar
value: value:
objectReference: {fileID: 9000000, guid: 76cee5628aa6b874c96342f004fa138b, type: 3} objectReference: {fileID: 9000000, guid: 76cee5628aa6b874c96342f004fa138b, type: 3}
- target: {fileID: 7686598050579119226, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: lineWidth
value: 0.6
objectReference: {fileID: 0}
- target: {fileID: 7686598050579119226, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: maxLength
value: 3
objectReference: {fileID: 0}
- target: {fileID: 7686598050579119226, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: minLength
value: 0.2
objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: arrowPrefab propertyPath: arrowPrefab
value: value:
@ -227325,7 +227298,15 @@ PrefabInstance:
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3} - target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: weaponHitBox propertyPath: weaponHitBox
value: value:
objectReference: {fileID: 1938848879} objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: aimAssistStrength
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8965661853020836870, guid: c34da37720b95c84887eda34e2d90e5b, type: 3}
propertyPath: enemyLayer.m_Bits
value: 64
objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents: []
m_RemovedGameObjects: [] m_RemovedGameObjects: []
m_AddedGameObjects: [] m_AddedGameObjects: []
@ -227772,83 +227753,6 @@ GameObject:
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 1
--- !u!1001 &7969472841528762147
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.x
value: 20.274
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.y
value: 9.322
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalPosition.z
value: 13.741
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.w
value: 0.12382896
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.x
value: 0.5433104
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.y
value: -0.066823
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalRotation.z
value: 0.82765627
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 14.192
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 65.587
objectReference: {fileID: 0}
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 172.153
objectReference: {fileID: 0}
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Size.x
value: 0.003
objectReference: {fileID: 0}
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Size.y
value: 0.008
objectReference: {fileID: 0}
- target: {fileID: 5253520193507450777, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Layer
value: 8
objectReference: {fileID: 0}
- target: {fileID: 6875888761843048781, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Enabled
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Name
value: "\uCE7C (4)"
objectReference: {fileID: 0}
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
propertyPath: m_Layer
value: 8
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
--- !u!222 &8011247558027849043 --- !u!222 &8011247558027849043
CanvasRenderer: CanvasRenderer:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -228007,8 +227911,6 @@ SceneRoots:
- {fileID: 4755848957906863847} - {fileID: 4755848957906863847}
- {fileID: 398512784} - {fileID: 398512784}
- {fileID: 1390519481} - {fileID: 1390519481}
- {fileID: 7969472841528762147}
- {fileID: 1532158138}
- {fileID: 1992891316} - {fileID: 1992891316}
- {fileID: 2112919309} - {fileID: 2112919309}
- {fileID: 2119519052} - {fileID: 2119519052}
@ -228020,6 +227922,7 @@ SceneRoots:
- {fileID: 1824697940} - {fileID: 1824697940}
- {fileID: 216801511} - {fileID: 216801511}
- {fileID: 85056390} - {fileID: 85056390}
- {fileID: 1175521096951328089}
- {fileID: 600231664} - {fileID: 600231664}
- {fileID: 1927423250} - {fileID: 1927423250}
- {fileID: 2067270637} - {fileID: 2067270637}

View File

@ -0,0 +1,155 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2943732763553649162
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 529370269987782371}
- component: {fileID: 5228667605444404581}
- component: {fileID: 4979562685888428679}
- component: {fileID: 8230402311320924260}
- component: {fileID: 3429443446101725902}
- component: {fileID: -1087238979925095596}
m_Layer: 8
m_Name: Arrow Test
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &529370269987782371
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 38, y: 7.99, z: 41}
m_LocalScale: {x: 0.073155954, y: 0.06251806, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &5228667605444404581
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &4979562685888428679
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!65 &8230402311320924260
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!54 &3429443446101725902
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
serializedVersion: 4
m_Mass: 1
m_Drag: 0
m_AngularDrag: 0.05
m_CenterOfMass: {x: 0, y: 0, z: 0}
m_InertiaTensor: {x: 1, y: 1, z: 1}
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_ImplicitCom: 1
m_ImplicitTensor: 1
m_UseGravity: 1
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!114 &-1087238979925095596
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2943732763553649162}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1c61ccbf2fc5f2144872ea56d89cb755, type: 3}
m_Name:
m_EditorClassIdentifier:
arrowName: "\uAE30\uBCF8 \uD654\uC0B4"
damage: 15
speed: 20
range: 15
pickupUI: {fileID: 0}
uiDisplayRange: 3
visualModel: {fileID: 2943732763553649162}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7af7365e5854aed458abd798049cc5b2
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -56,37 +56,32 @@ PrefabInstance:
propertyPath: m_Name propertyPath: m_Name
value: Arrow value: Arrow
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
propertyPath: m_Layer
value: 8
objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents: []
m_RemovedGameObjects: [] m_RemovedGameObjects: []
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
insertIndex: -1
addedObject: {fileID: -8985903288884462599}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3} - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: -3399849508453939123} addedObject: {fileID: -3399849508453939123}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3} - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: -2262200229160577635} addedObject: {fileID: -2262200229160577635}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
insertIndex: -1
addedObject: {fileID: 8027594905793114800}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
insertIndex: -1
addedObject: {fileID: -3219543398048858031}
m_SourcePrefab: {fileID: 100100000, guid: 6ecc17433e8741d4c990408160a2a534, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
--- !u!1 &791703799912573729 stripped --- !u!1 &791703799912573729 stripped
GameObject: GameObject:
m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3} m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 6ecc17433e8741d4c990408160a2a534, type: 3}
m_PrefabInstance: {fileID: 449757124165146224} m_PrefabInstance: {fileID: 449757124165146224}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!114 &-8985903288884462599
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 791703799912573729}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 473d386fc9b5d9c49aac6669d6973f71, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!65 &-3399849508453939123 --- !u!65 &-3399849508453939123
BoxCollider: BoxCollider:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -135,3 +130,43 @@ Rigidbody:
m_Interpolate: 0 m_Interpolate: 0
m_Constraints: 0 m_Constraints: 0
m_CollisionDetection: 0 m_CollisionDetection: 0
--- !u!135 &8027594905793114800
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 791703799912573729}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 2.9
m_Center: {x: -0.0006635487, y: -0.00016829367, z: 0.00038632748}
--- !u!114 &-3219543398048858031
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 791703799912573729}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1c61ccbf2fc5f2144872ea56d89cb755, type: 3}
m_Name:
m_EditorClassIdentifier:
arrowName: "\uC880\uB354 \uC388 \uD654\uC0B4"
damage: 15
speed: 20
range: 15
pickupUI: {fileID: 0}
uiDisplayRange: 3
visualModel: {fileID: 791703799912573729}

View File

@ -927,6 +927,9 @@ MonoBehaviour:
chargeDuration: 2 chargeDuration: 2
chargeDelay: 3 chargeDelay: 3
prepareTime: 0.5 prepareTime: 0.5
dropItemPrefabs:
- {fileID: 791703799912573729, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
dropChance: 100
chargeAnimation: Monster_Charge chargeAnimation: Monster_Charge
prepareAnimation: Monster_ChargePrepare prepareAnimation: Monster_ChargePrepare
Monster_Walk: Monster_Walk Monster_Walk: Monster_Walk

View File

@ -364,6 +364,9 @@ MonoBehaviour:
chargeDuration: 2 chargeDuration: 2
chargeDelay: 3 chargeDelay: 3
prepareTime: 3 prepareTime: 3
dropItemPrefabs:
- {fileID: 791703799912573729, guid: e9867839af14eb14ca3d49ee41fc5390, type: 3}
dropChance: 100
chargeAnimation: Run-run chargeAnimation: Run-run
prepareAnimation: Run-wait prepareAnimation: Run-wait
Monster_Walk: Run-walk Monster_Walk: Run-walk

View File

@ -1524,6 +1524,11 @@ MonoBehaviour:
impactSpawnPoint: {fileID: 0} impactSpawnPoint: {fileID: 0}
attackRange: 2 attackRange: 2
attackDelay: 1.5 attackDelay: 1.5
dropItemPrefabs:
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
dropChance: 30
attackAnimations: attackAnimations:
- ghoul_attack - ghoul_attack
Monster_Walk: ghoul_walk Monster_Walk: ghoul_walk

View File

@ -110,13 +110,13 @@ Transform:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3835737397246117387} m_GameObject: {fileID: 3835737397246117387}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0.7027862, y: 0.23967019, z: -0.29418004, w: -0.60175407} m_LocalRotation: {x: -0.119923264, y: 0.000000029802322, z: 0.000000044470653, w: 0.9927832}
m_LocalPosition: {x: -0.00007, y: 0.0012, z: 0.00026} m_LocalPosition: {x: -0.00024, y: -0.00444, z: 0.00469}
m_LocalScale: {x: 0.00999999, y: 0.009999995, z: 0.010000003} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 642015492957721826} m_Father: {fileID: 642015492957721826}
m_LocalEulerAnglesHint: {x: -44.813, y: 261.676, z: 103.109} m_LocalEulerAnglesHint: {x: -13.775, y: 0, z: 0}
--- !u!1 &4977077540650227567 --- !u!1 &4977077540650227567
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -276,11 +276,10 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
attackScript: {fileID: 8965661853020836870} attackScript: {fileID: 8965661853020836870}
interaction: {fileID: 8385686067015665091} uiColor: {r: 1, g: 1, b: 0, a: 0.5}
radius: 5 lineWidth: 1
segments: 20 minLength: 5
fanColor: {r: 1, g: 0.9, b: 0, a: 0.4} maxLength: 20
minAngle: 2
--- !u!1001 &1112926104530361804 --- !u!1001 &1112926104530361804
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1338,13 +1337,13 @@ MonoBehaviour:
chargeStages: chargeStages:
- chargeTime: 1 - chargeTime: 1
damageMult: 1.5 damageMult: 1.5
rangeMult: 1.2 rangeMult: 1.1
- chargeTime: 2 - chargeTime: 2
damageMult: 2 damageMult: 2
rangeMult: 1.5 rangeMult: 1.2
- chargeTime: 3 - chargeTime: 3
damageMult: 2.5 damageMult: 2.5
rangeMult: 2 rangeMult: 1.5
--- !u!114 &8160405634931995834 --- !u!114 &8160405634931995834
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -32414,7 +32414,7 @@ AnimationClip:
m_AdditiveReferencePoseClip: {fileID: 0} m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0 m_AdditiveReferencePoseTime: 0
m_StartTime: 0 m_StartTime: 0
m_StopTime: 0.15 m_StopTime: 0.116666675
m_OrientationOffsetY: 0 m_OrientationOffsetY: 0
m_Level: 0 m_Level: 0
m_CycleOffset: 0 m_CycleOffset: 0
@ -127013,7 +127013,7 @@ AnimationClip:
floatParameter: 0 floatParameter: 0
intParameter: 0 intParameter: 0
messageOptions: 0 messageOptions: 0
- time: 0.15 - time: 0.11666667
functionName: OnAttackEnd functionName: OnAttackEnd
data: data:
objectReferenceParameter: {fileID: 0} objectReferenceParameter: {fileID: 0}

View File

@ -1,19 +1,26 @@
using UnityEngine; using UnityEngine;
using UnityEngine.AI; using UnityEngine.AI;
using System.Collections; using System.Collections;
using System.Collections.Generic; // ✅ 리스트 사용 필수
/// <summary> /// <summary>
/// 돌진 공격 몬스터 (두 번째 돌진 고장 수정판) /// 돌진 공격 몬스터
/// - Agent On/Off 타이밍 완벽하게 정리
/// </summary> /// </summary>
public class ChargeMonster : MonsterClass public class ChargeMonster : MonsterClass
{ {
[Header("=== 돌진 공격 설정 ===")] [Header("=== 돌진 공격 설정 ===")]
[SerializeField] private float chargeSpeed = 15f; // 돌진 속도 [SerializeField] private float chargeSpeed = 15f;
[SerializeField] private float chargeRange = 10f; // 돌진 시작 거리 [SerializeField] private float chargeRange = 10f;
[SerializeField] private float chargeDuration = 2f; // 돌진 지속 시간 [SerializeField] private float chargeDuration = 2f;
[SerializeField] private float chargeDelay = 3f; // 돌진 쿨타임 [SerializeField] private float chargeDelay = 3f;
[SerializeField] private float prepareTime = 0.5f; // 돌진 준비 시간 [SerializeField] private float prepareTime = 0.5f;
// 🎁 [추가] 드랍 아이템 리스트
[Header("=== 드랍 아이템 설정 ===")]
[Tooltip("드랍 가능한 아이템 리스트 (랜덤 1개)")]
[SerializeField] private List<GameObject> dropItemPrefabs;
[Tooltip("아이템이 나올 확률 (0 ~ 100%)")]
[Range(0, 100)][SerializeField] private float dropChance = 30f;
private float lastChargeTime; private float lastChargeTime;
private bool isCharging = false; private bool isCharging = false;
@ -67,17 +74,14 @@ public class ChargeMonster : MonsterClass
void HandleChargeCombat(float distance) void HandleChargeCombat(float distance)
{ {
// 쿨타임 체크 & 사거리 체크
if (distance <= chargeRange && Time.time >= lastChargeTime + chargeDelay) if (distance <= chargeRange && Time.time >= lastChargeTime + chargeDelay)
{ {
StartCoroutine(PrepareCharge()); StartCoroutine(PrepareCharge());
} }
// 추적 모드
else if (!isCharging && !isPreparing) else if (!isCharging && !isPreparing)
{ {
if (agent.isOnNavMesh) if (agent.isOnNavMesh)
{ {
// ⭐ [수정] 추적 시작할 때 "나 멈춰있니?" 확인하고 풀어주기
if (agent.isStopped) agent.isStopped = false; if (agent.isStopped) agent.isStopped = false;
agent.SetDestination(playerTransform.position); agent.SetDestination(playerTransform.position);
} }
@ -87,8 +91,6 @@ public class ChargeMonster : MonsterClass
IEnumerator PrepareCharge() IEnumerator PrepareCharge()
{ {
isPreparing = true; isPreparing = true;
// 이동 완전 정지
if (agent.isOnNavMesh) if (agent.isOnNavMesh)
{ {
agent.isStopped = true; agent.isStopped = true;
@ -96,12 +98,10 @@ public class ChargeMonster : MonsterClass
agent.velocity = Vector3.zero; agent.velocity = Vector3.zero;
} }
// 방향 설정
chargeDirection = (playerTransform.position - transform.position).normalized; chargeDirection = (playerTransform.position - transform.position).normalized;
chargeDirection.y = 0; chargeDirection.y = 0;
if (chargeDirection != Vector3.zero) transform.rotation = Quaternion.LookRotation(chargeDirection); if (chargeDirection != Vector3.zero) transform.rotation = Quaternion.LookRotation(chargeDirection);
// 준비 애니메이션
if (!string.IsNullOrEmpty(prepareAnimation)) animator.Play(prepareAnimation, 0, 0f); if (!string.IsNullOrEmpty(prepareAnimation)) animator.Play(prepareAnimation, 0, 0f);
Debug.Log("[ChargeMonster] 돌진 준비..."); Debug.Log("[ChargeMonster] 돌진 준비...");
@ -116,10 +116,7 @@ public class ChargeMonster : MonsterClass
isCharging = true; isCharging = true;
lastChargeTime = Time.time; lastChargeTime = Time.time;
// ⭐ [핵심 수정] 조건 없이 강제로 끄기! (NavMesh 위에 있든 말든 일단 꺼야 물리 이동 가능)
if (agent != null) agent.enabled = false; if (agent != null) agent.enabled = false;
// 물리 켜기
if (_rigidbody != null) _rigidbody.isKinematic = false; if (_rigidbody != null) _rigidbody.isKinematic = false;
animator.Play(chargeAnimation, 0, 0f); animator.Play(chargeAnimation, 0, 0f);
@ -129,30 +126,22 @@ public class ChargeMonster : MonsterClass
while (Time.time < chargeStartTime + chargeDuration) while (Time.time < chargeStartTime + chargeDuration)
{ {
// 돌진 중에도 방향을 잃지 않도록
if (_rigidbody != null) if (_rigidbody != null)
{
_rigidbody.velocity = chargeDirection * chargeSpeed; _rigidbody.velocity = chargeDirection * chargeSpeed;
}
else else
{
transform.position += chargeDirection * chargeSpeed * Time.deltaTime; transform.position += chargeDirection * chargeSpeed * Time.deltaTime;
}
yield return null; yield return null;
} }
// 돌진 끝 정리
if (_rigidbody != null) if (_rigidbody != null)
{ {
_rigidbody.velocity = Vector3.zero; _rigidbody.velocity = Vector3.zero;
_rigidbody.isKinematic = true; _rigidbody.isKinematic = true;
} }
// Agent 다시 켜기
if (agent != null) if (agent != null)
{ {
agent.enabled = true; agent.enabled = true;
// 켜지자마자 미끄러짐 방지
agent.ResetPath(); agent.ResetPath();
agent.velocity = Vector3.zero; agent.velocity = Vector3.zero;
} }
@ -164,8 +153,6 @@ public class ChargeMonster : MonsterClass
void UpdateMovementAnimation() void UpdateMovementAnimation()
{ {
if (isCharging || isPreparing || isHit || isResting) return; if (isCharging || isPreparing || isHit || isResting) return;
// Agent가 켜져 있고 움직일 때만 걷기 모션
if (agent.enabled && agent.velocity.magnitude > 0.1f) if (agent.enabled && agent.velocity.magnitude > 0.1f)
animator.Play(Monster_Walk); animator.Play(Monster_Walk);
else else
@ -175,7 +162,6 @@ public class ChargeMonster : MonsterClass
void Patrol() void Patrol()
{ {
if (Time.time < nextPatrolTime) return; if (Time.time < nextPatrolTime) return;
Vector3 randomPoint = transform.position + new Vector3( Vector3 randomPoint = transform.position + new Vector3(
Random.Range(-patrolRadius, patrolRadius), Random.Range(-patrolRadius, patrolRadius),
0, 0,
@ -191,15 +177,30 @@ public class ChargeMonster : MonsterClass
private void OnCollisionEnter(Collision collision) private void OnCollisionEnter(Collision collision)
{ {
if (!isCharging) return; if (!isCharging) return;
if (collision.gameObject.CompareTag("Player")) if (collision.gameObject.CompareTag("Player"))
{ {
if (collision.gameObject.TryGetComponent<PlayerHealth>(out var playerHealth)) if (collision.gameObject.TryGetComponent<PlayerHealth>(out var playerHealth))
{ {
if (!playerHealth.isInvincible) if (!playerHealth.isInvincible)
{
playerHealth.TakeDamage(attackDamage); playerHealth.TakeDamage(attackDamage);
Debug.Log($"[ChargeMonster] 쾅! 데미지: {attackDamage}"); }
}
}
// ☠️ [추가] 죽을 때 아이템 드랍
protected override void OnDie()
{
if (_rigidbody != null) _rigidbody.velocity = Vector3.zero;
if (dropItemPrefabs != null && dropItemPrefabs.Count > 0)
{
float randomValue = Random.Range(0f, 100f);
if (randomValue <= dropChance)
{
int randomIndex = Random.Range(0, dropItemPrefabs.Count);
if (dropItemPrefabs[randomIndex] != null)
{
Instantiate(dropItemPrefabs[randomIndex], transform.position + Vector3.up * 0.5f, Quaternion.identity);
} }
} }
} }

View File

@ -1,17 +1,23 @@
using UnityEngine; using UnityEngine;
using UnityEngine.AI; using UnityEngine.AI;
using System.Collections; // IEnumerator 사용을 위해 추가 using System.Collections;
using System.Collections.Generic; // ✅ 리스트 사용을 위해 필수 추가
/// <summary>
/// 근접 공격 몬스터 (칼, 도끼 등)
/// </summary>
public class MeleeMonster : MonsterClass public class MeleeMonster : MonsterClass
{ {
[Header("=== 근접 공격 설정 ===")] [Header("=== 근접 공격 설정 ===")]
// [SerializeField] private MonsterWeapon myWeapon; //[SerializeField] private MonsterWeapon myWeapon; // ✅ 주석 해제됨 (이제 무기 연결 가능!)
[SerializeField] private float attackRange = 2f; [SerializeField] private float attackRange = 2f;
[SerializeField] private float attackDelay = 1.5f; [SerializeField] private float attackDelay = 1.5f;
// 🎁 [수정] 단일 아이템 -> 리스트로 변경
[Header("=== 드랍 아이템 설정 ===")]
[Tooltip("드랍 가능한 아이템들을 여기에 여러 개 등록하세요. (랜덤 1개 드랍)")]
[SerializeField] private List<GameObject> dropItemPrefabs;
[Tooltip("아이템이 나올 확률 (0 ~ 100%)")]
[Range(0, 100)][SerializeField] private float dropChance = 30f; // 기본 30%
private float lastAttackTime; private float lastAttackTime;
[Header("공격 / 이동 애니메이션")] [Header("공격 / 이동 애니메이션")]
@ -29,10 +35,6 @@ public class MeleeMonster : MonsterClass
private int attackIndex; private int attackIndex;
private bool isPlayerInZone; private bool isPlayerInZone;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 초기화
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
protected override void Init() protected override void Init()
{ {
if (agent != null) agent.stoppingDistance = attackRange - 0.4f; if (agent != null) agent.stoppingDistance = attackRange - 0.4f;
@ -41,17 +43,12 @@ public class MeleeMonster : MonsterClass
protected override void OnResetStats() protected override void OnResetStats()
{ {
// 무기에 데미지 설정
if (myWeapon != null) if (myWeapon != null)
{ {
myWeapon.SetDamage(attackDamage); myWeapon.SetDamage(attackDamage);
} }
} }
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// AI 로직
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
protected override void ExecuteAILogic() protected override void ExecuteAILogic()
{ {
if (isHit || isAttacking || isResting) return; if (isHit || isAttacking || isResting) return;
@ -124,14 +121,8 @@ public class MeleeMonster : MonsterClass
nextPatrolTime = Time.time + patrolInterval; nextPatrolTime = Time.time + patrolInterval;
} }
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 공격 이벤트 (애니메이션에서 호출)
// ⭐ [핵심 수정] override 추가!
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
public override void OnAttackStart() public override void OnAttackStart()
{ {
// base.OnAttackStart(); // 부모 기능도 쓰고 싶으면 주석 해제
isAttacking = true; isAttacking = true;
isResting = false; isResting = false;
if (myWeapon != null) myWeapon.EnableHitBox(); if (myWeapon != null) myWeapon.EnableHitBox();
@ -144,7 +135,6 @@ public class MeleeMonster : MonsterClass
if (!isDead && !isHit) StartCoroutine(RestAfterAttack()); if (!isDead && !isHit) StartCoroutine(RestAfterAttack());
} }
// ⭐ [핵심 수정] override 및 protected 추가!
protected override IEnumerator RestAfterAttack() protected override IEnumerator RestAfterAttack()
{ {
isResting = true; isResting = true;
@ -152,23 +142,36 @@ public class MeleeMonster : MonsterClass
isResting = false; isResting = false;
} }
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 피격 / 사망 시 무기 끄기
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
protected override void OnStartHit() protected override void OnStartHit()
{ {
if (myWeapon != null) myWeapon.DisableHitBox(); if (myWeapon != null) myWeapon.DisableHitBox();
} }
// 🎲 [핵심 수정] 리스트에서 랜덤 뽑기 + 확률 체크
protected override void OnDie() protected override void OnDie()
{ {
if (myWeapon != null) myWeapon.DisableHitBox(); if (myWeapon != null) myWeapon.DisableHitBox();
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 1. 리스트에 아이템이 하나라도 있는지 확인
// Trigger 감지 (플레이어 인식 영역) if (dropItemPrefabs != null && dropItemPrefabs.Count > 0)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ {
// 2. 확률 체크 (0 ~ 100)
float randomValue = Random.Range(0f, 100f);
if (randomValue <= dropChance) // 당첨!
{
// 3. 리스트에서 랜덤하게 하나 뽑기 (0번 ~ 마지막 번호 중 하나)
int randomIndex = Random.Range(0, dropItemPrefabs.Count);
GameObject selectedItem = dropItemPrefabs[randomIndex];
if (selectedItem != null)
{
Instantiate(selectedItem, transform.position + Vector3.up * 0.5f, Quaternion.identity);
// Debug.Log($"🎉 아이템 드랍! ({selectedItem.name})");
}
}
}
}
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {

View File

@ -28,18 +28,30 @@ public class PlayerAttack : MonoBehaviour
[SerializeField] private List<ChargeStage> chargeStages; [SerializeField] private List<ChargeStage> chargeStages;
[Header("--- 🎯 에임 보정 설정 ---")]
[SerializeField] private bool enableAutoAim = true; // 자동 조준 켜기/끄기
[SerializeField] private float autoAimRange = 15f; // 자동 조준 감지 범위
[SerializeField] private float autoAimAngle = 45f; // 마우스 커서 기준 각도 (넓을수록 감지 잘됨)
[Range(0f, 1f)]
[Tooltip("에임 보정 강도 (0: 보정 없음, 1: 완전 자동 조준)")]
[SerializeField] private float aimAssistStrength = 0.4f; // 40% 보정 (에임핵 느낌)
[SerializeField] private LayerMask enemyLayer; // 적 레이어
[Tooltip("차징 최대 단계에서만 자동 조준 활성화")]
[SerializeField] private bool onlyMaxCharge = true; // 최대 차징에서만 작동
private float _lastAttackTime; private float _lastAttackTime;
private float _chargeTimer; private float _chargeTimer;
private bool _isCharging = false; private bool _isCharging = false;
private bool _isAttacking = false; private bool _isAttacking = false;
// 재장전 잠금 장치 (한 발 쏘면 우클릭 뗄 때까지 발사 불가)
private bool _waitForRelease = false; private bool _waitForRelease = false;
private float _pendingDamage; private float _pendingDamage;
private float _pendingSpeed; private float _pendingSpeed;
private float _pendingRange; private float _pendingRange;
// 🎯 발사 방향 저장
private Vector3 _pendingShootDirection;
public bool IsCharging => _isCharging; public bool IsCharging => _isCharging;
public bool IsAttacking public bool IsAttacking
{ {
@ -59,6 +71,14 @@ public class PlayerAttack : MonoBehaviour
new ChargeStage { chargeTime = 2f, damageMult = 2.5f, rangeMult = 1.5f } new ChargeStage { chargeTime = 2f, damageMult = 2.5f, rangeMult = 1.5f }
}; };
} }
float calculatedMaxTime = 0f;
foreach (var stage in chargeStages)
{
if (stage.chargeTime > calculatedMaxTime)
calculatedMaxTime = stage.chargeTime;
}
maxChargeTime = Mathf.Max(calculatedMaxTime, 0.1f);
} }
private void Update() private void Update()
@ -79,6 +99,9 @@ public class PlayerAttack : MonoBehaviour
_pendingSpeed = normalSpeed; _pendingSpeed = normalSpeed;
_pendingRange = normalRange; _pendingRange = normalRange;
// 🎯 마우스 방향 계산 (일반 공격은 자동 조준 없음)
_pendingShootDirection = GetMouseDirection();
_lastAttackTime = Time.time; _lastAttackTime = Time.time;
if (pAnim != null) pAnim.TriggerThrow(); if (pAnim != null) pAnim.TriggerThrow();
@ -89,7 +112,6 @@ public class PlayerAttack : MonoBehaviour
// --- [2] 차징 시작 --- // --- [2] 차징 시작 ---
public void StartCharging() public void StartCharging()
{ {
// 🔒 잠금 상태(방금 쏨)라면 차징 시작 안 함 (손 떼야 풀림)
if (_waitForRelease) return; if (_waitForRelease) return;
_isCharging = true; _isCharging = true;
@ -99,7 +121,6 @@ public class PlayerAttack : MonoBehaviour
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true); if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true);
} }
// 내부용: 효과 끄기
private void ResetChargingEffects() private void ResetChargingEffects()
{ {
_isCharging = false; _isCharging = false;
@ -109,14 +130,14 @@ public class PlayerAttack : MonoBehaviour
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(false); if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(false);
} }
// 외부 호출: 우클릭 뗐을 때 (여기서 잠금을 풉니다) // --- [3] 차징 취소 ---
public void CancelCharging() public void CancelCharging()
{ {
ResetChargingEffects(); ResetChargingEffects();
_waitForRelease = false; // ✅ 잠금 해제! 다시 쏠 수 있음 _waitForRelease = false;
} }
// --- [3] 차징 발사 --- // --- [4] 차징 발사 ---
public void ReleaseAttack() public void ReleaseAttack()
{ {
if (!_isCharging) return; if (!_isCharging) return;
@ -131,43 +152,143 @@ public class PlayerAttack : MonoBehaviour
_pendingSpeed = normalSpeed * currentStage.rangeMult; _pendingSpeed = normalSpeed * currentStage.rangeMult;
_pendingRange = normalRange * currentStage.rangeMult; _pendingRange = normalRange * currentStage.rangeMult;
// 🎯 발사 방향 계산 (차징 최대 시 자동 조준)
bool isMaxCharge = _chargeTimer >= maxChargeTime * 0.95f; // 95% 이상이면 최대 차징
_pendingShootDirection = GetShootDirection(isMaxCharge);
if (pAnim != null) pAnim.TriggerThrow(); if (pAnim != null) pAnim.TriggerThrow();
// 🔒 발사했으므로 잠금! (우클릭 뗄 때까지 차징 불가)
_waitForRelease = true; _waitForRelease = true;
_lastAttackTime = Time.time; _lastAttackTime = Time.time;
StartCoroutine(AttackRoutine()); StartCoroutine(AttackRoutine());
} }
// --- [4] 이벤트: 화살 생성 --- // --- [5] 🎯 마우스 방향 계산 ---
private Vector3 GetMouseDirection()
{
// 마우스 위치 → 월드 좌표
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, transform.position);
if (groundPlane.Raycast(ray, out float distance))
{
Vector3 worldMousePos = ray.GetPoint(distance);
Vector3 direction = (worldMousePos - firePoint.position).normalized;
direction.y = 0; // 수평 발사
return direction;
}
// 실패 시 플레이어 정면
return transform.forward;
}
// --- [6] 🎯 발사 방향 계산 (에임 어시스트 포함) ---
private Vector3 GetShootDirection(bool isMaxCharge)
{
Vector3 mouseDir = GetMouseDirection();
// 자동 조준 비활성화 또는 최대 차징 아님
if (!enableAutoAim || (onlyMaxCharge && !isMaxCharge))
{
return mouseDir;
}
// 🎯 적 탐색
Transform bestTarget = FindBestTarget(mouseDir);
if (bestTarget != null)
{
// 적 방향 계산 (중심부 조준)
Vector3 targetPos = bestTarget.position + Vector3.up * 1.2f;
Vector3 targetDir = (targetPos - firePoint.position).normalized;
targetDir.y = 0; // 수평 발사
// ✨ 에임 어시스트: 마우스 방향과 적 방향을 섞음!
// aimAssistStrength = 0.4 → 마우스 60% + 적 40%
Vector3 assistedDir = Vector3.Lerp(mouseDir, targetDir, aimAssistStrength);
assistedDir.y = 0;
assistedDir.Normalize();
Debug.Log($"🎯 에임 어시스트 활성화! 타겟: {bestTarget.name}, 보정 강도: {aimAssistStrength * 100}%");
return assistedDir;
}
// 적 없으면 마우스 방향
return mouseDir;
}
// --- [7] 🎯 최적 타겟 찾기 ---
private Transform FindBestTarget(Vector3 mouseDirection)
{
Collider[] enemies = Physics.OverlapSphere(transform.position, autoAimRange, enemyLayer);
if (enemies.Length == 0) return null;
Transform bestTarget = null;
float bestScore = float.MaxValue;
foreach (var enemy in enemies)
{
Vector3 dirToEnemy = (enemy.transform.position - transform.position).normalized;
// 마우스 방향과의 각도 체크
float angle = Vector3.Angle(mouseDirection, dirToEnemy);
if (angle > autoAimAngle) continue; // 각도 범위 밖
// 거리 체크
float distance = Vector3.Distance(transform.position, enemy.transform.position);
// 점수 계산: 각도 + 거리 (낮을수록 좋음)
float score = angle * 0.5f + distance * 0.5f;
if (score < bestScore)
{
bestScore = score;
bestTarget = enemy.transform;
}
}
return bestTarget;
}
// --- [8] 이벤트: 화살 생성 ---
public void OnShootArrow() public void OnShootArrow()
{ {
if (arrowPrefab == null || firePoint == null) return; if (arrowPrefab == null || firePoint == null) return;
GameObject arrow = Instantiate(arrowPrefab, firePoint.position, transform.rotation); // 🎯 저장된 방향으로 회전 계산
PlayerArrow arrowScript = arrow.GetComponent<PlayerArrow>(); Quaternion shootRotation = Quaternion.LookRotation(_pendingShootDirection);
// 화살 생성 (계산된 방향으로)
GameObject arrow = Instantiate(arrowPrefab, firePoint.position, shootRotation);
// ArrowItem 초기화
ArrowItem arrowItem = arrow.GetComponent<ArrowItem>();
if (arrowItem != null)
{
arrowItem.Initialize(_pendingDamage, _pendingSpeed, _pendingRange);
return;
}
// 하위 호환
PlayerArrow arrowScript = arrow.GetComponent<PlayerArrow>();
if (arrowScript != null) if (arrowScript != null)
{ {
arrowScript.Initialize(_pendingDamage, _pendingSpeed, _pendingRange); arrowScript.Initialize(_pendingDamage, _pendingSpeed, _pendingRange);
} }
} }
// --- [5] 이벤트: 공격 끝 (정상적인 경우) --- // --- [9] 이벤트: 공격 끝 ---
public void OnAttackEnd() public void OnAttackEnd()
{ {
_isAttacking = false; _isAttacking = false;
ResetChargingEffects(); ResetChargingEffects();
} }
// --- [6] 안전장치 코루틴 --- // --- [10] 안전장치 코루틴 ---
private IEnumerator AttackRoutine() private IEnumerator AttackRoutine()
{ {
_isAttacking = true; _isAttacking = true;
// 🚨 안전장치: 0.6초 뒤에는 무조건 공격 상태를 풉니다!
// (애니메이션 이벤트 OnAttackEnd가 씹혀도 멈추지 않게 함)
yield return new WaitForSeconds(0.6f); yield return new WaitForSeconds(0.6f);
if (_isAttacking) if (_isAttacking)
@ -177,6 +298,59 @@ public class PlayerAttack : MonoBehaviour
} }
} }
// --- [11] 화살 교체 ---
public void SwapArrow(GameObject newArrow)
{
if (newArrow == null) return;
arrowPrefab = newArrow;
Debug.Log($"화살이 {newArrow.name}(으)로 교체되었습니다!");
}
public void StartWeaponCollision() { } public void StartWeaponCollision() { }
public void StopWeaponCollision() { } public void StopWeaponCollision() { }
// --- [12] 🎯 디버그: 감지 범위 시각화 ---
private void OnDrawGizmosSelected()
{
if (!enableAutoAim) return;
// 자동 조준 범위 (노란색 원)
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, autoAimRange);
// 마우스 방향 (파란색 선)
if (Application.isPlaying && firePoint != null)
{
Vector3 mouseDir = GetMouseDirection();
Gizmos.color = Color.blue;
Gizmos.DrawRay(firePoint.position, mouseDir * 5f);
// 🎯 에임 어시스트 방향 (빨간색 선)
Transform target = FindBestTarget(mouseDir);
if (target != null)
{
Vector3 targetPos = target.position + Vector3.up * 1.2f;
Vector3 targetDir = (targetPos - firePoint.position).normalized;
targetDir.y = 0;
// 보정된 최종 방향
Vector3 assistedDir = Vector3.Lerp(mouseDir, targetDir, aimAssistStrength);
assistedDir.Normalize();
Gizmos.color = Color.red;
Gizmos.DrawRay(firePoint.position, assistedDir * 7f);
// 타겟 위치 표시
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(targetPos, 0.3f);
}
// 감지 각도 (연한 초록색 선)
Gizmos.color = new Color(0, 1, 0, 0.3f);
Vector3 leftBound = Quaternion.Euler(0, -autoAimAngle, 0) * mouseDir;
Vector3 rightBound = Quaternion.Euler(0, autoAimAngle, 0) * mouseDir;
Gizmos.DrawRay(firePoint.position, leftBound * autoAimRange);
Gizmos.DrawRay(firePoint.position, rightBound * autoAimRange);
}
}
} }

View File

@ -0,0 +1,213 @@
using UnityEngine;
/// <summary>
/// 바닥에 떨어진 화살 아이템 (발사체로도 사용 가능)
/// 모드 전환: 아이템 모드 ↔ 발사 모드
/// </summary>
public class ArrowItem : MonoBehaviour
{
[Header("--- 화살 정보 ---")]
[SerializeField] private string arrowName = "기본 화살";
[SerializeField] private float damage = 15f;
[SerializeField] private float speed = 20f;
[SerializeField] private float range = 15f;
[Header("--- UI 표시 (아이템 모드) ---")]
[SerializeField] private GameObject pickupUI;
[SerializeField] private float uiDisplayRange = 3f;
[Header("--- 비주얼 ---")]
[SerializeField] private GameObject visualModel; // 화살 모델
private Transform playerTransform;
private Rigidbody rb;
private Collider col;
// 모드 구분
private bool isItemMode = true; // true: 아이템 모드, false: 발사 모드
private Vector3 startPos;
private bool isFired = false;
private void Awake()
{
rb = GetComponent<Rigidbody>();
col = GetComponent<Collider>();
}
private void Start()
{
if (isItemMode)
{
SetupAsItem();
}
}
private void Update()
{
if (isItemMode)
{
UpdateItemMode();
}
else
{
UpdateProjectileMode();
}
}
#region
private void SetupAsItem()
{
// 플레이어 찾기
GameObject player = GameObject.FindGameObjectWithTag("Player");
if (player != null)
{
playerTransform = player.transform;
}
// UI 숨기기
if (pickupUI != null)
{
pickupUI.SetActive(false);
}
// 물리 설정 (바닥에 떨어진 아이템)
if (rb != null)
{
rb.useGravity = true;
rb.isKinematic = false;
}
if (col != null)
{
col.isTrigger = true;
}
}
private void UpdateItemMode()
{
if (playerTransform == null || pickupUI == null) return;
// 플레이어와의 거리 체크 (UI 표시용)
float distance = Vector3.Distance(transform.position, playerTransform.position);
bool isNear = distance <= uiDisplayRange;
pickupUI.SetActive(isNear);
}
/// <summary>
/// PlayerInteraction에서 호출
/// </summary>
public void Pickup(PlayerAttack playerAttack)
{
if (playerAttack == null) return;
// 자기 자신을 복제해서 발사용 프리팹으로 제공
GameObject arrowPrefab = gameObject;
playerAttack.SwapArrow(arrowPrefab);
Debug.Log($"화살이 [{arrowName}](으)로 교체되었습니다!");
// 아이템 제거
Destroy(gameObject);
}
#endregion
#region
/// <summary>
/// PlayerAttack에서 호출 (발사 초기화)
/// </summary>
public void Initialize(float dmg, float arrowSpeed, float maxRange)
{
Debug.Log($"🏹 화살 발사! 방향: {transform.forward}, 속도: {arrowSpeed}");
// 발사 모드로 전환
isItemMode = false;
isFired = true;
// 스탯 설정
this.damage = dmg;
this.speed = arrowSpeed;
this.range = maxRange;
this.startPos = transform.position;
// UI 숨기기
if (pickupUI != null)
{
pickupUI.SetActive(false);
}
// 물리 설정 (발사체)
if (rb != null)
{
rb.useGravity = false;
rb.isKinematic = false;
// ✅ [중요] transform.forward 방향으로 발사
// 화살이 Z축(파란 화살표) 방향을 앞으로 향하고 있어야 함!
Vector3 shootDirection = transform.forward;
rb.velocity = shootDirection * speed;
Debug.Log($"📍 발사 방향: {shootDirection}, 속도 벡터: {rb.velocity}");
}
if (col != null)
{
col.isTrigger = true;
}
// 5초 후 자동 삭제
Destroy(gameObject, 5f);
}
private void UpdateProjectileMode()
{
if (!isFired) return;
// 최대 사거리 체크
if (Vector3.Distance(startPos, transform.position) >= range)
{
Destroy(gameObject);
}
}
private void OnTriggerEnter(Collider other)
{
// 아이템 모드에서는 충돌 무시
if (isItemMode) return;
// 발사 모드: 적 또는 벽 충돌
if (other.CompareTag("Enemy"))
{
var monster = other.GetComponent<MonsterClass>();
if (monster != null)
{
monster.TakeDamage(damage);
}
Destroy(gameObject);
}
else if (other.CompareTag("Wall") || other.CompareTag("Ground"))
{
Destroy(gameObject);
}
}
#endregion
#region
/// <summary>
/// 몬스터 드롭 시 화살 정보 설정
/// </summary>
public void SetArrowData(string name, float dmg, float spd, float rng)
{
arrowName = name;
damage = dmg;
speed = spd;
range = rng;
}
#endregion
}

View File

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

View File

@ -16,6 +16,14 @@ public class PlayerInteraction : MonoBehaviour
Collider[] hits = Physics.OverlapSphere(transform.position, interactRange, itemLayer); Collider[] hits = Physics.OverlapSphere(transform.position, interactRange, itemLayer);
foreach (var hit in hits) foreach (var hit in hits)
{ {
// 🏹 [새로 추가] 화살 아이템 습득
if (hit.TryGetComponent<ArrowItem>(out var arrowItem))
{
PickupArrow(arrowItem);
break;
}
// 기존 무기 습득
if (hit.TryGetComponent<EquippableItem>(out var item)) if (hit.TryGetComponent<EquippableItem>(out var item))
{ {
if (playerStats.Strength >= item.Config.RequiredStrength) if (playerStats.Strength >= item.Config.RequiredStrength)
@ -25,11 +33,30 @@ public class PlayerInteraction : MonoBehaviour
} }
else { CinemachineShake.Instance?.ShakeNoNo(); continue; } else { CinemachineShake.Instance?.ShakeNoNo(); continue; }
} }
// 기존 포션/제단
if (hit.TryGetComponent<HealthPotion>(out var potion)) { potion.Use(GetComponent<PlayerHealth>()); break; } if (hit.TryGetComponent<HealthPotion>(out var potion)) { potion.Use(GetComponent<PlayerHealth>()); break; }
if (hit.TryGetComponent<HealthAltar>(out var altar)) { altar.Use(GetComponent<PlayerHealth>()); break; } if (hit.TryGetComponent<HealthAltar>(out var altar)) { altar.Use(GetComponent<PlayerHealth>()); break; }
} }
} }
// 🏹 [새 함수] 화살 습득 처리
private void PickupArrow(ArrowItem arrowItem)
{
if (arrowItem == null) return;
// PlayerAttack 찾아서 화살 교체
PlayerAttack playerAttack = GetComponent<PlayerAttack>();
if (playerAttack != null)
{
arrowItem.Pickup(playerAttack);
}
else
{
Debug.LogWarning("PlayerAttack 컴포넌트를 찾을 수 없습니다!");
}
}
private void EquipWeapon(EquippableItem item) private void EquipWeapon(EquippableItem item)
{ {
if (_currentWeapon != null) _currentWeapon.OnDropped(transform.forward); if (_currentWeapon != null) _currentWeapon.OnDropped(transform.forward);

View File

@ -1,18 +1,23 @@
using UnityEngine; using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class PureUnityFan : MonoBehaviour public class ArrowRangeUI : MonoBehaviour
{ {
// 🚨 수정됨: 끝부분의 \ 기호를 모두 삭제했습니다.
[Header("--- 참조 ---")] [Header("--- 참조 ---")]
[SerializeField] private PlayerAttack attackScript; [SerializeField] private PlayerAttack attackScript; // PlayerAttack 스크립트 연결
[SerializeField] private PlayerInteraction interaction;
[Header("--- 부채꼴 설정 ---")] [Header("--- UI 설정 ---")]
[SerializeField] private float radius = 5f; [Tooltip("사거리 표시기의 색상")]
[SerializeField] private int segments = 40; [SerializeField] private Color uiColor = new Color(1f, 1f, 0f, 0.5f); // 노란색 반투명
[SerializeField] private Color fanColor = new Color(1f, 0.9f, 0f, 0.4f); [Tooltip("화살표 UI의 폭 (두께)")]
[Tooltip("풀차징 시에도 유지할 최소 부채꼴 각도 (너무 얇으면 안 보일 수 있음)")] [SerializeField] private float lineWidth = 1.0f;
[SerializeField] private float minAngle = 2f; // ⭐ [추가] 최소 두께 설정
[Header("--- 길이 설정 ---")]
[Tooltip("차징 0%일 때의 최소 길이 (기본 사거리)")]
[SerializeField] private float minLength = 5f;
[Tooltip("풀차징일 때의 최대 길이 (최대 사거리)")]
[SerializeField] private float maxLength = 20f;
private Mesh _mesh; private Mesh _mesh;
private MeshFilter _meshFilter; private MeshFilter _meshFilter;
@ -20,19 +25,24 @@ public class PureUnityFan : MonoBehaviour
private void Awake() private void Awake()
{ {
// 메쉬 초기화
_mesh = new Mesh(); _mesh = new Mesh();
_meshFilter = GetComponent<MeshFilter>(); _meshFilter = GetComponent<MeshFilter>();
_meshRenderer = GetComponent<MeshRenderer>(); _meshRenderer = GetComponent<MeshRenderer>();
_meshFilter.mesh = _mesh; _meshFilter.mesh = _mesh;
_meshRenderer.material.color = fanColor;
// 재질(Material)이 없다면 임시로 생성
if (_meshRenderer.material == null)
{
_meshRenderer.material = new Material(Shader.Find("Sprites/Default"));
}
_meshRenderer.material.color = uiColor;
} }
private void Update() private void Update()
{ {
// 1. 참조 확인 및 예외 처리 // 1. 공격 스크립트가 없거나 차징 중이 아니면 끄기
if (attackScript == null || interaction == null) return; if (attackScript == null || !attackScript.IsCharging)
if (!attackScript.IsCharging || interaction.CurrentWeapon == null)
{ {
_meshRenderer.enabled = false; _meshRenderer.enabled = false;
return; return;
@ -40,58 +50,52 @@ public class PureUnityFan : MonoBehaviour
_meshRenderer.enabled = true; _meshRenderer.enabled = true;
// 2. 점진적 보간(Lerp)을 통한 부드러운 정확도 계산 // 2. 차징 진행도(0.0 ~ 1.0) 가져오기
float progress = attackScript.ChargeProgress; // 0.0 ~ 1.0 float progress = attackScript.ChargeProgress;
float smoothSpread;
var config = interaction.CurrentWeapon.Config; // 3. 진행도에 따라 길이 계산 (Lerp로 부드럽게 늘어남)
float s1 = config.GetSpread(1); // 시작 정확도 float currentLength = Mathf.Lerp(minLength, maxLength, progress);
float s2 = config.GetSpread(2); // 중간 정확도
float s3 = config.GetSpread(3); // 최종 정확도 (0)
if (progress < 0.5f) // 4. 직사각형 메쉬 그리기
{ CreateRectangleMesh(currentLength, lineWidth);
smoothSpread = Mathf.Lerp(s1, s2, progress * 2f);
}
else
{
smoothSpread = Mathf.Lerp(s2, s3, (progress - 0.5f) * 2f);
}
// 3. ⭐ [핵심 수정] 계산된 각도가 설정한 최소 각도보다 작아지지 않도록 제한
// (WeaponConfig에서 0을 반환하더라도, UI는 최소 minAngle만큼은 유지함)
float targetAngle = Mathf.Max(smoothSpread * 2f, minAngle);
CreateFanMesh(targetAngle);
} }
private void CreateFanMesh(float angle) // 직사각형 메쉬 생성 함수
private void CreateRectangleMesh(float length, float width)
{ {
// 메쉬 생성 로직 (기존과 동일) Vector3[] vertices = new Vector3[4];
int vertexCount = segments + 2; int[] triangles = new int[6];
Vector3[] vertices = new Vector3[vertexCount]; Vector2[] uvs = new Vector2[4];
int[] triangles = new int[segments * 3];
vertices[0] = Vector3.zero; float halfWidth = width / 2f;
float halfAngle = angle / 2f;
for (int i = 0; i <= segments; i++) // 정점 4개 정의 (플레이어 발밑 기준 앞으로 뻗어나감)
{ vertices[0] = new Vector3(-halfWidth, 0.1f, 0);
float currAngle = Mathf.Lerp(-halfAngle, halfAngle, (float)i / segments); vertices[1] = new Vector3(halfWidth, 0.1f, 0);
float rad = currAngle * Mathf.Deg2Rad; vertices[2] = new Vector3(-halfWidth, 0.1f, length);
vertices[i + 1] = new Vector3(Mathf.Sin(rad), 0, Mathf.Cos(rad)) * radius; vertices[3] = new Vector3(halfWidth, 0.1f, length);
if (i < segments) // 삼각형 연결
{ triangles[0] = 0;
triangles[i * 3] = 0; triangles[1] = 2;
triangles[i * 3 + 1] = i + 1; triangles[2] = 1;
triangles[i * 3 + 2] = i + 2;
}
}
triangles[3] = 2;
triangles[4] = 3;
triangles[5] = 1;
// UV 매핑
uvs[0] = new Vector2(0, 0);
uvs[1] = new Vector2(1, 0);
uvs[2] = new Vector2(0, 1);
uvs[3] = new Vector2(1, 1);
// 메쉬 적용
_mesh.Clear(); _mesh.Clear();
_mesh.vertices = vertices; _mesh.vertices = vertices;
_mesh.triangles = triangles; _mesh.triangles = triangles;
_mesh.uv = uvs;
_mesh.RecalculateNormals(); _mesh.RecalculateNormals();
_mesh.RecalculateBounds();
} }
} }