OldBlueWater/BlueWater/Assets/02.Scripts/Ai/Human/Combat/CombatAi.cs

193 lines
6.8 KiB
C#
Raw Normal View History

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)
{
2023-09-20 05:01:46 +00:00
combatAnimator.SetFloat(SpeedHash, combatAgent.velocity.magnitude);
2023-09-18 00:21:55 +00:00
}
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
{
if (GameManager.Inst.CameraController.MainCam != null)
2023-09-13 03:23:27 +00:00
{
var source = new ConstraintSource
{
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
}
}