155 lines
4.8 KiB
C#
155 lines
4.8 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
public class PlayerAttack : MonoBehaviour
|
|
{
|
|
[Header("--- 활 설정 ---")]
|
|
[SerializeField] private GameObject arrowPrefab; // 화살 프리팹
|
|
[SerializeField] private Transform firePoint; // 발사 위치
|
|
[SerializeField] private PlayerAnimator pAnim; // 애니메이션 제어
|
|
|
|
[Header("--- 일반 공격 (좌클릭) ---")]
|
|
[SerializeField] private float normalDamage = 10f;
|
|
[SerializeField] private float normalRange = 15f;
|
|
[SerializeField] private float normalSpeed = 20f;
|
|
[SerializeField] private float attackCooldown = 0.5f;
|
|
|
|
[Header("--- 차징 공격 (우클릭) ---")]
|
|
[SerializeField] private float maxChargeTime = 2.0f;
|
|
|
|
[System.Serializable]
|
|
public struct ChargeStage
|
|
{
|
|
public float chargeTime;
|
|
public float damageMult;
|
|
public float rangeMult;
|
|
}
|
|
|
|
[SerializeField] private List<ChargeStage> chargeStages;
|
|
|
|
private float _lastAttackTime;
|
|
private float _chargeTimer;
|
|
private bool _isCharging = false;
|
|
private bool _isAttacking = false;
|
|
|
|
// 🔥 추가: 애니메이션 이벤트 발생 시점에 사용할 데이터 저장용 변수
|
|
private float _pendingDamage;
|
|
private float _pendingSpeed;
|
|
private float _pendingRange;
|
|
|
|
public bool IsCharging => _isCharging;
|
|
public bool IsAttacking
|
|
{
|
|
get => _isAttacking;
|
|
set => _isAttacking = value;
|
|
}
|
|
public float ChargeProgress => Mathf.Clamp01(_chargeTimer / maxChargeTime);
|
|
|
|
private void Start()
|
|
{
|
|
if (chargeStages == null || chargeStages.Count == 0)
|
|
{
|
|
chargeStages = new List<ChargeStage>
|
|
{
|
|
new ChargeStage { chargeTime = 0f, damageMult = 1f, rangeMult = 1f },
|
|
new ChargeStage { chargeTime = 1f, damageMult = 1.5f, rangeMult = 1.2f },
|
|
new ChargeStage { chargeTime = 2f, damageMult = 2.5f, rangeMult = 1.5f }
|
|
};
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_isCharging)
|
|
{
|
|
_chargeTimer += Time.deltaTime;
|
|
}
|
|
}
|
|
|
|
// 1. 좌클릭: 일반 공격 시도 (데이터만 저장하고 애니메이션 재생)
|
|
public void PerformNormalAttack()
|
|
{
|
|
if (Time.time < _lastAttackTime + attackCooldown) return;
|
|
if (_isAttacking) return;
|
|
|
|
// ✅ 여기서 바로 발사하지 않고 정보만 저장합니다.
|
|
_pendingDamage = normalDamage;
|
|
_pendingSpeed = normalSpeed;
|
|
_pendingRange = normalRange;
|
|
|
|
_lastAttackTime = Time.time;
|
|
|
|
// 애니메이션 트리거 실행
|
|
if (pAnim != null) pAnim.TriggerThrow();
|
|
|
|
StartCoroutine(AttackRoutine());
|
|
}
|
|
|
|
public void StartCharging()
|
|
{
|
|
_isCharging = true;
|
|
_chargeTimer = 0f;
|
|
|
|
if (pAnim != null) pAnim.SetCharging(true);
|
|
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true);
|
|
}
|
|
|
|
public void CancelCharging()
|
|
{
|
|
_isCharging = false;
|
|
_chargeTimer = 0f;
|
|
|
|
if (pAnim != null) pAnim.SetCharging(false);
|
|
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(false);
|
|
}
|
|
|
|
// 2. 우클릭 중 좌클릭: 차징 발사 시도 (수치 계산 후 애니메이션 재생)
|
|
public void ReleaseAttack()
|
|
{
|
|
if (!_isCharging) return;
|
|
|
|
ChargeStage currentStage = chargeStages[0];
|
|
foreach (var stage in chargeStages)
|
|
{
|
|
if (_chargeTimer >= stage.chargeTime) currentStage = stage;
|
|
}
|
|
|
|
// ✅ 계산된 결과값을 저장해둡니다.
|
|
_pendingDamage = normalDamage * currentStage.damageMult;
|
|
_pendingSpeed = normalSpeed * currentStage.rangeMult;
|
|
_pendingRange = normalRange * currentStage.rangeMult;
|
|
|
|
// 애니메이션 트리거 실행
|
|
if (pAnim != null) pAnim.TriggerThrow();
|
|
|
|
CancelCharging();
|
|
_lastAttackTime = Time.time;
|
|
StartCoroutine(AttackRoutine());
|
|
}
|
|
|
|
// 3. 🎯 핵심: 애니메이션의 'OnShootArrow' 이벤트 타이밍에 맞춰 실제 화살 생성
|
|
public void OnShootArrow()
|
|
{
|
|
if (arrowPrefab == null || firePoint == null) return;
|
|
|
|
GameObject arrow = Instantiate(arrowPrefab, firePoint.position, transform.rotation);
|
|
PlayerArrow arrowScript = arrow.GetComponent<PlayerArrow>();
|
|
|
|
if (arrowScript != null)
|
|
{
|
|
// 미리 저장해둔(_pending...) 수치를 사용해 화살 초기화
|
|
arrowScript.Initialize(_pendingDamage, _pendingSpeed, _pendingRange);
|
|
}
|
|
}
|
|
|
|
private IEnumerator AttackRoutine()
|
|
{
|
|
_isAttacking = true;
|
|
yield return new WaitForSeconds(0.2f);
|
|
_isAttacking = false;
|
|
}
|
|
|
|
public void StartWeaponCollision() { }
|
|
public void StopWeaponCollision() { }
|
|
} |