Найти ближний объект Unity

481
02 августа 2017, 18:39

Всем привет. У меня вопрос. Я сделал NavMeshAgent в Unity. И через for задал ему несколько целей. Уничтожает один объект, затем другой. Но, как я понял, он определяет не ближний объект, а по возрастанию (по индексу массива). Как сделать так, чтобы персонаж определял ближний объект, затем уничтожил его, а потом переходил к другому ближнему? Один человек посоветовал мне через magnitude, но работает некорректно.

Вот мой код:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Unit : MonoBehaviour {
private NavMeshAgent agent;
private GameObject[] target;
private Animator anim;
private float distance;
public Transform start;
void Start () {
    agent = GetComponent<NavMeshAgent> ();
    anim = GetComponent<Animator> ();
}
public void Attack(int index){
    switch (index) {
    case 0:
        {
            for (int i = 0; i < target.Length; i++) {
                distance = Vector3.Distance (transform.position, agent.steeringTarget);
                Vector3 move = target [i].transform.position;
                transform.LookAt (new Vector3 (target [i].transform.position.x, 0, target [i].transform.position.z));
                agent.SetDestination (move);
                agent.updateRotation = true;
            }
        }
        break;
    case 1:
        {
            anim.Play ("Idle Firing");
            RaycastHit hit;
            if (Physics.Raycast (start.position, start.forward, out hit, 100.0f)) {
                Debug.Log (hit.point);
                if (hit.collider.tag == "Target") {
                    hit.collider.gameObject.GetComponent<Building> ().health -= 1;
                    if (hit.collider.gameObject.GetComponent<Building> ().health <= 0) {
                        Destroy (hit.collider.gameObject);
                        anim.Play ("Idle");
                    }
                }
            } else {
                Debug.LogError ("Error");
            }
        }
        break;
    case 3:
        {
            anim.Play ("Idle");
        }
        break;
    }
}
public void Navigate(){
    for (int i = 0; i < target.Length; i++) {
        distance = Vector3.Distance (transform.position, agent.steeringTarget);
        if (distance > agent.stoppingDistance) {
            anim.Play ("Run_Forwards");
        }
    }
}
void Shoot(){
    Attack (0);
    if (distance > agent.stoppingDistance) {
        Navigate ();
    } else if (distance <= agent.stoppingDistance) {
        Attack (1);
    } else {
        anim.Play ("Idle");
    }
}
void Update () {
    target = GameObject.FindGameObjectsWithTag ("Target");
    Shoot ();
}

}

Буду очень благодарен за правильное решение.

Answer 1

Идеологически можно подойти к решению 2 способами:

  1. Один раз найти ближайшую цель, запомнить ее и двигаться в ее направлении до тех пор, пока она не будет уничтожена
  2. Каждый раз при вызове Update() пересчитывать расстояния и каждый раз искать ближайшую цель. Это может быть точнее, чем первый вариант, потому что будет учитывать скорость перемещения целей (если они движутся, и если они движутся с разной скоростью), однако требует пересчета при каждом вызове Update, в силу чего менее оптимально, чем первый вариант.

Однако, стоит заметить, что вам посоветовали верный способ поиска ближайшей цели (использование magnitude) Вы также можете попробовать Vector3.Distance, но судя по документации, этот метод работает через magnitude. Или можете попробовать Vector3.sqrMagnitude, он схож по идее работы с magnitude, но работает чуть быстрее, за счет того, что не выполняется операция вычисления квадратного корня, однако в силу этого дает менее точный результат. Вы можете почитать обсуждения на тему методов поиска ближайшего объекта здесь и здесь.

Вам может казаться результат вычисления ближайшей цели неверным, если работаете с вычислениями через Vector3, так как он работает с 3 измерениями (А скорее всего речь идет именно о трехмерной игре, так как вы используете навигацию Unity). Например, если взять игру с видом сверху, то учет разности высот при измерении расстояния может казаться визуально неверным, но точным математически. Таким образом вы можете попробовать считать расстояния с помощью тех же методов magnitude, sqrMagnitude или Distance, но используя Vector2. Тогда при вычислении расстояния учитываться будут только x и y координаты объектов. Такой подход может дать более "верное" решение задачи с точки зрения визуальной части.

READ ALSO
убрать пробелы из строки средствами c#

убрать пробелы из строки средствами c#

Как лучше написать код для удаления символов пробела из строки?

392
Как вызвать метод перед выбором новой строки?

Как вызвать метод перед выбором новой строки?

Есть datagridviewПри выборе строки грида отображается детализация по данной позиции на форме ниже в textBox - ах

290
Wpf + Prism навигация перерисовывает DataGridHeader Style?

Wpf + Prism навигация перерисовывает DataGridHeader Style?

Задавал вопрос с сообществе PrismBrian Lagunas уверяет, что это не проблема Prism

320
Visual studio вылет при запуске без отладчика

Visual studio вылет при запуске без отладчика

Народ, такой очень странный вопрос, может у кого было

448