Enum 위치 변경, Draw 위치 오류 수정
This commit is contained in:
parent
d5a77eeb7c
commit
cc6eb456c1
@ -1,802 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.Animations;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public enum EAiType
|
||||
{
|
||||
NONE = -1,
|
||||
PLAYER,
|
||||
PIRATE,
|
||||
ENEMY
|
||||
}
|
||||
|
||||
public enum EAttackerType
|
||||
{
|
||||
NONE = -1,
|
||||
OFFENSE,
|
||||
DEFENSE
|
||||
}
|
||||
|
||||
public enum EOffenseType
|
||||
{
|
||||
NONE = -1,
|
||||
NORMAL,
|
||||
ONLY_HOUSE
|
||||
}
|
||||
|
||||
public enum EDefenseType
|
||||
{
|
||||
NONE = -1,
|
||||
STRIKER,
|
||||
MIDFIELDER,
|
||||
DEFENDER,
|
||||
KEEPER
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AiController : MonoBehaviour, IDamageable
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[Title("Skin")]
|
||||
[Tooltip("SkinnedMeshRenderer, MeshRenderer의 Material을 모두 담고 있는 리스트")]
|
||||
[SerializeField] protected List<Material> skinMaterialList = new(10);
|
||||
|
||||
[Tooltip("캐릭터 외곽선의 기본 색상")]
|
||||
[SerializeField] protected Color defaultSkinColor = Color.black;
|
||||
|
||||
[Tooltip("캐릭터에 마우스 커서가 올라가 있을 때 색상")]
|
||||
[SerializeField] protected Color mouseEnterHighlightSkinColor = Color.white;
|
||||
|
||||
[Tooltip("캐릭터가 선택되었을 때 색상")]
|
||||
[SerializeField] protected Color selectedSkinColor = Color.red;
|
||||
|
||||
[DisableIf("@true")]
|
||||
[SerializeField] private IslandInfo islandInfo;
|
||||
|
||||
public bool IsAttackCoroutine { get; set; }
|
||||
public Vector3 DefensePos { get; set; }
|
||||
|
||||
protected bool isAttacking;
|
||||
|
||||
protected Transform backpackContainer;
|
||||
protected Transform leftWeaponContainer;
|
||||
protected Transform leftShieldContainer;
|
||||
protected Transform headContainer;
|
||||
protected Transform rightWeaponContainer;
|
||||
protected Transform bodyContainer;
|
||||
protected Transform flagContainer;
|
||||
|
||||
protected Animator aiAnimator;
|
||||
protected NavMeshAgent navMeshAgent;
|
||||
//private UnitController myUnitController;
|
||||
//private UnitController mouseEnterUnitController;
|
||||
private UnitSelection unitSelection;
|
||||
private CapsuleCollider myCollider;
|
||||
private LookAtConstraint lookAtConstraint;
|
||||
protected CapsuleCollider hitBoxCollider;
|
||||
protected CloseWeapon closeWeapon;
|
||||
|
||||
private static readonly int SpeedHash = Animator.StringToHash("Speed");
|
||||
protected static readonly int AttackHash = Animator.StringToHash("Attack");
|
||||
private static readonly int DamageHash = Animator.StringToHash("TakeDamage");
|
||||
private static readonly int DeathTypeHash = Animator.StringToHash("DeathType");
|
||||
private static readonly int DeathHash = Animator.StringToHash("Death");
|
||||
private static readonly int ShieldHash = Animator.StringToHash("Shield");
|
||||
private static readonly int OutlineColorHash = Shader.PropertyToID("_OutlineColor");
|
||||
|
||||
protected static readonly WaitForSeconds FindTargetWaitTime = new(0.5f);
|
||||
private static readonly WaitForSeconds CheckAgentArriveTime = new(0.1f);
|
||||
|
||||
private delegate EnemyView GetAiViewDataDelegate(string viewIdx);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity built-in function
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
DrawGizmosInFieldOfView();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
InitComponent();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitStart();
|
||||
ExecuteFindTarget();
|
||||
//Attack();
|
||||
navMeshAgent.stoppingDistance = AiStat.AtkRange;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
RemoveIslandInfo();
|
||||
StopAllCoroutines();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
aiAnimator.SetFloat(SpeedHash, navMeshAgent.velocity.normalized.magnitude);
|
||||
|
||||
// if (!TargetTransform || !navMeshAgent.enabled) return;
|
||||
//
|
||||
// var distanceToTarget = Vector3.Distance(transform.position, TargetTransform.position);
|
||||
//
|
||||
// navMeshAgent.isStopped = distanceToTarget <= navMeshAgent.stoppingDistance;
|
||||
|
||||
// switch (AiStat.AttackerType)
|
||||
// {
|
||||
// case EAttackerType.NONE:
|
||||
// break;
|
||||
// case EAttackerType.OFFENSE:
|
||||
// navMeshAgent.SetDestination(distanceToTarget <= AiStat.AtkRange ? transform.position : TargetTransform.position);
|
||||
// break;
|
||||
// case EAttackerType.DEFENSE:
|
||||
// switch (AiStat.DefenseType)
|
||||
// {
|
||||
// case EDefenseType.NONE:
|
||||
// print("AiStat.DefenseType == NONE Error");
|
||||
// break;
|
||||
// case EDefenseType.STRIKER:
|
||||
// navMeshAgent.SetDestination(distanceToTarget <= AiStat.AtkRange ? transform.position : TargetTransform.position);
|
||||
// break;
|
||||
// case EDefenseType.MIDFIELDER:
|
||||
// navMeshAgent.SetDestination(distanceToTarget <= AiStat.AtkRange ? transform.position : TargetTransform.position);
|
||||
// break;
|
||||
// case EDefenseType.DEFENDER:
|
||||
// navMeshAgent.SetDestination(distanceToTarget <= AiStat.AtkRange ? transform.position : TargetTransform.position);
|
||||
// break;
|
||||
// case EDefenseType.KEEPER:
|
||||
// break;
|
||||
// default:
|
||||
// throw new ArgumentOutOfRangeException();
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// throw new ArgumentOutOfRangeException();
|
||||
// }
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
UpdateLookAtTarget();
|
||||
}
|
||||
|
||||
// private void OnMouseEnter()
|
||||
// {
|
||||
// if (AiStat.AiType == EAiType.ENEMY) return;
|
||||
//
|
||||
// mouseEnterUnitController = gameObject.GetComponentInParent<UnitController>();
|
||||
//
|
||||
// if (mouseEnterUnitController == unitSelection.SelectedUnitController) return;
|
||||
//
|
||||
// foreach (var pirateUnitStat in mouseEnterUnitController.pirateUnitStat.UnitList)
|
||||
// {
|
||||
// pirateUnitStat.MouseEnterHighlight();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void OnMouseExit()
|
||||
// {
|
||||
// if (AiStat.AiType == EAiType.ENEMY ||
|
||||
// !mouseEnterUnitController || mouseEnterUnitController == unitSelection.SelectedUnitController) return;
|
||||
//
|
||||
// foreach (var pirateUnitStat in mouseEnterUnitController.pirateUnitStat.UnitList)
|
||||
// {
|
||||
// pirateUnitStat.ResetHighlight();
|
||||
// }
|
||||
//
|
||||
// mouseEnterUnitController = null;
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region interface property and function
|
||||
|
||||
#region IAiStat
|
||||
|
||||
[field: Space(10f)]
|
||||
[field: Title("AiStat")]
|
||||
[field: SerializeField] public EnemyStat AiStat { get; set; } = new();
|
||||
|
||||
public float GetCurrentHp() => AiStat.CurrentHp;
|
||||
public void SetCurrentHp(float value) => AiStat.CurrentHp = value;
|
||||
|
||||
public void TakeDamage(float attackerPower, float attackerShieldPenetrationRate, Vector3? attackPos = null)
|
||||
{
|
||||
if (attackPos != null && navMeshAgent.enabled && AiStat.AttackerType == EAttackerType.DEFENSE && !TargetTransform)
|
||||
{
|
||||
BeAttackedMovement((Vector3)attackPos);
|
||||
}
|
||||
|
||||
// 회피 성공 체크
|
||||
if (Random.Range(0, 100) < AiStat.AvoidanceRate)
|
||||
{
|
||||
// TODO : 회피 처리
|
||||
return;
|
||||
}
|
||||
|
||||
var finalDamage = Utils.CalcDamage(attackerPower, attackerShieldPenetrationRate, AiStat);
|
||||
|
||||
// 방패 막기 체크
|
||||
if (finalDamage == 0f)
|
||||
{
|
||||
aiAnimator.SetTrigger(ShieldHash);
|
||||
return;
|
||||
}
|
||||
var changeHp = Mathf.Max(AiStat.CurrentHp - finalDamage, 0);
|
||||
SetCurrentHp(changeHp);
|
||||
|
||||
// 죽었는지 체크
|
||||
if (changeHp == 0f)
|
||||
{
|
||||
RemoveIslandInfo();
|
||||
|
||||
StopAllCoroutines();
|
||||
navMeshAgent.enabled = false;
|
||||
myCollider.enabled = false;
|
||||
hitBoxCollider.enabled = false;
|
||||
|
||||
var randomValue = Random.Range(0, 2);
|
||||
aiAnimator.SetInteger(DeathTypeHash, randomValue);
|
||||
|
||||
// TODO : 죽었을 때 처리(죽는 애니메이션 이후 사라지는 효과 등)
|
||||
aiAnimator.SetTrigger(DeathHash);
|
||||
|
||||
Invoke(nameof(DestroyObject), 3f);
|
||||
return;
|
||||
}
|
||||
|
||||
aiAnimator.SetTrigger(DamageHash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFieldOfView
|
||||
|
||||
[field: Space(10f)]
|
||||
[field: Title("FieldOfView")]
|
||||
[field: SerializeField] public bool IsDrawGizmosInFieldOfView { get; set; } = true;
|
||||
|
||||
[field: SerializeField] public LayerMask TargetLayer { get; set; }
|
||||
|
||||
[field: SerializeField] public Collider[] ColliderWithinRange { get; set; } = new Collider[TARGET_MAX_SIZE];
|
||||
|
||||
[field: SerializeField] public Transform TargetTransform { get; set; }
|
||||
|
||||
|
||||
protected const int TARGET_MAX_SIZE = 30;
|
||||
|
||||
public void DrawGizmosInFieldOfView()
|
||||
{
|
||||
if (!IsDrawGizmosInFieldOfView) return;
|
||||
|
||||
var myPos = transform.position;
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(myPos, AiStat.ViewRange);
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(myPos, AiStat.DefenseRange);
|
||||
|
||||
if (!TargetTransform) return;
|
||||
|
||||
Debug.DrawLine(myPos, TargetTransform.position, Color.red);
|
||||
}
|
||||
|
||||
public IEnumerator FindTargetInOffense()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
switch (AiStat.OffenseType)
|
||||
{
|
||||
case EOffenseType.NONE:
|
||||
print("AiStat.OffenseType == NONE Error");
|
||||
break;
|
||||
case EOffenseType.NORMAL:
|
||||
if (islandInfo.EnemyList.Count > 0)
|
||||
{
|
||||
SetNearestTargetInOffense(islandInfo.EnemyList);
|
||||
}
|
||||
else if (islandInfo.HouseList.Count > 0)
|
||||
{
|
||||
SetNearestTargetInOffense(islandInfo.HouseList);
|
||||
}
|
||||
break;
|
||||
case EOffenseType.ONLY_HOUSE:
|
||||
if (navMeshAgent.pathStatus == NavMeshPathStatus.PathPartial)
|
||||
{
|
||||
SetNearestTargetInOffense(islandInfo.TargetAllList);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (islandInfo.HouseList.Count > 0)
|
||||
{
|
||||
SetNearestTargetInOffense(islandInfo.HouseList);
|
||||
}
|
||||
else if (islandInfo.EnemyList.Count > 0)
|
||||
{
|
||||
SetNearestTargetInOffense(islandInfo.EnemyList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (TargetTransform && navMeshAgent.enabled)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, TargetTransform.position);
|
||||
|
||||
navMeshAgent.isStopped = distanceToTarget <= navMeshAgent.stoppingDistance;
|
||||
if (distanceToTarget > navMeshAgent.stoppingDistance)
|
||||
{
|
||||
navMeshAgent.SetDestination(TargetTransform.position);
|
||||
}
|
||||
}
|
||||
|
||||
yield return FindTargetWaitTime;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator FindTargetInDefense()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
switch (AiStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("AiStat.DefenseType == NONE Error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
SetNearestTargetInDefense(transform.position, AiStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.MIDFIELDER:
|
||||
SetNearestTargetInDefense(transform.position, AiStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
SetNearestTargetInDefense(DefensePos, AiStat.DefenseRange);
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
SetNearestTargetInDefense(transform.position, AiStat.ViewRange);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (TargetTransform && navMeshAgent.enabled)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, TargetTransform.position);
|
||||
|
||||
navMeshAgent.isStopped = distanceToTarget <= navMeshAgent.stoppingDistance;
|
||||
if (distanceToTarget > navMeshAgent.stoppingDistance)
|
||||
{
|
||||
navMeshAgent.SetDestination(TargetTransform.position);
|
||||
}
|
||||
}
|
||||
|
||||
yield return FindTargetWaitTime;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetNearestTargetInOffense<T>(List<T> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var nearestTarget = targetList.OrderBy(t =>
|
||||
{
|
||||
var myPos = transform.position;
|
||||
var targetTransform = (Transform)(object)t;
|
||||
|
||||
if (!targetTransform)
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
var targetCollider = targetTransform.GetComponent<Collider>();
|
||||
|
||||
if (!targetCollider)
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
var closestPoint = targetCollider.ClosestPoint(myPos);
|
||||
return Vector3.Distance(myPos, closestPoint);
|
||||
})
|
||||
.FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
TargetTransform = (Transform)(object)nearestTarget;
|
||||
}
|
||||
|
||||
public virtual void SetNearestTargetInDefense(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(ColliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, ColliderWithinRange,
|
||||
TargetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
TargetTransform = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, ColliderWithinRange[i].transform.position);
|
||||
|
||||
if (distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = ColliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
TargetTransform = nearestTargetTransform;
|
||||
}
|
||||
|
||||
public virtual void UpdateLookAtTarget()
|
||||
{
|
||||
if (CanAttack())
|
||||
{
|
||||
navMeshAgent.updateRotation = false;
|
||||
|
||||
var targetPos = TargetTransform.position;
|
||||
targetPos.y = transform.position.y;
|
||||
transform.LookAt(targetPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
navMeshAgent.updateRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IAiMover
|
||||
|
||||
[field: Space(10f)]
|
||||
[field: Title("AiMover")]
|
||||
[field: SerializeField] public bool IsCommanded { get; set; }
|
||||
|
||||
public void BeAttackedMovement(Vector3 attackPos)
|
||||
{
|
||||
switch (AiStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("AiStat.DefenseType == NONE Error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
Utils.SetCloseDestination(navMeshAgent, attackPos, AiStat.AtkRange - 0.5f, AiStat.AtkRange);
|
||||
break;
|
||||
case EDefenseType.MIDFIELDER:
|
||||
Utils.SetCloseDestination(navMeshAgent, attackPos, AiStat.AtkRange - 0.5f, AiStat.AtkRange);
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
if (Vector3.Distance(DefensePos, attackPos) <= AiStat.DefenseRange)
|
||||
{
|
||||
Utils.SetCloseDestination(navMeshAgent, attackPos, AiStat.AtkRange - 0.5f, AiStat.AtkRange);
|
||||
}
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void CommandMove(Vector3 targetPos)
|
||||
{
|
||||
StartCoroutine(CommandMoveCoroutine(targetPos));
|
||||
}
|
||||
|
||||
public IEnumerator CommandMoveCoroutine(Vector3 targetPos)
|
||||
{
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (Utils.SetCloseDestination(navMeshAgent, targetPos, 0.5f, 1f))
|
||||
{
|
||||
IsCommanded = true;
|
||||
}
|
||||
|
||||
while (navMeshAgent.pathPending || navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance)
|
||||
{
|
||||
yield return CheckAgentArriveTime;
|
||||
}
|
||||
|
||||
IsCommanded = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom function
|
||||
|
||||
private void InitComponent()
|
||||
{
|
||||
backpackContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Backpack_container"));
|
||||
leftWeaponContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 L Clavicle/Bip001 L UpperArm/Bip001 L Forearm/Bip001 L Hand/L_hand_container"));
|
||||
leftShieldContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 L Clavicle/Bip001 L UpperArm/Bip001 L Forearm/Bip001 L Hand/L_shield_container"));
|
||||
headContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Neck/Bip001 Head/Head_container"));
|
||||
rightWeaponContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 R Clavicle/Bip001 R UpperArm/Bip001 R Forearm/Bip001 R Hand/R_hand_container"));
|
||||
bodyContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Body_container"));
|
||||
flagContainer = Utils.GetComponentAndAssert<Transform>(transform.
|
||||
Find("Flag_container"));
|
||||
|
||||
aiAnimator = Utils.GetComponentAndAssert<Animator>(transform);
|
||||
navMeshAgent = Utils.GetComponentAndAssert<NavMeshAgent>(transform);
|
||||
//myUnitController = Utils.GetComponentAndAssert<UnitController>(transform.parent);
|
||||
myCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform);
|
||||
lookAtConstraint = Utils.GetComponentAndAssert<LookAtConstraint>(flagContainer);
|
||||
hitBoxCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform.Find("HitBox"));
|
||||
unitSelection = Utils.GetComponentAndAssert<UnitSelection>(UnitManager.Inst.transform);
|
||||
|
||||
if (Camera.main != null)
|
||||
{
|
||||
var source = new ConstraintSource
|
||||
{
|
||||
sourceTransform = Camera.main.transform,
|
||||
weight = 1f
|
||||
};
|
||||
lookAtConstraint.AddSource(source);
|
||||
}
|
||||
|
||||
lookAtConstraint.constraintActive = true;
|
||||
}
|
||||
|
||||
private void InitStart()
|
||||
{
|
||||
var getAiViewData = GetAiViewData(false);
|
||||
|
||||
InitViewModel(false);
|
||||
FindMaterial();
|
||||
SetLayer();
|
||||
SetCloseWeapon(getAiViewData);
|
||||
SetCurrentHp(AiStat.MaxHp);
|
||||
SetMoveSpeed(AiStat.MoveSpd);
|
||||
|
||||
DefensePos = transform.position;
|
||||
}
|
||||
|
||||
private void InitViewModel(bool isEditor)
|
||||
{
|
||||
var getAiViewData = GetAiViewData(isEditor);
|
||||
|
||||
SetActiveViewModel(backpackContainer, getAiViewData(AiStat.ViewIdx).Backpack);
|
||||
SetActiveViewModel(leftWeaponContainer, getAiViewData(AiStat.ViewIdx).LeftWeapon);
|
||||
SetActiveViewModel(leftShieldContainer, getAiViewData(AiStat.ViewIdx).LeftShield);
|
||||
SetActiveViewModel(headContainer, getAiViewData(AiStat.ViewIdx).Head);
|
||||
SetActiveViewModel(rightWeaponContainer, getAiViewData(AiStat.ViewIdx).RightWeapon);
|
||||
SetActiveViewModel(bodyContainer, getAiViewData(AiStat.ViewIdx).Body);
|
||||
SetActiveViewModel(flagContainer, getAiViewData(AiStat.ViewIdx).Flag);
|
||||
}
|
||||
|
||||
private void SetCloseWeapon(GetAiViewDataDelegate getAiViewData)
|
||||
{
|
||||
if (getAiViewData(AiStat.ViewIdx).RightWeapon == -1) return;
|
||||
|
||||
closeWeapon = rightWeaponContainer.GetChild(getAiViewData(AiStat.ViewIdx).RightWeapon).AddComponent<CloseWeapon>();
|
||||
closeWeapon.gameObject.layer = LayerMask.NameToLayer("Weapon");
|
||||
//closeWeapon.SetAttackerAiType(AiStat.AiType);
|
||||
closeWeapon.SetBoxCollider();
|
||||
}
|
||||
|
||||
private GetAiViewDataDelegate GetAiViewData(bool isEditor) => isEditor ? DataManager.Inst.GetEnemyViewSoFromKey : DataManager.Inst.GetEnemyViewDictionaryFromKey;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void InitStartInEditor()
|
||||
{
|
||||
var getAiViewData = GetAiViewData(true);
|
||||
|
||||
InitComponent();
|
||||
InitViewModel(true);
|
||||
SetLayer();
|
||||
SetCloseWeapon(getAiViewData);
|
||||
SetCurrentHp(AiStat.MaxHp);
|
||||
SetMoveSpeed(AiStat.MoveSpd);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void ExecuteFindTarget()
|
||||
{
|
||||
switch (AiStat.AttackerType)
|
||||
{
|
||||
case EAttackerType.NONE:
|
||||
print("AiStat.AttackerType == NONE Error");
|
||||
break;
|
||||
case EAttackerType.OFFENSE:
|
||||
StartCoroutine(nameof(FindTargetInOffense));
|
||||
break;
|
||||
case EAttackerType.DEFENSE:
|
||||
StartCoroutine(nameof(FindTargetInDefense));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetActiveViewModel(Transform container, int model)
|
||||
{
|
||||
foreach (Transform item in container)
|
||||
{
|
||||
if (!item.gameObject.activeSelf) continue;
|
||||
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (model != -1)
|
||||
{
|
||||
container.GetChild(model).gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Attack()
|
||||
{
|
||||
IsAttackCoroutine = true;
|
||||
StartCoroutine(nameof(AttackAnimation));
|
||||
}
|
||||
|
||||
protected virtual IEnumerator AttackAnimation()
|
||||
{
|
||||
closeWeapon.SetIsAttacked(false);
|
||||
closeWeapon.SetWeaponStat(AiStat.Atk, AiStat.ShieldPenetrationRate, AiStat.AttackerType == EAttackerType.OFFENSE);
|
||||
aiAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(AiStat.AtkCooldown);
|
||||
IsAttackCoroutine = false;
|
||||
}
|
||||
|
||||
protected virtual bool CanAttack()
|
||||
{
|
||||
switch (AiStat.AttackerType)
|
||||
{
|
||||
case EAttackerType.NONE:
|
||||
print("AiStat.AttackerType == NONE Error");
|
||||
return false;
|
||||
case EAttackerType.OFFENSE:
|
||||
if (!TargetTransform || !islandInfo.TargetAllList.Contains(TargetTransform)) return false;
|
||||
break;
|
||||
case EAttackerType.DEFENSE:
|
||||
if (!TargetTransform) return false;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var targetInAttackRange = Vector3.Distance(transform.position, TargetTransform.position) <=
|
||||
AiStat.AtkRange;
|
||||
|
||||
return targetInAttackRange;
|
||||
}
|
||||
|
||||
private void FindMaterial()
|
||||
{
|
||||
var skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
var meshRenderers = GetComponentsInChildren<MeshRenderer>();
|
||||
|
||||
foreach (var skin in skinnedMeshRenderers)
|
||||
{
|
||||
if (!skin.gameObject.activeSelf) continue;
|
||||
|
||||
skinMaterialList.Add(skin.material);
|
||||
}
|
||||
|
||||
foreach (var skin in meshRenderers)
|
||||
{
|
||||
if (!skin.gameObject.activeSelf) continue;
|
||||
|
||||
skinMaterialList.Add(skin.material);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetOutlineColor(Color color)
|
||||
{
|
||||
foreach (var skin in skinMaterialList)
|
||||
{
|
||||
skin.SetColor(OutlineColorHash, color);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveIslandInfo()
|
||||
{
|
||||
if (islandInfo == null) return;
|
||||
|
||||
islandInfo.RemoveListElement(islandInfo.EnemyList, transform);
|
||||
}
|
||||
|
||||
private void SetAgentIsStopped(bool value)
|
||||
{
|
||||
if (navMeshAgent.enabled)
|
||||
{
|
||||
navMeshAgent.isStopped = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SetLayer()
|
||||
{
|
||||
// switch (AiStat.AiType)
|
||||
// {
|
||||
// case EAiType.NONE:
|
||||
// print("AiStat.AiType == NONE Error");
|
||||
// break;
|
||||
// case EAiType.PLAYER:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Player");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Player";
|
||||
// TargetLayer = LayerMask.GetMask("Enemy");
|
||||
// break;
|
||||
// case EAiType.PIRATE:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Pirate");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Pirate";
|
||||
// TargetLayer = LayerMask.GetMask("Enemy");
|
||||
// break;
|
||||
// case EAiType.ENEMY:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Enemy");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Enemy";
|
||||
// TargetLayer = LayerMask.GetMask("Player") | LayerMask.GetMask("Pirate");
|
||||
// break;
|
||||
// default:
|
||||
// throw new ArgumentOutOfRangeException();
|
||||
// }
|
||||
//
|
||||
// if (AiStat.AttackerType == EAttackerType.OFFENSE)
|
||||
// {
|
||||
// TargetLayer |= LayerMask.GetMask("Props");
|
||||
// }
|
||||
}
|
||||
|
||||
public IslandInfo GetIslandInfo() => islandInfo;
|
||||
public void SetIslandInfo(IslandInfo info) => islandInfo = info;
|
||||
public void SetAttackerType(EAttackerType type) => AiStat.AttackerType = type;
|
||||
public void SetOffenseType(EOffenseType type) => AiStat.OffenseType = type;
|
||||
public void SetDefenseType(EDefenseType type) => AiStat.DefenseType = type;
|
||||
public void SetCloseWeaponCanAttack(int boolValue) => closeWeapon.SetCanAttack(boolValue == 1);
|
||||
public void ResetHighlight() => SetOutlineColor(defaultSkinColor);
|
||||
public void MouseEnterHighlight() => SetOutlineColor(mouseEnterHighlightSkinColor);
|
||||
public void SelectedHighlight() => SetOutlineColor(selectedSkinColor);
|
||||
private void DestroyObject() => Destroy(gameObject);
|
||||
public void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
public NavMeshAgent GetNavMeshAgent() => navMeshAgent;
|
||||
public Animator GetAnimator() => aiAnimator;
|
||||
public void SetMoveSpeed(float value) => navMeshAgent.speed = value;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 349d312f1c182334c94df84081148204
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -3,6 +3,37 @@ using UnityEngine;
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public enum EAiType
|
||||
{
|
||||
NONE = -1,
|
||||
PLAYER,
|
||||
PIRATE,
|
||||
ENEMY
|
||||
}
|
||||
|
||||
public enum EAttackerType
|
||||
{
|
||||
NONE = -1,
|
||||
OFFENSE,
|
||||
DEFENSE
|
||||
}
|
||||
|
||||
public enum EOffenseType
|
||||
{
|
||||
NONE = -1,
|
||||
NORMAL,
|
||||
ONLY_HOUSE
|
||||
}
|
||||
|
||||
public enum EDefenseType
|
||||
{
|
||||
NONE = -1,
|
||||
STRIKER,
|
||||
MIDFIELDER,
|
||||
DEFENDER,
|
||||
KEEPER
|
||||
}
|
||||
|
||||
public class BaseAi : MonoBehaviour
|
||||
{
|
||||
|
||||
|
@ -89,11 +89,11 @@ namespace BlueWaterProject
|
||||
|
||||
protected void FlagLookAtCamera()
|
||||
{
|
||||
if (Camera.main != null)
|
||||
if (GameManager.Inst.CameraController.MainCam != null)
|
||||
{
|
||||
var source = new ConstraintSource
|
||||
{
|
||||
sourceTransform = Camera.main.transform,
|
||||
sourceTransform = GameManager.Inst.CameraController.MainCam.transform,
|
||||
weight = 1f
|
||||
};
|
||||
lookAtConstraint.AddSource(source);
|
||||
|
@ -39,7 +39,8 @@ namespace BlueWaterProject
|
||||
if (EnemyStat.DefenseType == EDefenseType.DEFENDER)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(defensePos, EnemyStat.DefenseRange);
|
||||
var startPos = Application.isPlaying ? defensePos : transform.position;
|
||||
Gizmos.DrawWireSphere(startPos, EnemyStat.DefenseRange);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
|
@ -51,7 +51,6 @@ namespace BlueWaterProject
|
||||
protected override void OnAwake()
|
||||
{
|
||||
GroundLayer = LayerMask.GetMask("Ground");
|
||||
//InitPlayerUnitList();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
@ -60,7 +59,6 @@ namespace BlueWaterProject
|
||||
MaxGroundDistance = 4f;
|
||||
UnitSpacing = 2.5f;
|
||||
InitCharacterPrefabList();
|
||||
//InitPlayerUnitList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -77,6 +75,8 @@ namespace BlueWaterProject
|
||||
[Button("프리팹 초기화")]
|
||||
private void InitCharacterPrefabList()
|
||||
{
|
||||
GroundLayer = LayerMask.GetMask("Ground");
|
||||
|
||||
PiratePrefab = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs/Character/Unit", "PirateUnit", ".prefab");
|
||||
BaseHumanPrefab = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs/Character", "BaseHuman", ".prefab");
|
||||
ArrowPrefab = Utils.LoadFromFolder<GameObject>("Assets/05.Prefabs", "Arrow_01", ".prefab");
|
||||
@ -93,25 +93,6 @@ namespace BlueWaterProject
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// /// <summary>
|
||||
// /// 플레이어가 가진 유닛 리스트 초기화
|
||||
// /// </summary>
|
||||
// [GUIColor(0, 1, 0)]
|
||||
// [Button("플레이어 유닛 가져오기")]
|
||||
// private void InitPlayerUnitList()
|
||||
// {
|
||||
// SetPlayerUnits();
|
||||
//
|
||||
// pirateUnitList = new List<PirateUnit>(PIRATE_UNIT_CAPACITY);
|
||||
//
|
||||
// foreach (Transform item in pirateUnits)
|
||||
// {
|
||||
// if (!item.gameObject.activeSelf) continue;
|
||||
//
|
||||
// pirateUnitList.Add(item.GetComponent<PirateUnit>());
|
||||
// }
|
||||
// }
|
||||
|
||||
private void SetPlayerUnits()
|
||||
{
|
||||
@ -459,21 +440,6 @@ namespace BlueWaterProject
|
||||
}
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// pirateUnitList 내의 속성
|
||||
// /// </summary>
|
||||
// public void RemovePlayerUnitListElement(PirateUnit pirateUnit)
|
||||
// {
|
||||
// if (pirateUnitList.Contains(pirateUnit))
|
||||
// {
|
||||
// pirateUnitList.Remove(pirateUnit);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Debug.Log("제거하려는 속성이 리스트 내에 존재하지 않습니다.");
|
||||
// }
|
||||
// }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ namespace BlueWaterProject
|
||||
[SerializeField] private LayerMask groundLayer;
|
||||
|
||||
private PirateUnit previousUnitController;
|
||||
private Camera mainCamera;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -39,7 +38,6 @@ namespace BlueWaterProject
|
||||
unitLayer = LayerMask.GetMask("Pirate");
|
||||
groundLayer = LayerMask.GetMask("Ground");
|
||||
|
||||
mainCamera = Camera.main;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -50,7 +48,7 @@ namespace BlueWaterProject
|
||||
{
|
||||
if (!context.performed || !IsSelectable) return;
|
||||
|
||||
var ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
var ray = GameManager.Inst.CameraController.MainCam.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
|
||||
// 부대를 클릭 했을 때,
|
||||
if (Physics.Raycast(ray, out var hit, Mathf.Infinity, unitLayer, QueryTriggerInteraction.Collide))
|
||||
@ -117,7 +115,7 @@ namespace BlueWaterProject
|
||||
{
|
||||
if (!context.performed || !IsSelectable || SelectedPirateUnit == null) return;
|
||||
|
||||
var ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
var ray = GameManager.Inst.CameraController.MainCam.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
|
||||
if (Physics.Raycast(ray, out var hit, Mathf.Infinity, groundLayer, QueryTriggerInteraction.Collide))
|
||||
{
|
||||
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27a2118a3de80f8409a13741224fd29f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,284 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class Archer : AiController
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[Header("화살 오브젝트 관리")]
|
||||
[Tooltip("화살 오브젝트 풀링할 최대 갯수")]
|
||||
[SerializeField] private int arrowMaxSize = 100;
|
||||
|
||||
[Tooltip("화살 발사 후 오브젝트 저장될 위치")]
|
||||
[SerializeField] private Transform arrowsPoolLocation;
|
||||
|
||||
[SerializeField] private LayerMask archerLayer;
|
||||
|
||||
private IEnumerator shootArrowCoroutine;
|
||||
|
||||
private IObjectPool<Arrow> arrowPool;
|
||||
|
||||
[SerializeField] private Vector3 rayOffset = new(0f, 2f, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Built-in Function
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!IsDrawGizmosInFieldOfView) return;
|
||||
|
||||
var myPos = transform.position;
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(myPos, AiStat.ViewRange);
|
||||
|
||||
if (!CanAttack()) return;
|
||||
|
||||
var targetPos = TargetTransform.position;
|
||||
var direction = ((targetPos + rayOffset) - (myPos + rayOffset)).normalized;
|
||||
|
||||
Debug.DrawRay(myPos + rayOffset, direction * AiStat.AtkRange, Color.red);
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
var animatorControllerList = UnitManager.Inst.AIAnimatorControllerList;
|
||||
if (animatorControllerList == null)
|
||||
{
|
||||
Debug.LogError("Animator Controller List is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
var archerController = animatorControllerList.Find(obj => obj.name == "Archer");
|
||||
if (archerController == null)
|
||||
{
|
||||
Debug.LogError("No AnimatorController named 'Archer' was found in the list.");
|
||||
return;
|
||||
}
|
||||
|
||||
aiAnimator.runtimeAnimatorController = archerController;
|
||||
arrowsPoolLocation = GameObject.Find("ObjectPoolManager/Arrows").transform;
|
||||
arrowPool = new ObjectPool<Arrow>(CreateArrow, OnGetArrow, OnReleaseArrow, OnDestroyArrow, maxSize:arrowMaxSize);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom function
|
||||
|
||||
protected override void SetLayer()
|
||||
{
|
||||
// switch (AiStat.AiType)
|
||||
// {
|
||||
// case EAiType.NONE:
|
||||
// break;
|
||||
// case EAiType.PLAYER:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Player");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Player";
|
||||
// TargetLayer = LayerMask.GetMask("Enemy");
|
||||
// archerLayer = LayerMask.GetMask("Ground") | LayerMask.GetMask("Water") |
|
||||
// LayerMask.GetMask("Enemy");
|
||||
// break;
|
||||
// case EAiType.PIRATE:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Pirate");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Pirate";
|
||||
// TargetLayer = LayerMask.GetMask("Enemy");
|
||||
// archerLayer = LayerMask.GetMask("Ground") | LayerMask.GetMask("Water") |
|
||||
// LayerMask.GetMask("Enemy");
|
||||
// break;
|
||||
// case EAiType.ENEMY:
|
||||
// gameObject.layer = LayerMask.NameToLayer("Enemy");
|
||||
// hitBoxCollider.gameObject.layer = LayerMask.NameToLayer("HitBox");
|
||||
// hitBoxCollider.gameObject.tag = "Enemy";
|
||||
// TargetLayer = LayerMask.GetMask("Player") | LayerMask.GetMask("Pirate");
|
||||
// archerLayer = LayerMask.GetMask("Ground") | LayerMask.GetMask("Water") |
|
||||
// LayerMask.GetMask("Player") | LayerMask.GetMask("Pirate");
|
||||
// break;
|
||||
// default:
|
||||
// throw new ArgumentOutOfRangeException();
|
||||
// }
|
||||
|
||||
if (AiStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
TargetLayer |= LayerMask.GetMask("Props");
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateLookAtTarget()
|
||||
{
|
||||
if (TargetTransform)
|
||||
{
|
||||
navMeshAgent.updateRotation = false;
|
||||
|
||||
var targetPos = TargetTransform.position;
|
||||
targetPos.y = transform.position.y;
|
||||
transform.LookAt(targetPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
navMeshAgent.updateRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetNearestTargetInOffense<T>(List<T> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var nearestTarget = targetList.OrderBy(t =>
|
||||
{
|
||||
var myPos = transform.position;
|
||||
var targetTransform = (Transform)(object)t;
|
||||
|
||||
if (!targetTransform)
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
var targetCollider = targetTransform.GetComponent<Collider>();
|
||||
|
||||
if (!targetCollider || !IsRaycastHitTarget(targetTransform))
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
var closestPoint = targetCollider.ClosestPoint(myPos);
|
||||
return Vector3.Distance(myPos, closestPoint);
|
||||
})
|
||||
.FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
TargetTransform = (Transform)(object)nearestTarget;
|
||||
|
||||
if (!TargetTransform || !navMeshAgent.enabled) return;
|
||||
Utils.SetCloseDestination(navMeshAgent, TargetTransform.position, AiStat.AtkRange - 0.5f, AiStat.AtkRange);
|
||||
}
|
||||
|
||||
public override void SetNearestTargetInDefense(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(ColliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, ColliderWithinRange,
|
||||
TargetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
TargetTransform = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, ColliderWithinRange[i].transform.position);
|
||||
|
||||
if (!IsRaycastHitTarget(ColliderWithinRange[i].transform) || distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = ColliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
TargetTransform = nearestTargetTransform;
|
||||
}
|
||||
|
||||
private bool IsRaycastHitTarget(Transform targetTransform)
|
||||
{
|
||||
var myPos = transform.position;
|
||||
var direction = ((targetTransform.position + rayOffset) - (myPos + rayOffset)).normalized;
|
||||
var raycastHitTarget = Physics.Raycast(myPos + rayOffset, direction, out var hit, AiStat.AtkRange, archerLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
return raycastHitTarget && targetTransform == hit.transform;
|
||||
}
|
||||
|
||||
// protected override bool CanAttack()
|
||||
// {
|
||||
// if (!TargetTransform) return false;
|
||||
//
|
||||
// var myPos = transform.position;
|
||||
// var targetPos = TargetTransform.position;
|
||||
// var direction = ((targetPos + rayOffset) - (myPos + rayOffset)).normalized;
|
||||
//
|
||||
// var targetInAttackRange = Vector3.Distance(myPos, targetPos) <= AiStat.AtkRange;
|
||||
// var raycastHitTarget = Physics.Raycast(myPos + rayOffset, direction, out var hit, AiStat.AtkRange, archerLayer, QueryTriggerInteraction.Collide);
|
||||
//
|
||||
// return targetInAttackRange && raycastHitTarget;
|
||||
// }
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!CanAttack())
|
||||
{
|
||||
isAttacking = false;
|
||||
yield return FindTargetWaitTime;
|
||||
continue;
|
||||
}
|
||||
|
||||
isAttacking = true;
|
||||
aiAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(AiStat.AtkCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnShootArrow()
|
||||
{
|
||||
if (!TargetTransform) return;
|
||||
|
||||
var arrow = arrowPool.Get();
|
||||
var isOffense = AiStat.AttackerType == EAttackerType.OFFENSE;
|
||||
|
||||
// arrow.SetShootingArrow(leftWeaponContainer.position, transform.position,
|
||||
// TargetTransform.position + rayOffset, AiStat, AiStat.AiType, AiStat.Inaccuracy, isOffense);
|
||||
arrow.ShootArrowCoroutine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnStoppedMove(int boolValue)
|
||||
{
|
||||
if (!navMeshAgent.enabled) return;
|
||||
|
||||
navMeshAgent.isStopped = boolValue == 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ObjectPool Function
|
||||
|
||||
private Arrow CreateArrow()
|
||||
{
|
||||
var arrow = Instantiate(UnitManager.Inst.ArrowPrefab, leftWeaponContainer.position, Quaternion.identity, arrowsPoolLocation).GetComponent<Arrow>();
|
||||
arrow.SetManagedPool(arrowPool);
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private void OnGetArrow(Arrow arrow) => arrow.gameObject.SetActive(true);
|
||||
private void OnReleaseArrow(Arrow arrow) => arrow.ReleaseArrowSetting();
|
||||
private void OnDestroyArrow(Arrow arrow) => Destroy(arrow.gameObject);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b934a5073db193343a89fc4597056b68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class Axeman : AiController
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
aiAnimator.runtimeAnimatorController = UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == "Axeman");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62993cbcb58ab6845897f946bdcb90c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class SpearKnight : AiController
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
aiAnimator.runtimeAnimatorController = UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == "SpearKnight");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8aa9e82d64fb86549a75d2c51f97dd21
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class Spearman : AiController
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
aiAnimator.runtimeAnimatorController = UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == "Spearman");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d17ac59ab4fe31846b058c6e1ca1cbb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class SwordKnight : AiController
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
aiAnimator.runtimeAnimatorController = UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == "SwordKnight");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4363b722ccf9a2b49b7506fd355c6a4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class Swordman : AiController
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
aiAnimator.runtimeAnimatorController = UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == "Swordman");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7bb4d34880889448a03ef7d1b0ebee9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a55ee4efaad27d948ba5f03fc6d7bc80
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed9b95dc6ed6d0647ad7f1a8f305385d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ff1f29eab234cf4490d9bb383892c44
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5789d13135b86645a366dac6583d1cd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3643c0d76ec153646b1203880bfb64ed
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d7c4217783978e4abe6496ac71eee94
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 697b6e7dea1fde146b7e3e5cf3ed9e9f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 078b8f13a17171b49892ad10426d5af0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9406a33814af9c47b352e77f079d798
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9aacf6f3043624194bb6f6fe9a580786
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4227764308e84f89a765fbf315e2945
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41e59f562b69648719f2424c438758f3
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b044a2387a61dac41bdf204adffdce9d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd287c84e887ea24a8679e67aac7c074
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f3f53ee059b45a4d9a5b9fc75e8aea9
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f211254f5bfad224ba88868f2c75432c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4368c9be31b3c174dbfd80f2caf98889
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 617b3f1032a08c14ebfedfa340767cdf
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f597f19f656ba56eae4f6a3a7cc528f4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48e08dc33330d11e9d4a1b246c52e4f6
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed09910c0094cb27be8f3ca264680da3
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc355dd4cf1e6173beaeb22c2858cbe1
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -127,7 +127,6 @@ PlayerSettings:
|
||||
switchAllowGpuScratchShrinking: 0
|
||||
switchNVNMaxPublicTextureIDCount: 0
|
||||
switchNVNMaxPublicSamplerIDCount: 0
|
||||
switchMaxWorkerMultiple: 8
|
||||
switchNVNGraphicsFirmwareMemory: 32
|
||||
vulkanNumSwapchainBuffers: 3
|
||||
vulkanEnableSetSRGBWrite: 0
|
||||
@ -147,7 +146,6 @@ PlayerSettings:
|
||||
isWsaHolographicRemotingEnabled: 0
|
||||
enableFrameTimingStats: 0
|
||||
enableOpenGLProfilerGPURecorders: 1
|
||||
allowHDRDisplaySupport: 0
|
||||
useHDRDisplay: 0
|
||||
hdrBitDepth: 0
|
||||
m_ColorGamuts: 00000000
|
||||
@ -690,6 +688,7 @@ PlayerSettings:
|
||||
switchSocketBufferEfficiency: 4
|
||||
switchSocketInitializeEnabled: 1
|
||||
switchNetworkInterfaceManagerInitializeEnabled: 1
|
||||
switchPlayerConnectionEnabled: 1
|
||||
switchUseNewStyleFilepaths: 0
|
||||
switchUseLegacyFmodPriorities: 0
|
||||
switchUseMicroSleepForYield: 1
|
||||
|
Loading…
Reference in New Issue
Block a user