Новичок и с кодом не работал.Хотелось бы просто услышать мнение, советы и т.д. Скорее всего до конца это не работает как надо, но мы стараемся, честно)
Это скрипт ИИ. Намешано дофига всего). Задача бежать в сторону Обелиска, остановиться и атаковать, если в поле зрения попадается игрок, то бежит к нему и атакует. Первый раз пробовал ссылаться и на переменные и методы из других скриптов и работал с параметрами).
public class EnemyAIwithFOV : MonoBehaviour
{
[Header("Переменные для настройки баланса")]
public attackEvent attackEvent;
[Space]
[Header("Абсолютное обноружение")]
[Range(1, 3)] public int minDistance = 1;
[Header("Настройка дистанции атаки")]
[Range(0, 20)] public float attackRadius = 10;
[Header("Настройка дистанции обзора")]
[Range(1, 40)] public float sightRadius = 16;
[Header("Настройка угла обзора")]
[Range(0, 360)] public int fieldOfViewAngle = 60; // угол обзора
private int absoluteSign = 2;
[Header("Цели для выбора приоритета")]
public Transform primaryTarget;
public Transform secondaryTarget;
[Header("Атрибуты")]
public NavMeshAgent nav;
[Header("Цели")]
[Header("Текущая цель")]
[SerializeField] private Transform currentTarget;
[Header("Лист персонажей находящихся в радиусе")]
[SerializeField] private List<Transform> targetsInRange = new List<Transform>();
[Header("Лист персонажей находящихся в видимости")]
[SerializeField] private List<Transform> targetsInSight = new List<Transform>();
public Animator EnemyAnim;
public bool attack;
public bool attackPlayer;
public bool attackStella;
public void SearchTargetPosition()
{
Collider[] hitColliders = Physics.OverlapSphere(transform.position, attackRadius);
foreach (Collider hitCollider in hitColliders)
{
if (hitCollider.CompareTag("Enemy") || hitCollider.CompareTag("Player"))
{
targetsInRange.Add(hitCollider.transform);
}
}
}
private void Start()
{
EnemyAnim = GetComponent<Animator>();
nav = GetComponent<NavMeshAgent>();
SearchTargetPosition();
attack = false;
attackPlayer = false;
attackStella = false;
}
public void Attack()
{
StartCoroutine("AttackWithTime");
EnemyAnim.SetTrigger("Attack");
}
public IEnumerator AttackWithTime()
{
yield return new WaitForSeconds(0.8f);
int attackTarget = attackEvent.targetToDamage;
attackEvent.AttackEnemy(attackTarget);
yield return new WaitForSeconds(1.6f);
}
private void Update()
{
absoluteSign = minDistance;
Collider[] hitColliders = Physics.OverlapSphere(transform.position, attackRadius);
foreach (Collider hitCollider in hitColliders)
{
if (hitCollider.CompareTag("Enemy") || hitCollider.CompareTag("Player"))
{
Transform target = hitCollider.transform;
Vector3 targetDirection = (target.position - transform.position).normalized;
if (currentTarget != null && Vector3.Distance(nav.transform.position, currentTarget.position) <= attackRadius)
{
nav.isStopped = true;
EnemyAnim.SetBool("nav.isStoped", nav.isStopped);
}
else
{
nav.isStopped = false;
EnemyAnim.SetBool("nav.isStoped", nav.isStopped);
}
foreach (Collider enemy in hitColliders)
{
if (enemy.CompareTag("Player") && currentTarget == CompareTag("Player"))
{
attack = true;
attackPlayer = true;
Attack();
}
else
{
attack = false;
attackPlayer = false;
attackStella = false;
StartCoroutine("AttackWithTime");
}
if (enemy.CompareTag("Enemy") && currentTarget == CompareTag("Enemy"))
{
attack = true;
attackStella = true;
Attack();
}
else
{
attack = false;
attackPlayer = false;
attackStella = false;
StartCoroutine("AttackWithTime");
}
transform.LookAt(new Vector3(currentTarget.position.x, transform.position.y, currentTarget.position.z));
}
}
}
if (currentTarget == null || !targetsInRange.Contains(currentTarget))
{
currentTarget = GetNewTarget();
}
if (currentTarget != null && Vector3.Distance(transform.position, currentTarget.position) >= minDistance)
{
TransformNavMesh();
}
targetsInSight.Clear();
Collider[] targetsInViewRadius = Physics.OverlapSphere(transform.position, sightRadius);
Collider[] targetInAbsolutRadius = Physics.OverlapSphere(transform.position, absoluteSign);
foreach (Collider targetCollider in targetInAbsolutRadius)
{
if (targetCollider.CompareTag("Player"))
{
targetsInSight.Add(targetCollider.transform);
}
}
foreach (Collider targetCollider in targetsInViewRadius)
{
if (targetCollider.CompareTag("Enemy") || targetCollider.CompareTag("Player"))
{
Transform target = targetCollider.transform;
Vector3 targetDirection = (target.position - transform.position).normalized;
float targetDistance = Vector3.Distance(transform.position, target.position);
if (targetDistance <= sightRadius && Vector3.Angle(transform.forward, targetDirection) < fieldOfViewAngle / 2 || targetDistance <= absoluteSign)
{
RaycastHit hit;
Debug.DrawLine(transform.position, target.position);
if (Physics.Raycast(transform.position, targetDirection, out hit, targetDistance))
{
if (hit.transform == target)
{
targetsInSight.Add(target);
}
}
}
}
}
if (secondaryTarget != null && targetsInSight.Contains(secondaryTarget) && !targetsInSight.Contains(primaryTarget))
{
currentTarget = secondaryTarget;
}
else if (currentTarget == secondaryTarget && !targetsInSight.Contains(secondaryTarget))
{
currentTarget = primaryTarget;
}
if (currentTarget != null && Vector3.Distance(transform.position, currentTarget.position) > sightRadius)
{
currentTarget = null;
}
}
private Transform GetNewTarget()
{
Transform newTarget = null;
if (primaryTarget != null)
{
newTarget = primaryTarget;
}
if (secondaryTarget != null && targetsInSight.Contains(secondaryTarget))
{
newTarget = secondaryTarget;
}
if (newTarget == null && targetsInRange.Count > 0)
{
newTarget = targetsInRange[Random.Range(0, targetsInRange.Count)];
}
return newTarget;
}
public void TransformNavMesh()
{
nav.SetDestination(currentTarget.transform.position);
}
}
public class attackEvent : MonoBehaviour
{
public healthBar healthBar;
public healthStella healthStella;
public float minDamage;
public float maxDamage;
public float curretDamage;
public EnemyAIwithFOV enemyScript;
public bool attackPlayer;
public bool attackStella;
public int targetToDamage;
public void Start()
{
attackPlayer = false;
attackStella = false;
}
public void Update()
{
CheckTargetForDamage();
}
public void CheckTargetForDamage()
{
if (enemyScript.attack == true && enemyScript.attackPlayer == true)
{
attackPlayer = true;
}
else attackPlayer = false;
if (enemyScript.attack == true && enemyScript.attackStella == true)
{
attackStella = true;
}
else attackStella = false;
if (attackPlayer)
{
targetToDamage = 1;
Debug.Log("Враг бьет игрока");
}
if (attackStella)
{
targetToDamage = 2;
Debug.Log("Враг бьет обелиск");
}
if (!attackPlayer && !attackStella)
{
targetToDamage = 0;
Debug.Log("Враг никого не бьет");
}
}
public void Damage(float minDamage, float maxDamage, out float curretDamage)
{
curretDamage = Random.Range(minDamage, maxDamage);
}
public void SetDamage()
{
Damage(minDamage, maxDamage, out curretDamage);
}
public void AttackEnemy(int whoToBeat)
{
SetDamage();
if (whoToBeat == 1)
{
healthBar.GetDamage();
}
if (whoToBeat == 2)
{
healthStella.GetDamage();
}
}
}
В нем он проверяет кого бьет противник и так же присваивает для цели "типо" индекс (возможно это можно было реализовать через массивы, но я пока плохо в них разбираюсь) и генерируется случайный урон
И после из этого скрипта все отправляется в показатели здоровья целей.