Используйте коллайдер нескольких объектов как один коллайдер

На моем уровне fps (Unity) цели появляются в случайном месте. Я хочу убедиться, что цели не могут появляться за объектами или внутри объектов.

Чтобы убедиться, что они не появляются позади объекта, я сделал raycast переход от игрока к цели. Если есть препятствия, я пересчитываю точку появления. Это работает нормально, но, поскольку цели являются сферами, лучей не будет препятствовать, когда цель находится на 50% внутри объекта, например, пола. Очевидно, я этого не хочу.

Чтобы определить, находится ли цель в границах другого объекта, я попытался использовать OnCollisionEnter и OnCollisionExit. Хотя это работает при простом перемещении цели внутри другого объекта, это кажется ненадежным, когда цикл обновления одного скрипта пересчитывает позицию появления, в то время как цикл обновления цели отслеживает столкновение.

Поэтому я искал другой подход. Вот что я придумал (из документов Unity):

m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
    Debug.Log("Bounds intersecting");
}

Мир игровых объектов - это родительский объект, в который я помещаю все объекты своего игрового мира.

Проблема в том, что он учитывает только коллайдер первого объекта. Я в основном хочу использовать один большой коллайдер, состоящий из всех объектов уровня.

Это возможно? Или кто-нибудь знает другой подход к тому, как я могу этого добиться?


person binoculars    schedule 28.01.2018    source источник


Ответы (1)


Вы должны использовать метод GetComponentsInChildren вместо GetComponentInChildren, чтобы вы могли получить из него массив collider, на котором вы можете выполнить foreach, чтобы проверить, пересекаются ли bounds.

I.E.:

m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
    if (objCollider.bounds.Intersects(m_Collider2.bounds))
    {
        Debug.Log("Bounds intersecting");
        break;
    }
}

Но такой способ выполнения задач очень тяжел для ЦП, поскольку GetComponent методы очень медленные, поэтому их использование должно быть ограничено внутри Awake и Start методов, если это возможно.

Другой подход к проблеме - создать List<Collider> в начале и добавить к нему начальные дочерние элементы вашего игрового объекта World. Если создается другой экземпляр, просто Add его в свой список, если он уничтожен, просто Remove его.

Затем, непосредственно перед созданием экземпляра, вы можете проверить bounds, выполнив цикл внутри List с foreach, проверка будет намного быстрее.

==================================

РЕДАКТИРОВАТЬ:

Хорошо, вот в чем дело. Прежде всего, добавьте эти строки в ваш World скрипт игрового объекта (я думаю, вы вызвали класс World):

using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type

public class World : MonoBehaviour {

    //The list which will hold references to the children game objects colliders
    public List<Collider> childrenColliders;

    private void Start() {
        //Code used to populate the list at start
        childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
    }

Теперь, поскольку в скрипте, который порождает новый объект, уже есть переменная world, которая содержит ссылку на класс World:

foreach(Collider coll in world.childrenColliders) {
    if (coll.bounds.Intersects(m_Collider2.bounds))
    {
        Debug.Log("Bounds intersecting");
        break;
    }
}

И, конечно же, как я уже сказал ранее, не забудьте добавить коллайдер только что созданного игрового объекта в список с помощью:

void AddNewGameObject() {
    // spawnPoint is the transform.position Vector3 you'll use for the new game object
    var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
    world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}

Это почти все. ;)

person Galandil    schedule 28.01.2018
comment
Спасибо за комментарий. Хорошо, поэтому использование GetComponent не вариант. Я понимаю основы вашего предложения List, но поскольку я новичок в C Sharp и Unity, я действительно не знаю, что именно делать. Есть ли шанс, что вы могли бы уточнить немного больше? - person binoculars; 28.01.2018
comment
Отредактировал ответ, чтобы дать больше понимания и практического решения. - person Galandil; 29.01.2018