2023-09-18 00:21:55 +00:00
|
|
|
using BehaviorDesigner.Runtime;
|
2023-09-13 03:23:27 +00:00
|
|
|
using UnityEngine;
|
|
|
|
using UnityEngine.AI;
|
|
|
|
using UnityEngine.Animations;
|
|
|
|
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
|
|
namespace BlueWaterProject
|
|
|
|
{
|
|
|
|
public abstract class CombatAi : HumanAi
|
|
|
|
{
|
|
|
|
#region Properties and variables
|
|
|
|
|
|
|
|
// 일반 변수
|
2023-09-18 00:21:55 +00:00
|
|
|
[SerializeField] protected bool isDrawGizmosInFieldOfView = true;
|
|
|
|
[SerializeField] protected bool isAttacking;
|
|
|
|
[SerializeField] protected LayerMask targetLayer;
|
|
|
|
[SerializeField] protected Vector3 defensePos;
|
2023-09-13 07:05:21 +00:00
|
|
|
|
2023-09-18 00:21:55 +00:00
|
|
|
[SerializeField] protected Transform targetTransform;
|
|
|
|
[SerializeField] protected Collider[] colliderWithinRange = new Collider[TARGET_MAX_SIZE];
|
|
|
|
[SerializeField] protected IslandInfo attackingIslandInfo;
|
|
|
|
[SerializeField] protected IslandInfo defendingIslandInfo;
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
// 컴포넌트 관련 변수
|
2023-09-13 07:05:21 +00:00
|
|
|
protected Animator combatAnimator;
|
2023-09-18 00:21:55 +00:00
|
|
|
protected NavMeshAgent combatAgent;
|
2023-09-13 03:23:27 +00:00
|
|
|
protected CapsuleCollider myCollider;
|
|
|
|
protected CapsuleCollider hitBoxCollider;
|
|
|
|
protected LookAtConstraint lookAtConstraint;
|
2023-09-18 00:21:55 +00:00
|
|
|
protected BehaviorTree behaviorTree;
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
// 애니메이션 관련 변수
|
|
|
|
protected static readonly int SpeedHash = Animator.StringToHash("Speed");
|
|
|
|
protected static readonly int AttackHash = Animator.StringToHash("Attack");
|
|
|
|
protected static readonly int DamageHash = Animator.StringToHash("TakeDamage");
|
|
|
|
protected static readonly int DeathTypeHash = Animator.StringToHash("DeathType");
|
|
|
|
protected static readonly int DeathHash = Animator.StringToHash("Death");
|
|
|
|
protected static readonly int ShieldHash = Animator.StringToHash("Shield");
|
|
|
|
protected static readonly int OutlineColorHash = Shader.PropertyToID("_OutlineColor");
|
2023-09-18 00:21:55 +00:00
|
|
|
|
|
|
|
protected const int TARGET_MAX_SIZE = 30;
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Abstract methods
|
|
|
|
|
|
|
|
protected abstract void SetLayer();
|
2023-09-18 05:02:11 +00:00
|
|
|
protected abstract void SetCurrentHp(float value, bool useBehaviorTreeVariable = false);
|
2023-09-18 00:21:55 +00:00
|
|
|
protected abstract void RemoveAiListElement();
|
|
|
|
public abstract void FindTarget();
|
|
|
|
public abstract bool CanAttack();
|
|
|
|
public abstract void Attack();
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Unity built-in methods
|
|
|
|
|
|
|
|
protected override void Awake()
|
|
|
|
{
|
2023-09-13 07:05:21 +00:00
|
|
|
base.Awake();
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
FlagLookAtCamera();
|
|
|
|
SetLayer();
|
|
|
|
}
|
|
|
|
|
2023-09-18 00:21:55 +00:00
|
|
|
private void Update()
|
|
|
|
{
|
|
|
|
if (combatAnimator.runtimeAnimatorController != null && combatAnimator.isActiveAndEnabled)
|
|
|
|
{
|
|
|
|
combatAnimator.SetFloat(SpeedHash, combatAgent.velocity.normalized.magnitude);
|
|
|
|
}
|
|
|
|
UpdateLookAtTarget();
|
|
|
|
}
|
|
|
|
|
2023-09-13 03:23:27 +00:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Custom methods
|
|
|
|
|
|
|
|
protected override void InitComponent()
|
|
|
|
{
|
|
|
|
base.InitComponent();
|
|
|
|
|
2023-09-13 07:05:21 +00:00
|
|
|
combatAnimator = Utils.GetComponentAndAssert<Animator>(transform);
|
2023-09-18 00:21:55 +00:00
|
|
|
combatAgent = Utils.GetComponentAndAssert<NavMeshAgent>(transform);
|
2023-09-13 03:23:27 +00:00
|
|
|
myCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform);
|
|
|
|
hitBoxCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform.Find("HitBox"));
|
|
|
|
lookAtConstraint = Utils.GetComponentAndAssert<LookAtConstraint>(flagContainer);
|
|
|
|
}
|
|
|
|
|
2023-09-13 07:05:21 +00:00
|
|
|
protected void FlagLookAtCamera()
|
2023-09-13 03:23:27 +00:00
|
|
|
{
|
2023-09-18 06:28:37 +00:00
|
|
|
if (GameManager.Inst.CameraController.MainCam != null)
|
2023-09-13 03:23:27 +00:00
|
|
|
{
|
|
|
|
var source = new ConstraintSource
|
|
|
|
{
|
2023-09-18 06:28:37 +00:00
|
|
|
sourceTransform = GameManager.Inst.CameraController.MainCam.transform,
|
2023-09-13 03:23:27 +00:00
|
|
|
weight = 1f
|
|
|
|
};
|
|
|
|
lookAtConstraint.AddSource(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
lookAtConstraint.constraintActive = true;
|
|
|
|
}
|
2023-09-18 00:21:55 +00:00
|
|
|
|
|
|
|
protected void SetBehaviorTree(ExternalBehaviorTree externalBehaviorTree)
|
|
|
|
{
|
|
|
|
if (!externalBehaviorTree)
|
|
|
|
{
|
|
|
|
print("externalBehaviorTree == null error");
|
|
|
|
}
|
|
|
|
|
|
|
|
var bt = gameObject.GetComponent<BehaviorTree>();
|
|
|
|
if (bt != null)
|
|
|
|
{
|
|
|
|
Destroy(bt);
|
|
|
|
}
|
|
|
|
|
|
|
|
behaviorTree = gameObject.AddComponent<BehaviorTree>();
|
|
|
|
behaviorTree.StartWhenEnabled = false;
|
|
|
|
behaviorTree.ExternalBehavior = externalBehaviorTree;
|
|
|
|
|
|
|
|
behaviorTree.EnableBehavior();
|
|
|
|
}
|
|
|
|
|
2023-09-18 05:02:11 +00:00
|
|
|
public void MoveTarget(Vector3 targetPos, float stopDistance)
|
2023-09-18 00:21:55 +00:00
|
|
|
{
|
|
|
|
if (Vector3.Distance(combatAgent.destination, targetPos) < 0.1f) return;
|
|
|
|
|
2023-09-18 05:02:11 +00:00
|
|
|
combatAgent.stoppingDistance = stopDistance;
|
2023-09-18 00:21:55 +00:00
|
|
|
combatAgent.SetDestination(targetPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateLookAtTarget()
|
|
|
|
{
|
|
|
|
if (CanAttack())
|
|
|
|
{
|
|
|
|
combatAgent.updateRotation = false;
|
|
|
|
|
|
|
|
var targetPos = targetTransform.position;
|
|
|
|
targetPos.y = transform.position.y;
|
|
|
|
transform.LookAt(targetPos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
combatAgent.updateRotation = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 05:02:11 +00:00
|
|
|
public void SetTargetTransform(Transform value, bool useBehaviorTreeVariable = false)
|
2023-09-18 00:21:55 +00:00
|
|
|
{
|
|
|
|
targetTransform = value;
|
|
|
|
|
2023-09-18 05:02:11 +00:00
|
|
|
if (!useBehaviorTreeVariable) return;
|
|
|
|
|
|
|
|
Utils.SetBehaviorVariable(behaviorTree, "TargetTransform", value);
|
2023-09-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void Die()
|
|
|
|
{
|
|
|
|
RemoveIslandInfo();
|
|
|
|
RemoveAiListElement();
|
|
|
|
|
|
|
|
StopAllCoroutines();
|
|
|
|
combatAgent.enabled = false;
|
|
|
|
myCollider.enabled = false;
|
|
|
|
hitBoxCollider.enabled = false;
|
|
|
|
|
|
|
|
var randomValue = Random.Range(0, 2);
|
|
|
|
combatAnimator.SetInteger(DeathTypeHash, randomValue);
|
|
|
|
|
|
|
|
// TODO : 죽었을 때 처리(죽는 애니메이션 이후 사라지는 효과 등)
|
|
|
|
combatAnimator.SetTrigger(DeathHash);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RemoveIslandInfo()
|
|
|
|
{
|
|
|
|
if (defendingIslandInfo == null) return;
|
|
|
|
|
|
|
|
defendingIslandInfo.RemoveListElement(defendingIslandInfo.EnemyList, transform);
|
|
|
|
}
|
2023-09-13 03:23:27 +00:00
|
|
|
|
2023-09-13 07:05:21 +00:00
|
|
|
protected void SetAnimatorController(string controllerName) => combatAnimator.runtimeAnimatorController =
|
|
|
|
UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == controllerName);
|
2023-09-18 00:21:55 +00:00
|
|
|
protected void SetMoveSpeed(float value) => combatAgent.speed = value;
|
|
|
|
public void SetAttackingIslandInfo(IslandInfo info) => attackingIslandInfo = info;
|
|
|
|
public void SetDefendingIslandInfo(IslandInfo info) => defendingIslandInfo = info;
|
|
|
|
public Transform GetTargetTransform() => targetTransform;
|
|
|
|
public Vector3 GetDefensePos() => defensePos;
|
2023-09-18 05:02:11 +00:00
|
|
|
public NavMeshAgent GetCombatAgent() => combatAgent;
|
2023-09-13 03:23:27 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|