OldBlueWater/BlueWater/Assets/02.Scripts/Character/CombatPlayer/CombatPlayerController.cs

355 lines
14 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
public class CombatPlayerController : MonoBehaviour, IDamageable
{
/***********************************************************************
* Definitions
***********************************************************************/
#region Class
[Serializable]
public class Components
{
public PlayerInput playerInput;
public Transform visualLook;
public Animator animator;
public PhysicsMovement movement;
}
[Serializable]
public class CharacterOption
{
[Range(0f, 1000f), Tooltip("최대 체력")]
public float maxHp = 100f;
[Title("공격")]
[Range(1, 21), Tooltip("한 번에 공격 가능한 개체 수")]
public int maxHitNum = 10;
[Range(0f, 100f), Tooltip("공격 데미지")]
public float attackDamage = 10f;
[Range(0.1f, 2f), Tooltip("콤보 공격 포함 총 걸리는 시간")]
public float attackTime = 0.7f;
[Range(0.1f, 5f), Tooltip("공격 범위 사거리(반지름)")]
public float attackRange = 1.5f;
[Range(0f, 360f), Tooltip("공격 범위 각도")]
public float attackAngle = 180f;
[Tooltip("공격할 레이어 설정")]
public LayerMask targetLayer = -1;
}
[Serializable]
[DisableIf("@true")]
public class CurrentState
{
public bool useMouseAttack = true;
public bool isInvincibility;
public bool isAttacking;
public bool isComboPossible;
public bool isComboAttacking;
}
[DisableIf("@true")]
[Serializable]
public class CurrentValue
{
[Tooltip("현재 체력")]
public float currentHp;
[Tooltip("최근에 공격 받은 충돌체 배열")]
public Collider[] hitColliders;
}
#endregion
/***********************************************************************
* Variables
***********************************************************************/
#region Variables
[field: SerializeField] public Components MyComponents { get; private set; }
[field: SerializeField] public CharacterOption MyCharacterOption { get; private set; }
[field: SerializeField] public CurrentState MyCurrentState { get; set; }
[field: SerializeField] public CurrentValue MyCurrentValue { get; set; }
public string mainSkillName;
public GameObject MainSkillObject { get; private set; }
private ISkill mainSkill;
public static readonly int IsMovingHash = Animator.StringToHash("isMoving");
public static readonly int XDirectionHash = Animator.StringToHash("xDirection");
public static readonly int ZDirectionHash = Animator.StringToHash("zDirection");
public static readonly int IsAttackingHash = Animator.StringToHash("isAttacking");
public static readonly int IsActivateMainSkillHash = Animator.StringToHash("isActivateMainSkill");
#endregion
/***********************************************************************
* Unity Events
***************************************************************m********/
#region Unity Events
private void OnEnable()
{
MyComponents.playerInput.actions.FindAction("Attack").performed += OnAttackEvent;
}
private void OnDisable()
{
MyComponents.playerInput.actions.FindAction("Attack").performed -= OnAttackEvent;
}
private void Start()
{
InitComponents();
InitSkills();
InitStartValue();
}
private void Update()
{
MoveAnimation();
FlipVisualLook(MyComponents.movement.GetPreviousMoveDirection().x);
}
#endregion
/***********************************************************************
* Init Methods
***********************************************************************/
#region Unity Events
private void InitComponents()
{
if (!TryGetComponent(out MyComponents.movement))
{
MyComponents.movement = gameObject.AddComponent<PhysicsMovement>();
}
MyComponents.movement.SetAnimator(MyComponents.animator);
}
private void InitSkills()
{
MainSkillObject = SkillManager.Inst.InstantiateSkill(mainSkillName).gameObject;
mainSkill = MainSkillObject.GetComponent<ISkill>();
if (mainSkill != null)
{
var myCollider = MyComponents.movement.MyComponents.capsuleCollider;
var myRb = MyComponents.movement.MyComponents.rb;
var myVisualLook = MyComponents.visualLook;
var ui = UiManager.Inst.CombatUi.MainSkillUi;
ui.gameObject.SetActive(true);
mainSkill.SkillInputData.InitInputData(myCollider, myRb, myVisualLook, MyCharacterOption.targetLayer, ui);
mainSkill.InitData();
}
}
private void InitStartValue()
{
MyCurrentValue.hitColliders = new Collider[MyCharacterOption.maxHitNum];
SetCurrentHp(MyCharacterOption.maxHp);
}
#endregion
/***********************************************************************
* Player Input
***********************************************************************/
#region Unity Events
private void OnAttackEvent(InputAction.CallbackContext context)
{
if (MyCurrentState.isAttacking && !MyCurrentState.isComboPossible) return;
var control = context.control;
if (control.name.Equals("leftButton"))
{
MyCurrentState.useMouseAttack = true;
}
else if (control.name.Equals("k"))
{
MyCurrentState.useMouseAttack = false;
}
if (MyCurrentState.isComboPossible)
{
MyCurrentState.isComboAttacking = true;
return;
}
MyComponents.animator.SetBool(IsAttackingHash, true);
}
private void OnActivateMainSkill()
{
if (MyCurrentState.isAttacking || GetIsDashing()) return;
mainSkill.SkillInputData.UpdateInputData(GetCurrentPosition());
if (mainSkill.EnableSkill())
{
SetEnableMoving(false);
MyComponents.animator.SetBool(IsActivateMainSkillHash, true);
mainSkill.ActivateSkill();
}
}
#endregion
/***********************************************************************
* Interfaces
***********************************************************************/
#region Interfaces
// IDamageable
public void TakeDamage(float attackerPower, Vector3? attackPos = null)
{
if (MyCurrentState.isInvincibility) return;
var changeHp = Mathf.Max(MyCurrentValue.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");
}
public float GetCurrentHp() => MyCurrentValue.currentHp;
#endregion
/***********************************************************************
* Methods
***********************************************************************/
#region Methods
public void AttackTiming()
{
var attackDirection = MyComponents.movement.GetPreviousMoveDirection();
Array.Clear(MyCurrentValue.hitColliders, 0, MyCharacterOption.maxHitNum);
var size = Physics.OverlapSphereNonAlloc(transform.position, MyCharacterOption.attackRange, MyCurrentValue.hitColliders, MyCharacterOption.targetLayer);
for (var i = 0; i < size; i++)
{
var targetDirection = (MyCurrentValue.hitColliders[i].transform.position - transform.position).normalized;
var angleBetween = Vector3.Angle(attackDirection, targetDirection);
if (angleBetween >= MyCharacterOption.attackAngle * 0.5f) continue;
if (MyCurrentValue.hitColliders[i].gameObject.layer == LayerMask.NameToLayer("Enemy"))
{
var iDamageable = MyCurrentValue.hitColliders[i].transform.GetComponent<IDamageable>();
iDamageable.TakeDamage(MyCharacterOption.attackDamage);
VisualFeedbackManager.Inst.TriggerHitStop(0.1f);
}
else if (MyCurrentValue.hitColliders[i].gameObject.layer == LayerMask.NameToLayer("Skill") &&
MyCurrentValue.hitColliders[i].CompareTag("DestructiveSkill"))
{
var iDamageable = MyCurrentValue.hitColliders[i].transform.GetComponent<IDamageable>();
iDamageable.TakeDamage(MyCharacterOption.attackDamage);
}
}
}
private void MoveAnimation()
{
var isMoving = MyComponents.movement.GetIsMoving();
var previousDirection = MyComponents.movement.GetPreviousMoveDirection();
MyComponents.animator.SetBool(IsMovingHash, isMoving);
if (isMoving)
{
MyComponents.animator.SetFloat(XDirectionHash, previousDirection.x);
MyComponents.animator.SetFloat(ZDirectionHash, previousDirection.z);
}
}
private void FlipVisualLook(float previousDirectionX)
{
var localScale = MyComponents.visualLook.localScale;
localScale.x = previousDirectionX switch
{
> 0.01f => Mathf.Abs(localScale.x),
< -0.01f => -Mathf.Abs(localScale.x),
_ => localScale.x
};
MyComponents.visualLook.localScale = localScale;
}
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();
}
[Button("현재 체력 변경")]
private void SetCurrentHp(float value) => MyCurrentValue.currentHp = value;
public void SetEnableMoving(bool value) => MyComponents.movement.SetEnableMoving(value);
public void Move(Vector3 velocity) => MyComponents.movement.Move(velocity);
public void MoveToCurrentDirection(float speed) => MyComponents.movement.MoveToCurrentDirection(speed);
public bool GetIsAttacking() => MyCurrentState.isAttacking;
public bool GetIsComboAttacking() => MyCurrentState.isComboAttacking;
public bool GetIsDashing() => MyComponents.movement.GetIsDashing();
public float GetDashCooldown() => MyComponents.movement.GetDashCooldown();
public float GetDashTime() => MyComponents.movement.GetDashTime();
public float GetAttackTime() => MyCharacterOption.attackTime;
public void SetIsAttacking(bool value) => MyCurrentState.isAttacking = value;
public void SetIsComboAttacking(bool value) => MyCurrentState.isComboAttacking = value;
public void SetIsComboPossible(bool value) => MyCurrentState.isComboPossible = value;
public void SetIsDashing(bool value) => MyComponents.movement.SetIsDashing(value);
public void SetEnableDashing(bool value) => MyComponents.movement.SetEnableDashing(value);
public Vector3 GetCurrentPosition() => MyComponents.movement.GetCurrentPosition();
public void SetIsInvincibility(bool value) => MyCurrentState.isInvincibility = value;
public void SetIsTrigger(bool value) => MyComponents.movement.SetIsTrigger(value);
public void SetUseGravity(bool value) => MyComponents.movement.SetUseGravity(value);
public void SetPreviousMoveDirection(Vector3 value)
{
MyComponents.movement.SetPreviousMoveDirection(value);
if (value != Vector3.zero)
{
MyComponents.animator.SetFloat(XDirectionHash, value.x);
MyComponents.animator.SetFloat(ZDirectionHash, value.z);
}
}
#endregion
}
}