OldBlueWater/BlueWater/Assets/02.Scripts/Character/CombatPlayer/CombatPlayer.cs
NTG 5f4e88d671 Closes #149 CombatPlayer 추가
+ Red Sprite V3(이누야샤) 캐릭터 추가
+ 03.CombatTest Scene(전투 테스트용 씬) 추가
+ 4방향 Idle, Walk, Dash, ComboAttack 구현
+ ComboAttack 애니메이션 복제 및 수정
2024-01-24 09:48:26 +09:00

238 lines
8.1 KiB
C#

using System;
using System.Collections;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
public class CombatPlayer : MonoBehaviour, IDamageable
{
[Title("초기화 방식")]
[SerializeField] private bool autoInit = true;
[Title("캐릭터 변수")]
[SerializeField] private float maxHp = 100f;
[SerializeField] private float currentHp;
[SerializeField] private float moveSpeed = 5f;
[field: Title("대쉬")]
[field: SerializeField] public float DashForce { get; set; } = 20f;
[field: SerializeField] public float DashCooldown { get; set; } = 0.5f;
[field: DisableIf("@true")]
[field: SerializeField] public bool IsDashing { get; set; }
[field: DisableIf("@true")]
[field: SerializeField] public bool EnableDash { get; set; } = true;
[field: Title("공격")]
[field: SerializeField] public int MaxHitNum { get; set; } = 10;
[field: SerializeField] public float AttackDamage { get; set; } = 10f;
[field: SerializeField] public float AttackRange { get; set; } = 1.5f;
[field: SerializeField] public float AttackAngle { get; set; } = 180f;
[field: SerializeField] public float ComboTime { get; set; } = 0.5f;
[field: SerializeField] public LayerMask TargetLayer { get; set; }
[field: DisableIf("@true")]
[field: SerializeField] public bool IsAttacking { get; set; }
[field: DisableIf("@true")]
[field: SerializeField] public bool IsComboAttacking { get; set; }
[field: DisableIf("@true")]
[field: SerializeField] public bool IsComboPossible { get; set; }
[Title("컴포넌트")]
[SerializeField] private PlayerInput playerInput;
[field: SerializeField] public Rigidbody Rb { get; set; }
[SerializeField] private Transform visualLook;
[field: SerializeField] public Animator Animator { get; set; }
private Vector2 movementInput;
public Vector3 PreviousDir { get; set; } = Vector3.back;
[field: SerializeField] public Collider[] HitColliders { get; set; }
private static readonly int XDirectionHash = Animator.StringToHash("xDirection");
private static readonly int ZDirectionHash = Animator.StringToHash("zDirection");
private static readonly int IsMovingHash = Animator.StringToHash("isMoving");
public readonly int isDashingHash = Animator.StringToHash("isDashing");
public readonly int isAttackingHash = Animator.StringToHash("isAttacking");
[Button("셋팅 초기화")]
private void Init()
{
playerInput = GetComponent<PlayerInput>();
Rb = GetComponent<Rigidbody>();
visualLook = transform.Find("VisualLook");
Animator = visualLook.GetComponent<Animator>();
}
private void Awake()
{
if (autoInit)
{
Init();
}
}
private void Start()
{
HitColliders = new Collider[MaxHitNum];
SetCurrentHp(maxHp);
}
private void OnEnable()
{
playerInput.actions.FindAction("Attack").performed += OnAttackEvent;
}
private void OnDisable()
{
playerInput.actions.FindAction("Attack").performed -= OnAttackEvent;
}
private void Update()
{
HandleMovement();
}
public void TakeDamage(float attackerPower, Vector3? attackPos = null)
{
if (IsDashing) return;
var changeHp = Mathf.Max(currentHp - attackerPower, 0);
SetCurrentHp(changeHp);
if (InIslandCamera.Inst.InIslandCam)
{
VisualFeedbackManager.Inst.CameraShake(InIslandCamera.Inst.InIslandCam);
}
// 죽었는지 체크
if (changeHp == 0f)
{
Die();
return;
}
}
public void Die()
{
print("Combat Player Die");
}
private void OnMove(InputValue value)
{
movementInput = value.Get<Vector2>();
}
public void OnDash()
{
if (!EnableDash || IsDashing) return;
Animator.SetBool(isDashingHash, true);
}
private void OnAttackEvent(InputAction.CallbackContext context)
{
if (IsAttacking && !IsComboPossible) return;
// var control = context.control;
//
// if (control.name.Equals("leftButton"))
// {
// UseMouseAttack = true;
// }
// else if (control.name.Equals("k"))
// {
// UseMouseAttack = false;
// }
if (IsComboPossible)
{
IsComboAttacking = true;
return;
}
Animator.SetBool(isAttackingHash, true);
}
private void HandleMovement()
{
if (!IsDashing)
{
var movement = new Vector3(movementInput.x, 0, movementInput.y);
var moveDirection = movement.normalized;
Rb.velocity = moveDirection * moveSpeed;
}
var localScale = visualLook.localScale;
localScale.x = Rb.velocity.x switch
{
> 0.01f => Mathf.Abs(localScale.x),
< -0.01f => -Mathf.Abs(localScale.x),
_ => localScale.x
};
visualLook.localScale = localScale;
if (Rb.velocity != Vector3.zero)
{
PreviousDir = Rb.velocity.normalized;
Animator.SetFloat(XDirectionHash, PreviousDir.x);
Animator.SetFloat(ZDirectionHash, PreviousDir.z);
}
var isMoving = Rb.velocity != Vector3.zero;
Animator.SetBool(IsMovingHash, isMoving);
}
public void AttackTiming()
{
var attackDirection = PreviousDir;
Array.Clear(HitColliders, 0, MaxHitNum);
var size = Physics.OverlapSphereNonAlloc(transform.position, AttackRange, HitColliders, TargetLayer);
for (var i = 0; i < size; i++)
{
var targetDirection = (HitColliders[i].transform.position - transform.position).normalized;
var angleBetween = Vector3.Angle(attackDirection, targetDirection);
if (angleBetween >= AttackAngle * 0.5f) continue;
if (HitColliders[i].gameObject.layer == LayerMask.NameToLayer("Enemy"))
{
var iDamageable = HitColliders[i].transform.GetComponent<IDamageable>();
iDamageable.TakeDamage(AttackDamage);
VisualFeedbackManager.Inst.TriggerHitStop(0.1f);
}
else if (HitColliders[i].gameObject.layer == LayerMask.NameToLayer("Skill") &&
HitColliders[i].CompareTag("DestructiveSkill"))
{
var iDamageable = HitColliders[i].transform.GetComponent<IDamageable>();
iDamageable.TakeDamage(AttackDamage);
}
}
}
public void CoolDown(float waitTime, Action onCooldownComplete = null)
{
StartCoroutine(CoolDownCoroutine(waitTime, onCooldownComplete));
}
private IEnumerator CoolDownCoroutine(float waitTime, Action onCooldownComplete = null)
{
var time = 0f;
while (time <= waitTime)
{
time += Time.deltaTime;
yield return null;
}
onCooldownComplete?.Invoke();
}
private void SetCurrentHp(float value)
{
currentHp = value;
}
}
}