358 lines
14 KiB
C#
358 lines
14 KiB
C#
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;
|
|
public bool isUsingSkill;
|
|
}
|
|
|
|
[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 myAnimator = MyComponents.animator;
|
|
var targetLayer = MyCharacterOption.targetLayer;
|
|
var ui = UiManager.Inst.CombatUi.MainSkillUi;
|
|
ui.gameObject.SetActive(true);
|
|
|
|
mainSkill.SkillInputData.InitInputData(myCollider, myRb, null, myVisualLook, myAnimator, null, 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.StartPosition = 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
|
|
}
|
|
} |