void LockTarget()
{
Collider[] zombies = Physics.OverlapSphere(turret.transform.position, maxDistance, _targetMask);
Transform target = null; //должна быть глобальная или передавать через return
if (!(zombies.Length > 0)) return;
float mindist = maxDistance;
foreach (Collider c in zombies)
{
float currentDist = Vector3.Distance(turret.transform.position, c.gameObject.transform.position);
if ((currentDist<mindist))
{
mindist = currentDist;
target = c.gameObject.transform;
}
}
}
targets.AddRange(manager.turrets);
mainBase = manager.mainBase;
player = manager.btr.transform;
if (targets.Count != 0) target = targets[Random.Range(0, targets.Count)];
else target = null;
btr = player.GetComponent<BTR>();
_agent.SetDestination(_target.position);
private void Update()
{
transform.rotation *= Quaternion.Euler(transform.rotation.x + 150f*Time.deltaTime, 0, 0);
}
}
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class BaseAi : MonoBehaviour
{
float _currentHeal;
NavMeshAgent _agent;
Coroutine _MoveTo;
Coroutine _TargetSearch;
float _speed;
[SerializeField] float _walkSpeed=5f;
Transform _target;
LayerMask _targetMask;
bool _IsAlive;
Animator _animator;
private void Start()
{
_IsAlive = true;
_agent = GetComponent<NavMeshAgent>();
_animator = GetComponent<Animator>();
_TargetSearch = StartCoroutine(TargetSearch());
}
IEnumerator TargetSearch() //там свой способ для поиска используй, это просто для примера
{
while (true)
{
Collider[] colliders = Physics.OverlapSphere(transform.position, 25f, _targetMask);
if (colliders.Length != 0)
{
_target = colliders[Random.Range(0, colliders.Length)].transform;
}
yield return new WaitForSeconds(0.5f);
}
}
void SearchOff()
{
StopCoroutine(_TargetSearch);
_TargetSearch= null;
}
void BrainOff()
{
StopCoroutine(_MoveTo);
_MoveTo = null;
}
private void Update()
{
if (_IsAlive)
{
if (_target == null && _TargetSearch == null) _TargetSearch = StartCoroutine(TargetSearch());
if (_target != null && _TargetSearch != null) SearchOff();
if (_target != null && _MoveTo == null) _MoveTo = StartCoroutine(WalkTo());
if (_target == null && _MoveTo != null) BrainOff();
_animator.SetFloat("MoveSpeed", _agent.speed); // переключать анимацию мы будем через скорость самого зомби
}
}
IEnumerator WalkTo()
{
while (true)
{
_agent.SetDestination(_target.position);
if (_agent.remainingDistance! > _agent.stoppingDistance) TryAttack();
if(_agent.remainingDistance>15f) yield return new WaitForSeconds(0.8f); //SetDestination ресурсоемкая команда
else yield return new WaitForSeconds(0.2f); //делаем бота более распоропнее, чем ближе он подходит 5 раз в секунду вероятно тож много
}
}
void TryAttack()
{
_agent.speed = 0f;
_animator.SetTrigger("Attack");
Invoke("RetrigetAttack", 0.5f); //отжатие триггера на атаку, лучше сделать через анимацию, а так надо поставить примерное время анимации удара
Collider[] colliders = Physics.OverlapSphere(transform.position+transform.up+transform.forward*0.5f, 1.5f, _targetMask);
foreach (Collider collider in colliders)
{
switch (collider.tag) // можно сделать проще повесить на все элементы скрипт Heals и брать только его
{
case "Player":
if (collider.TryGetComponent(out Mover btr)) //у меня тут свои скрипты будут
{
btr.TakeDamage(Random.Range(25, 35));
}
break;
case "Turret":
if (collider.TryGetComponent(out Turret turret))
{
turret.TakeDamage(Random.Range(20, 30));
}
break;
case "Base":
if (collider.TryGetComponent(out Base Mybase))
{
Mybase.TakeDamage(Random.Range(70, 90));
}
}
}
}
public void RetrigetAttack() //триггер его можну отдажть через анимацию или коррутину
{
_animator.ResetTrigger("Attack");
_agent.speed = _walkSpeed;
}
public void TakeDamage(float damage)
{
_currentHeal -= damage;
if (_currentHeal! > 0) Die();
}
void Die()
{
_IsAlive = false;
if(_TargetSearch!=null) SearchOff();
if(_MoveTo!=null)BrainOff();
_agent.enabled = false;
_animator.SetTrigger("Die");
}
}
Думаю это надо использовать как то по другому.
как минимум
ты если заходишь в метод сразу добавляешь, там могут быть повторные?
листы не надо постоянно создавать 1 раз создай в глобальных и просто очищай его.
Далее
как я понял ты объект не уничтожаешь, тогда вопрос есть вариант что он станет опять таргетом? вероятно в цикле выбора цели стоит сделать проверку на isAlive