Как можно оптимизировать этот код для ИИ / робота?
Я сделал ИИ / робота и его дальность / радиус обзора с помощью триггера, его передвижение я сделал с помощью NavMeshAgent и NavMeshObctacle (вроде так называется), можно ли как то проверить достиг ли _agent цели или нет, имею ввиду что если _agent достиг например: 100, 1, 100 и только тогда заново задавать новую цель, только вместо 100, 1, 100 будет игрок? Я уверен что есть ещё какие то способы оптимизировать код, спасибо всем!
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using Random = UnityEngine.Random;
public class FindPlayer : MonoBehaviour
{
// private
private int _enemyStatus = 3;
private int _change;
private Animator _animator;
// public static
public static float enemyHealth = 100;
[Header("Враг")]
[SerializeField] private Material _material;
[SerializeField] private float _enemyDamage = 20;
[Header("Игрок")]
[SerializeField] private GameObject _player;
[Header("Цель")]
[SerializeField] private NavMeshAgent _agent;
private void Start()
{
_player = GameObject.FindGameObjectWithTag("Player");
_animator = GetComponent<Animator>();
_material = gameObject.GetComponent<MeshRenderer>().material;
_agent = GetComponent<NavMeshAgent>();
}
private void OnTriggerEnter(Collider _collider)
{
switch (_collider.gameObject.tag)
{
case "Player":
{
if (_agent.isActiveAndEnabled)
{
_change = Random.Range(1, 3);
}
break;
}
}
}
private void OnTriggerStay(Collider _collider)
{
switch (_collider.gameObject.tag)
{
case "Player":
{
if (_agent.isActiveAndEnabled)
{
if (_enemyStatus == 3)
{
if (_change == 1)
{
print(_change);
_material.color = Color.green;
_animator.SetBool("Look", false);
transform.LookAt(_player.transform);
_agent.SetDestination(Vector3.back);
_enemyStatus = 1;
}
else
{
print(_change);
_material.color = Color.red;
_animator.SetBool("Look", true);
transform.LookAt(_player.transform);
_agent.SetDestination(_player.transform.position);
_enemyStatus = 2;
}
}
else
{
switch (_enemyStatus)
{
case 1:
{
_material.color = Color.red;
_animator.SetBool("Look", true);
transform.LookAt(_player.transform);
_agent.SetDestination(_player.transform.position);
break;
}
case 2:
{
_animator.SetBool("Look", false);
_material.color = Color.green;
transform.LookAt(_player.transform);
_agent.SetDestination(Vector3.back);
break;
}
}
}
}
break;
}
}
}
private IEnumerator OnTriggerExit(Collider _collider)
{
if (_agent.isActiveAndEnabled)
{
_animator.SetBool("Look", false);
_material.color = Color.white;
_agent.SetDestination(transform.position);
yield return new WaitForSeconds(5);
var whatPosition = Random.Range(1, 3);
switch (whatPosition)
{
case 1:
{
var randomRange = Random.Range(-80, 81);
var agentNewPosition = new Vector3(transform.position.x + randomRange, transform.position.y, transform.position.z);
_agent.SetDestination(agentNewPosition);
break;
}
case 2:
{
var randomRange = Random.Range(-80, 81);
var agentNewPosition = new Vector3(transform.position.x, transform.position.y, transform.position.z + randomRange);
_agent.SetDestination(agentNewPosition);
break;
}
}
}
}
private void OnCollisionEnter(Collision _collision)
{
switch (_collision.gameObject.tag)
{
case "Player":
{
if (_enemyStatus == 1)
{
GetTarget.playerHealth -= _enemyDamage;
}
break;
}
}
}
}
Ответы (1 шт):
п.с. пиал комменты идя по строкам кода
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using Random = UnityEngine.Random;
// судя по имени FindPlayer, класс занимается нахождением игрок...
// а почему игрока нужно искать? может просто не терять его? потом и искать не придется
public class FindPlayer : MonoBehaviour
{
// почему Status цифрами? нужно вангавать что каждая цифра значит?
// для кого enum пидумали? 3 это лучше чем 2? теплее чем 9? веселее чем -1?
// что делает Status врагов в поисковике игрока?
private int _enemyStatus = 3;
// change который int... понять и простить...
private int _change;
// Animator?... в FindPlayer?... боюсь к методам переходить
private Animator _animator;
// public static давай до свидания...
// жизнь врага... какого-то там врага... в классе поиске игрока? бросай наркотики!
public static float enemyHealth = 100;
[Header("Враг")]
// Material ?... в FindPlayer?...
[SerializeField] private Material _material;
// урон врага... в классе поиске игрока? завязывай с тяжелыми наркотиками!
// а почему жизни публично-статичные а у урон приватный? а в прочем какая разница... лол)
[SerializeField] private float _enemyDamage = 20;
[Header("Игрок")]
// тип GameObject? В 99.99% нужен либо Transform, либо скрипт, а GameObject не нужен
[SerializeField] private GameObject _player;
[Header("Цель")]
// ты в Header написал "Цель", что не плохой нейминг... но поле почему то,
// в итоге названа в честь его типа, а не _target... что случилось по дороге?
[SerializeField] private NavMeshAgent _agent;
private void Start()
{
// начинаю подозревать что скрипт весит на Enemy, что не капли не оправдывает написанное выше
// GameObject.Find это боковые колеса для детских велосипедов,
// когда нет ни то что архитектуры, даже клятого всеми синглтона
_player = GameObject.FindGameObjectWithTag("Player");
_animator = GetComponent<Animator>();
_material = gameObject.GetComponent<MeshRenderer>().material;
_agent = GetComponent<NavMeshAgent>();
}
private void OnTriggerEnter(Collider _collider)
{
// switch с одним case? во имя... науки видимо
switch (_collider.gameObject.tag)
case "Player":
if (_agent.isActiveAndEnabled)
// и сразу стало ясно для чего нужен _change... не, показалось
_change = Random.Range(1, 3);
break;
}
private void OnTriggerStay(Collider _collider)
{
switch (_collider.gameObject.tag)
{
case "Player":
{
if (_agent.isActiveAndEnabled)
{
if (_enemyStatus == 3) // если стейт равен чему-то там
{
if (_change == 1) // и что-то это равно чему-то зачем то то...
{
// 7ой уровень вложенности операционных скобок... ДА... МЫ ЭТО СДЕЛАЛИ
// уде на 3-4 можно было-бы записать все отдельным методом с именем объясняющим что в нем происходит
_material.color = Color.green;
_animator.SetBool("Look", false);
transform.LookAt(_player.transform);
_agent.SetDestination(Vector3.back);
_enemyStatus = 1;
// класс поиска игрока меняет матеилы, управляет аниматором, вращает трансформ,
// прокладывает пути, задает статусы, заказывает еду, выносит мусор, скачивает сериалы,
// но точно не ищет игрока
}
else
{
дублирование кода
...
}
}
else
{
switch (_enemyStatus)
{
case 1:
{
дублирование кода
...
break;
}
case 2:
{
дублирование кода
...
break;
}
}
}
}
break;
}
}
}
¦
¦
¦
ヾ○シ BREAK
ヘ/ FAAAaaa... ll
ノ
// почему IEnumerator? боюсь спрашивать
private IEnumerator OnTriggerExit(Collider _collider)
{
дублированием кода
ответ на вопрос который я боялся спросить и не зря
очередное дублированием не понятного кода, который делает что-то там точно не связанное с поиском игрока
...
}
...
}
Как оптимизировать? Ctrl+A, Backspace!
Никаких классов типа Player или Enemy не пишут в силу того что они не отличаются. Есть некая UnitModel где куча сущьностей типа статы, пак плавающих показателей вроде хп/мп/стамина, класс передвижения (могут быть разные), атаки, обработки урона, обработчик скина (единственный кто работает с Animator!), ссылка на TargetUnit тоже может быть и т.д. и во всём этом персонаж игрока ничем не отличается от врагов которых он бьет.
Разница лишь в том кто конкретным юнитам дает команды, игрок через управления или поведенчиский скрипт. Кто выбирает цели, игрок кликом по врагу или поисковик по списку всех юнитов ищущий всех у кого не такая-же фракция, что может использоваться и персонажем игрока в том числе.
Вижу что начал с правильного форматирования по стандарту, теперь учись писать осмысленный код, где у классов всего одна ответственность с говорящим названием.