// using System; // using System.Collections; // using BehaviorDesigner.Runtime; // using Sirenix.OdinInspector; // using UnityEngine; // using UnityEngine.AI; // using UnityEngine.InputSystem; // using UnityEngine.UI; // // // ReSharper disable once CheckNamespace // namespace BlueWaterProject // { // [RequireComponent(typeof(PlayerInput))] // public abstract class Crewmate : BaseCharacter, IDamageable, IAnimatorBridge, IAiView, INormalAttack, IInIslandPlayer // { // #region Properties and variables // // // DrawGizmos // [Title("DrawGizmos")] // [Tooltip("전체 Gizmos 그리기 여부")] // [SerializeField] private bool isDrawGizmos = true; // // [ShowIf("@isDrawGizmos")] // [Tooltip("타겟 인식 범위 그리기 여부")] // [SerializeField] private bool isDrawViewRange = true; // // [ShowIf("@isDrawGizmos")] // [Tooltip("이동제한 범위 그리기 여부")] // [SerializeField] private bool isDrawDefenseRange = true; // // [ShowIf("@isDrawGizmos")] // [Tooltip("타겟과의 상태 그리기 여부\n빨간색 = 공격 범위 밖\n파란색 = 공격 범위 안")] // [SerializeField] private bool isDrawTargetRange = true; // // // Stat // [field: Title("Stat")] // [field: Tooltip("최대 체력 설정")] // [field: SerializeField] public float MaxHp { get; private set; } = 100f; // // [field: Tooltip("현재 체력")] // [field: SerializeField] public float CurrentHp { get; private set; } // // [field: Tooltip("이동 속도 설정")] // [field: SerializeField] public float MoveSpd { get; set; } = 5f; // // [field: Tooltip("공격력 설정")] // [field: SerializeField] public float Atk { get; private set; } = 10f; // // [field: Tooltip("공격 속도(다음 공격 주기)\nAtkCooldown = 2f (2초마다 1번 공격)")] // [field: SerializeField] public float AtkCooldown { get; private set; } = 1f; // // [field: Tooltip("공격 사거리 설정")] // [field: SerializeField] public float AtkRange { get; set; } = 1.5f; // // [field: Tooltip("이동 제한 범위 설정")] // [field: SerializeField] public float DefenseRange { get; private set; } = 20f; // // [field: Tooltip("Idle 상태에서 랜덤으로 이동 여부")] // [field: SerializeField] public bool IsRandomMove { get; set; } // // [field: ShowIf("@IsRandomMove")] // [field: Tooltip("Idle 상태에서 이동하는 범위 설정")] // [field: SerializeField] public float RandomMoveRange { get; set; } // // // HpSlider // [Title("HpSlider")] // [SerializeField] private bool useHpSlider = true; // // [ShowIf("@useHpSlider")] // [Required("HpSlider 프리팹을 넣어주세요.")] // [SerializeField] private GameObject hpSliderPrefab; // // [ShowIf("@useHpSlider")] // [SerializeField] private Vector3 hpSliderOffset = Vector3.up; // // [ShowIf("@useHpSlider")] // [DisableIf("@true")] // [SerializeField] private Slider hpSlider; // // // Data // [field: Title("Data")] // [field: DisableIf("@true")] // [field: SerializeField] public Vector3 DefensePos { get; set; } // [field: DisableIf("@true")] // [field: SerializeField] public bool IsCombated { get; set; } // [field: DisableIf("@true")] // [field: SerializeField] public bool BeAttackedInIdle { get; set; } // [field: DisableIf("@true")] // [field: SerializeField] public bool UseRigidbody { get; set; } // [DisableIf("@true")] // [SerializeField] private bool beAttacked; // [DisableIf("@true")] // [SerializeField] protected bool isAttacking; // // // 일반 변수 // public int CrewmatePrefabIndex { get; set; } = -1; // // protected Vector2 movementInput; // protected bool usedNormalAttackCoroutine; // protected WaitForSeconds waitAtkCooldown; // // // 컴포넌트 // public GameObject GameObject => gameObject; // public Transform Transform => transform; // public Rigidbody Rb { get; set; } // public Collider MyCollider { get; set; } // public NavMeshAgent Agent { get; set; } // private BehaviorTree bt; // private Transform unitRoot; // protected Animator myAnimator; // private Canvas worldSpaceCanvas; // // // Hash // protected static readonly int RunStateHash = Animator.StringToHash("RunState"); // protected static readonly int AttackHash = Animator.StringToHash("Attack"); // protected static readonly int AttackStateHash = Animator.StringToHash("AttackState"); // protected static readonly int NormalStateHash = Animator.StringToHash("NormalState"); // protected static readonly int DieHash = Animator.StringToHash("Die"); // // // Const // private static readonly WaitForSeconds BeAttackedWaitTime = new(0.3f); // // #endregion // // #region abstract // // protected abstract IEnumerator NormalAttackCoroutine(); // // #endregion // // #region Unity built-in methods // // protected override void Awake() // { // base.Awake(); // // Rb = GetComponent(); // MyCollider = GetComponent(); // Agent = GetComponent(); // bt = GetComponent(); // // unitRoot = transform.Find("UnitRoot"); // if (unitRoot == null) // { // print("UnitRoot를 찾을 수 없습니다."); // } // else // { // myAnimator = unitRoot.GetComponent(); // if (myAnimator == null) // { // print("myAnimator를 찾을 수 없습니다."); // } // } // // worldSpaceCanvas = GameObject.Find("WorldSpaceCanvas")?.GetComponent(); // if (worldSpaceCanvas == null) // { // print("WorldSpaceCanvas 찾을 수 없습니다."); // } // else // { // if (useHpSlider) // { // hpSlider = Instantiate(hpSliderPrefab, worldSpaceCanvas.transform).GetComponent(); // hpSlider.gameObject.name = gameObject.name + " HpSlider"; // hpSlider.transform.rotation = unitRoot.transform.rotation; // } // } // } // // protected override void Start() // { // base.Start(); // // TargetLayer = LayerMask.GetMask("Enemy"); // // waitAtkCooldown = new WaitForSeconds(AtkCooldown); // Agent.updateRotation = false; // // SetAgentSpeed(MoveSpd); // hpSlider.maxValue = MaxHp; // SetCurrentHp(MaxHp); // } // // protected override void Update() // { // switch (useHpSlider) // { // case true when CurrentHp > 0 && CurrentHp < MaxHp: // { // if (!hpSlider.gameObject.activeSelf) // { // hpSlider.gameObject.SetActive(true); // } // // var localOffset = unitRoot.TransformPoint(hpSliderOffset); // hpSlider.transform.position = localOffset; // break; // } // case true when CurrentHp <= 0 || CurrentHp >= MaxHp: // { // if (hpSlider.gameObject.activeSelf) // { // hpSlider.gameObject.SetActive(false); // } // // break; // } // } // // if (CurrentHp <= 0) return; // // if (GameManager.Inst.CurrentInIslandPlayer.GameObject == gameObject) // { // // 움직이는 경우 // if (movementInput.x != 0 || movementInput.y != 0) // { // // Rigidbody 사용 // if (!UseRigidbody) // { // UseRigidbodyMovement(); // } // // if (!beAttacked) // { // myAnimator.SetFloat(RunStateHash, 0.5f); // } // } // // 멈춰있는 경우 // else // { // // NavMeshAgent 사용 // if (UseRigidbody) // { // UseAgentMovement(); // } // // if (Agent.velocity.x != 0 || Agent.velocity.z != 0) // { // myAnimator.SetFloat(RunStateHash, 0.5f); // } // else if (!beAttacked) // { // myAnimator.SetFloat(RunStateHash, 0f); // } // } // } // else // { // if (GameManager.Inst.CurrentInIslandPlayer.GameObject && GameManager.Inst.CurrentInIslandPlayer.UseRigidbody && !Target) // { // if (!UseRigidbody) // { // UseRigidbodyMovement(); // } // // if (!beAttacked) // { // myAnimator.SetFloat(RunStateHash, 0.5f); // } // } // else if (GameManager.Inst.CurrentInIslandPlayer.GameObject && !GameManager.Inst.CurrentInIslandPlayer.UseRigidbody) // { // if (UseRigidbody) // { // UseAgentMovement(); // } // // if (Agent.velocity.x != 0 || Agent.velocity.z != 0) // { // myAnimator.SetFloat(RunStateHash, 0.5f); // } // else if (!beAttacked) // { // myAnimator.SetFloat(RunStateHash, 0f); // } // } // } // // var localScale = transform.localScale; // if (UseRigidbody) // { // localScale.x = Rb.velocity.x switch // { // > 0 => Mathf.Abs(localScale.x), // < 0 => -Mathf.Abs(localScale.x), // _ => localScale.x // }; // } // else // { // if (Agent.velocity.x != 0) // { // localScale.x = Agent.velocity.x switch // { // > 0 => Mathf.Abs(localScale.x), // < 0 => -Mathf.Abs(localScale.x), // _ => localScale.x // }; // } // else // { // if (Target) // { // var targetToDistanceX = Target.bounds.center.x - MyCollider.bounds.center.x; // localScale.x = targetToDistanceX switch // { // > 0 => Mathf.Abs(localScale.x), // < 0 => -Mathf.Abs(localScale.x), // _ => localScale.x // }; // } // } // } // // transform.localScale = localScale; // } // // protected override void FixedUpdate() // { // if (CurrentHp <= 0) return; // // if (UseRigidbody) // { // // var movement = GameManager.Inst.InIslandPlayer.Rb.velocity * (MoveSpd / GameManager.Inst.InIslandPlayer.MoveSpd); // // rb.velocity = new Vector3(movement.x, 0, movement.z); // // if (GameManager.Inst.CurrentInIslandPlayer.GameObject == gameObject) // { // var localMovement = new Vector3(movementInput.x, 0, movementInput.y); // var worldDirection = transform.TransformDirection(localMovement); // // var movement = worldDirection * MoveSpd; // Rb.velocity = new Vector3(movement.x, 0, movement.z); // } // else // { // var predictedPos = GameManager.Inst.CurrentInIslandPlayer.Rb.position + GameManager.Inst.CurrentInIslandPlayer.Rb.velocity; // var moveDir = (predictedPos - transform.position).normalized; // Rb.velocity = new Vector3(moveDir.x, 0, moveDir.z) * MoveSpd; // } // } // } // // #endregion // // #region Interfaces // // //IDamageable // public void TakeDamage(float attackerPower, Vector3? attackPos = null) // { // IsCombated = true; // // if (!Target) // { // BeAttackedInIdle = true; // bt.SendEvent("BeAttackedInIdle", attackPos); // } // // var changeHp = Mathf.Max(CurrentHp - attackerPower, 0); // SetCurrentHp(changeHp); // // // 죽었는지 체크 // if (changeHp == 0f) // { // Die(); // return; // } // // StartCoroutine(nameof(BeAttacked)); // } // // public void Die() // { // myAnimator.SetTrigger(DieHash); // MyCollider.enabled = false; // if (Agent.enabled) // { // Agent.isStopped = true; // } // else // { // Rb.isKinematic = true; // } // Agent.enabled = false; // // if (GameManager.Inst.CurrentInIslandPlayer == (IInIslandPlayer)this) // { // foreach (var crewmate in GameManager.Inst.CurrentCrewmateList) // { // if (crewmate == null || !crewmate.gameObject.activeSelf || crewmate.CurrentHp <= 0) continue; // // GameManager.Inst.SetCurrentInIslandPlayer(crewmate); // return; // } // // // 게임 종료 // var overlayCanvas = GameObject.Find("OverlayCanvas"); // overlayCanvas.transform.Find("RestartPopUp").gameObject.SetActive(true); // return; // } // // Destroy(hpSlider.gameObject, 2f); // Destroy(gameObject, 2f); // } // // public float GetCurrentHp() => CurrentHp; // // // IAnimatorBridge // public virtual void AttackTiming() // { // if (!Target) return; // // var myCenterPos = MyCollider.bounds.center; // var targetDir = (Target.bounds.center - myCenterPos).normalized; // // if (!Physics.Raycast(MyCollider.bounds.center, targetDir, out var hit, AtkRange, TargetLayer)) return; // // var iDamageable = hit.transform.GetComponent(); // iDamageable.TakeDamage(Atk); // } // // public void SetIsAttacking(int boolValue) => isAttacking = boolValue == 1; // // // IAiView // [field: Title("IAiView")] // [field: SerializeField] public float ViewRadius { get; set; } = 15f; // [field: SerializeField] public Collider[] Targets { get; set; } = new Collider[MAX_COLLIDERS]; // [field: SerializeField] public Collider Target { get; set; } // [field: SerializeField] public LayerMask TargetLayer { get; set; } // // private const int MAX_COLLIDERS = 30; // // public void FindNearestTargetInRange(Vector3 centerPos, bool targetIsTrigger = true) // { // Array.Clear(Targets, 0, MAX_COLLIDERS); // // var numResults = Physics.OverlapSphereNonAlloc(centerPos, ViewRadius, Targets, TargetLayer, // targetIsTrigger ? QueryTriggerInteraction.Collide : QueryTriggerInteraction.Ignore); // // if (numResults <= 0) // { // SetTarget(null); // return; // } // // var nearestDistance = ViewRadius * ViewRadius; // Collider nearestTargetCollider = null; // // for (var i = 0; i < numResults; i++) // { // var distanceSqrToTarget = (centerPos - Targets[i].bounds.center).sqrMagnitude; // // if (distanceSqrToTarget >= nearestDistance) continue; // // nearestDistance = distanceSqrToTarget; // nearestTargetCollider = Targets[i]; // } // // SetTarget(nearestTargetCollider); // } // // public void SetTarget(Collider value) // { // Target = value; // // if (value != null) // { // IsCombated = true; // BeAttackedInIdle = false; // } // } // // public bool IsTargetWithinRange(Vector3 centerPos, float range) // { // var inRange = Vector3.Distance(centerPos, Target.bounds.center) <= AtkRange; // return inRange; // } // // public bool GoOutOfBounds() // { // var defensePosInRange = Vector3.Distance(transform.position, DefensePos) <= DefenseRange; // return !defensePosInRange; // } // // public void MoveTarget(Vector3 targetPos, float speed, float stopDistance = float.MaxValue) // { // if (Vector3.Distance(Agent.destination, targetPos) < 0.1f) return; // // SetAgentSpeed(speed); // Agent.stoppingDistance = stopDistance; // Agent.isStopped = false; // Agent.SetDestination(targetPos); // } // // // INormalAttack // public void NormalAttack() // { // StartCoroutine(nameof(NormalAttackCoroutine)); // } // // public void StopNormalAttackCoroutine() => StopCoroutine(nameof(NormalAttackCoroutine)); // public bool GetUsedNormalAttackCoroutine() => usedNormalAttackCoroutine; // // #endregion // // #region Player input system // // public void OnMove(InputValue value) // { // if (CurrentHp <= 0) return; // // movementInput = value.Get(); // } // // #endregion // // #region Custom methods // // private void UseRigidbodyMovement() // { // UseRigidbody = true; // Rb.isKinematic = false; // Agent.enabled = false; // } // // private void UseAgentMovement() // { // UseRigidbody = false; // Rb.isKinematic = true; // Agent.enabled = true; // // if (Target) return; // // MoveTarget(GameManager.Inst.CurrentInIslandPlayer.Transform.position, MoveSpd, GlobalValue.MAXIMUM_STOP_DISTANCE); // } // // private IEnumerator BeAttacked() // { // beAttacked = true; // myAnimator.SetFloat(RunStateHash, 1f); // yield return BeAttackedWaitTime; // // beAttacked = false; // } // // private void SetCurrentHp(float value) // { // CurrentHp = value; // // if (useHpSlider) // { // hpSlider.value = value; // } // } // // private void SetAgentSpeed(float value) => Agent.speed = value; // // #endregion // } // }