Projext/Assets/Scripts/Player/Equipment/EquipItem.cs
2026-02-13 00:23:25 +09:00

101 lines
8.9 KiB
C#

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>(); // 컴포넌트를 가져올거에요 -> Rigidbody를 찾아 _rb에 저장
_col = GetComponent<Collider>(); // 컴포넌트를 가져올거에요 -> 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<IDamageable>(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($"<color=orange>[투척 적중]</color> {collision.gameObject.name}에게 {finalDamage:F1} 데미지!"); // 로그를 찍을거에요 -> 적중 결과 출력
_isThrown = false; // 상태를 바꿀거에요 -> 한 번 맞으면 투척 상태 해제
} // 코드 블록을 끝낼거에요 -> 데미지 처리
if (collision.gameObject.layer != LayerMask.NameToLayer("Player")) _isThrown = false; // 조건이 맞으면 실행할거에요 -> 플레이어 레이어가 아니면 투척 상태 해제
} // 코드 블록을 끝낼거에요 -> OnCollisionEnter를
} // 코드 블록을 끝낼거에요 -> EquippableItem을