Files
2026-06-02 16:33:42 +09:00

101 lines
7.7 KiB
C#

using UnityEngine;
using UnityEngine.Serialization;
// 공격 판정 영역의 도형. Circle은 원거리 균등 판정, Box는 길쭉한 직선/넓은 부채꼴에 적합.
public enum HitShape
{
Circle,
Box
}
// ============================================================================
// ActionData
// ----------------------------------------------------------------------------
// 모든 액션(공격/모션/잡기/그라운드파운드)의 데이터를 표현하는 ScriptableObject.
// .asset 파일로 만들어 Inspector에서 디자이너가 직접 편집 가능.
// PlayerController는 코드 없이 데이터만 바꿔서 새 액션 추가 가능.
//
// 액션 종류 구분:
// - HasMotion = true → 이동 액션 (Dash/Roll 등)
// - HasHit = true → 데미지 액션 (펀치/킥 등)
// - IsGrab = true → 잡기 (가까운 적을 끌어당김)
// - 위 세 가지 조합 가능 → "전진하면서 때리는 콤보" 등
// ============================================================================
[CreateAssetMenu(fileName = "ActionData", menuName = "Combat/ActionData")]
public class ActionData : ScriptableObject
{
// [FormerlySerializedAs]: 옛 이름의 직렬화 데이터도 자동 로드 (기존 에셋 호환).
[FormerlySerializedAs("AttackName")]
[FormerlySerializedAs("MotionName")]
public string ActionName; // 디버그/Inspector 표시용 이름
public string AnimationState; // Animator의 State 이름 (Play()로 직접 호출)
public float AnimationSpeed = 1f; // 애니메이션 기본 재생 속도
public AnimationCurve AnimationSpeedCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f); // 시간에 따른 속도 변화 (windup 빠르게/임팩트 느리게 등)
public float Cooldown = 0.3f; // 이 액션 발동 후 다음 공격 입력 받기까지 시간
public float ComboWindow = 0.25f; // 콤보 transition 받을 수 있는 시간 (ComboNode에서도 별도 설정 가능)
// ─── 무기 조건 (콤보 트랜지션 무기별 분기 필터) ───────────────────────
// 같은 입력의 트랜지션을 무기별로 여러 개 깔아두면, 현재 장착 무기가
// 이 조건을 만족하는 액션만 실행된다 (Any면 무기와 무관하게 항상 가능).
[Header("Weapon")]
public WeaponRequirement RequiredWeapon = WeaponRequirement.Any;
// ─── 이동(모션) 파라미터 (HasMotion=true일 때 적용) ──────────────────
[Header("Motion")]
public bool HasMotion; // 이 액션이 위치 이동을 동반하는지
public Vector2 Velocity = Vector2.zero; // 모션 속도 (X는 facing 방향으로 자동 부호 변환)
public AnimationCurve MotionSpeedCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f); // 시간에 따른 속도 곱연산 (가속/감속)
[FormerlySerializedAs("Duration")]
public float MotionDuration = 0.3f; // 모션 전체 길이 (애니메이션 길이 안 쓸 때)
public bool CanMoveDuringAction; // 액션 중 좌우 입력 허용 여부 (보통 false)
public bool CanTurnDuringAction; // 액션 중 페이싱 변경 허용 여부
public bool UseInputDirection = true; // true면 현재 입력 방향, false면 현재 페이싱 방향으로 이동
public bool PreserveYVelocity = true; // true면 점프/낙하 중인 vy 유지, false면 ActionData.Velocity.y로 덮어씀
public bool StopHorizontalVelocityOnEnd = true; // 액션 종료 시 vx를 0으로 (관성으로 더 가지 않게)
// ─── 공격 판정 (HasHit=true일 때 적용) ─────────────────────────────
[Header("Hit")]
public bool HasHit = true; // 이 액션이 데미지를 주는지
public HitShape Shape = HitShape.Circle; // Circle = Radius 사용, Box = HitSize 사용
public Vector2 Offset = new Vector2(0.5f, 0f); // 캐릭터 기준 hit 영역 중심 (X는 facing 방향)
public float Radius = 0.5f; // Circle일 때 사용하는 반경
public Vector2 HitSize = new Vector2(1f, 0.5f); // Box일 때 사용하는 가로/세로 크기
public int Damage = 10; // 데미지 양
public float HitTiming = 0.15f; // 액션 시작 후 hit 발동까지 시간 (선딜)
public float HitDuration = 0f; // hit 영역이 활성 상태로 유지되는 시간 (0이면 단발)
// ─── 공격 이펙트 (hit 발동 시 생성하는 VFX) ─────────────────────────
public GameObject HitEffectPrefab; // 생성할 이펙트 프리팹 (null이면 없음)
public Vector2 HitEffectOffset = new Vector2(0.5f, 0f); // 캐릭터 기준 이펙트 생성 위치 (X는 facing 방향, hit 영역과 독립)
public bool HitEffectAttachToPlayer; // true면 플레이어 자식으로 부착 (같이 움직임), false면 월드 고정
public float HitEffectLifetime = 1f; // 자동 파괴 시간 (0이면 파괴 안 함 — 프리팹이 스스로 정리)
// ─── 효과음 (hit 발동 시 재생) ──────────────────────────────────────
[Header("Audio")]
public AudioClip AttackSound; // 무기 모션(휘두름/발사) 사운드. 적중 여부와 무관하게 발동 시 항상 재생 (null이면 없음)
[Range(0f, 1f)] public float AttackSoundVolume = 1f; // 모션 사운드 볼륨
public AudioClip HitSound; // 타격 사운드. 실제 적중 시에만 재생 (null이면 없음)
[Range(0f, 1f)] public float HitSoundVolume = 1f; // 타격 사운드 볼륨
// ─── 피격자 반응 (피격된 적의 동작) ─────────────────────────────────
[Header("Hit Reaction")]
public Vector2 HitVelocity = Vector2.zero; // 적에게 가할 넉백 속도 (X는 공격자 facing 방향)
public float HitStunDuration = 0.25f; // 피격자가 이동/공격을 못 하는 경직 시간
public bool UseHitPositionCorrection; // 적의 위치를 강제로 보정할지 (잡기/연계 안정성)
public Vector2 HitTargetOffset = new Vector2(0.8f, 0f); // 보정 시 공격자 기준 적의 목표 위치
public float HitPositionCorrectionDuration = 0.08f; // 보정 보간 시간 (0이면 즉시 텔레포트)
public bool CorrectHitTargetY; // 보정에서 Y도 이동시킬지 (false면 X만)
public string HitReactionAnimationState; // 적이 재생할 피격 애니메이션 State
// ─── 잡기 전용 (IsGrab=true일 때 적용) ─────────────────────────────
[Header("Grab")]
public bool IsGrab; // 잡기 액션 (GrabRoutine에서 처리)
public Vector2 GrabOffset = new Vector2(0.6f, 0f); // 잡힌 적의 위치 (공격자 기준)
public AnimationCurve GrabOffsetXCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f); // 시간에 따른 X 위치 비율 (당기기 효과)
public AnimationCurve GrabOffsetYCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f); // 시간에 따른 Y 위치 비율 (들어올리기 효과)
public string GrabbedAnimationState; // 잡힌 적이 재생할 애니메이션
public float GrabSearchRadius = 2f; // 잡기 타겟 검색 반경 (이 안에서 후보 찾기)
public float GrabRange = 0.5f; // 실제 잡기 가능 거리 (후보 중 이 거리 안에 있어야 잡힘)
}