using UnityEngine; // 유니티 기본 기능을 쓰기 위해 불러올거에요 -> UnityEngine를 public class EquippableItem : MonoBehaviour // 클래스를 선언할거에요 -> 장착/드랍/투척 가능한 아이템을 처리하는 EquippableItem을 { // 코드 블록을 시작할거에요 -> EquippableItem 범위를 [SerializeField] private WeaponConfig config; // 변수를 선언할거에요 -> 이 아이템이 참조할 무기 설정(WeaponConfig)을 config에 public WeaponConfig Config => config; // 프로퍼티를 선언할거에요 -> 외부에서 config를 읽을 수 있게 Config로 노출 [Header("--- 데미지 밸런스 ---")] // 인스펙터에 제목을 표시할거에요 -> 데미지 밸런스 섹션을 [SerializeField] private float lv1Mult = 1.0f; // 변수를 선언할거에요 -> 차지 1단계 배율을 lv1Mult에 [SerializeField] private float lv2Mult = 1.5f; // 변수를 선언할거에요 -> 차지 2단계 배율을 lv2Mult에 [SerializeField] private float lv3Mult = 2.5f; // 변수를 선언할거에요 -> 차지 3단계 배율을 lv3Mult에 // [제거] strengthBonusFactor 변수 삭제 // 설명을 적을거에요 -> 힘 보너스 배율은 더 이상 사용하지 않음 private Rigidbody _rb; // 변수를 선언할거에요 -> 리지드바디를 저장할 _rb를 private Collider _col; // 변수를 선언할거에요 -> 콜라이더를 저장할 _col을 private bool _isThrown; // 변수를 선언할거에요 -> 현재 투척 상태인지 저장할 _isThrown을 private int _chargeLevel; // 변수를 선언할거에요 -> 투척 당시 차지 레벨을 저장할 _chargeLevel을 private Stats _thrower; // 변수를 선언할거에요 -> 투척한 주체(플레이어 스탯)를 저장할 _thrower를 private Vector3 _originalWorldScale; // 변수를 선언할거에요 -> 원래 월드 스케일을 저장할 _originalWorldScale을 private void Awake() // 함수를 선언할거에요 -> 오브젝트가 켜질 때 1번 실행되는 Awake를 { // 코드 블록을 시작할거에요 -> Awake 범위를 _rb = GetComponent(); // 컴포넌트를 가져올거에요 -> Rigidbody를 찾아 _rb에 저장 _col = GetComponent(); // 컴포넌트를 가져올거에요 -> Collider를 찾아 _col에 저장 _originalWorldScale = transform.lossyScale; // 값을 저장할거에요 -> 현재 월드 기준 크기를 원본으로 기억 } // 코드 블록을 끝낼거에요 -> Awake를 public void OnPickedUp(Transform hand) // 함수를 선언할거에요 -> 아이템을 손에 집었을 때 처리하는 OnPickedUp을 { // 코드 블록을 시작할거에요 -> OnPickedUp 범위를 _isThrown = false; // 상태를 바꿀거에요 -> 투척 상태를 해제(false)로 transform.SetParent(hand); // 부모를 바꿀거에요 -> 손(Hand) 트랜스폼에 붙이기 transform.localScale = new Vector3( // 값을 설정할거에요 -> 손의 스케일 변화에도 월드 크기 유지되게 로컬 스케일 계산 _originalWorldScale.x / hand.lossyScale.x, // x축 크기를 보정할거에요 -> 원본 월드 스케일 기준으로 _originalWorldScale.y / hand.lossyScale.y, // y축 크기를 보정할거에요 -> 원본 월드 스케일 기준으로 _originalWorldScale.z / hand.lossyScale.z // z축 크기를 보정할거에요 -> 원본 월드 스케일 기준으로 ); // 로컬 스케일 설정을 끝낼거에요 -> 월드 크기 유지 transform.localPosition = Vector3.zero; // 위치를 맞출거에요 -> 손 기준 로컬 위치 0으로 transform.localRotation = Quaternion.identity; // 회전을 맞출거에요 -> 손 기준 로컬 회전 초기화 if (_rb) _rb.isKinematic = true; // 조건이 맞으면 실행할거에요 -> 리지드바디가 있으면 물리 비활성(키네마틱)으로 if (_col) _col.enabled = false; // 조건이 맞으면 실행할거에요 -> 콜라이더가 있으면 꺼서 손에서 충돌 안 나게 } // 코드 블록을 끝낼거에요 -> OnPickedUp을 public void OnDropped(Vector3 throwDir) // 함수를 선언할거에요 -> 아이템을 떨어뜨릴 때 처리하는 OnDropped를 { // 코드 블록을 시작할거에요 -> OnDropped 범위를 _isThrown = false; // 상태를 바꿀거에요 -> 투척 상태가 아님(false)으로 transform.SetParent(null); // 부모를 해제할거에요 -> 월드에 놓기 transform.localScale = _originalWorldScale; // 스케일을 되돌릴거에요 -> 원래 월드 스케일로 if (_rb) // 조건을 검사할거에요 -> 리지드바디가 있는지 { // 코드 블록을 시작할거에요 -> 물리 드랍 처리 _rb.isKinematic = false; // 값을 바꿀거에요 -> 물리 활성화 Vector3 force = (throwDir + Vector3.up * 0.5f).normalized * 5f; // 힘을 계산할거에요 -> 던지는 방향 + 살짝 위로 + 세기 5 _rb.AddForce(force, ForceMode.Impulse); // 힘을 줄거에요 -> 순간 힘(Impulse)으로 튕기듯 드랍 _rb.AddTorque(Random.insideUnitSphere * 3f, ForceMode.Impulse); // 회전도 줄거에요 -> 랜덤 토크로 자연스럽게 굴러가게 } // 코드 블록을 끝낼거에요 -> 물리 드랍 처리 if (_col) _col.enabled = true; // 조건이 맞으면 실행할거에요 -> 콜라이더를 다시 켜기 } // 코드 블록을 끝낼거에요 -> OnDropped를 public void OnThrown(Vector3 dir, float force, int lv, Stats s) // 함수를 선언할거에요 -> 투척 시작 세팅을 하는 OnThrown을 { // 코드 블록을 시작할거에요 -> OnThrown 범위를 _isThrown = true; // 상태를 바꿀거에요 -> 투척 상태(true)로 _chargeLevel = lv; // 값을 저장할거에요 -> 투척 당시 차지 레벨을 _thrower = s; // 값을 저장할거에요 -> 던진 주체(스탯)를 저장 transform.SetParent(null); // 부모를 해제할거에요 -> 월드로 분리 transform.localScale = _originalWorldScale; // 스케일을 되돌릴거에요 -> 원래 월드 스케일로 if (_rb) // 조건을 검사할거에요 -> 리지드바디가 있는지 { // 코드 블록을 시작할거에요 -> 물리 투척 처리 _rb.isKinematic = false; // 값을 바꿀거에요 -> 물리 활성화 _rb.AddForce(dir * force, ForceMode.Impulse); // 힘을 줄거에요 -> 던지는 방향 * force로 순간 가속 _rb.AddTorque(transform.right * 10f, ForceMode.Impulse); // 회전을 줄거에요 -> 오른쪽 축으로 스핀 주기 } // 코드 블록을 끝낼거에요 -> 물리 투척 처리 if (_col) _col.enabled = true; // 조건이 맞으면 실행할거에요 -> 콜라이더를 켜서 충돌 가능하게 } // 코드 블록을 끝낼거에요 -> OnThrown를 private void OnCollisionEnter(Collision collision) // 함수를 선언할거에요 -> 충돌이 일어나면 호출되는 OnCollisionEnter를 { // 코드 블록을 시작할거에요 -> OnCollisionEnter 범위를 if (!_isThrown) return; // 조건이 맞으면 종료할거에요 -> 투척 상태가 아니면 무시 if (_thrower != null && collision.gameObject == _thrower.gameObject) return; // 조건이 맞으면 종료할거에요 -> 던진 본인에게는 맞지 않게 if (collision.gameObject.TryGetComponent(out var target)) // 조건을 검사할거에요 -> 맞은 대상이 데미지를 받을 수 있는지 { // 코드 블록을 시작할거에요 -> 데미지 처리 float mult = _chargeLevel == 3 ? lv3Mult : (_chargeLevel == 2 ? lv2Mult : lv1Mult); // 배율을 고를거에요 -> 차지 레벨에 따라 lv1/2/3 배율 // ✨ [수정] 힘 보너스 로직 제거. (플레이어 기본 공격력 + 무기 대미지) * 차지 배율 // 설명을 적을거에요 -> 최종 데미지 계산 공식 float finalDamage = (_thrower.BaseAttackDamage + config.BaseDamage) * mult; // 값을 계산할거에요 -> (플레이어 공격력 + 무기 기본 데미지) * 배율 target.TakeDamage(finalDamage); // 함수를 실행할거에요 -> 대상에게 finalDamage만큼 데미지 주기 Debug.Log($"[투척 적중] {collision.gameObject.name}에게 {finalDamage:F1} 데미지!"); // 로그를 찍을거에요 -> 적중 결과 출력 _isThrown = false; // 상태를 바꿀거에요 -> 한 번 맞으면 투척 상태 해제 } // 코드 블록을 끝낼거에요 -> 데미지 처리 if (collision.gameObject.layer != LayerMask.NameToLayer("Player")) _isThrown = false; // 조건이 맞으면 실행할거에요 -> 플레이어 레이어가 아니면 투척 상태 해제 } // 코드 블록을 끝낼거에요 -> OnCollisionEnter를 } // 코드 블록을 끝낼거에요 -> EquippableItem을