» » » Unity3d. Реализация зон видимости и слышимости

 

Unity3d. Реализация зон видимости и слышимости

Автор: admin от 21-04-2015, 15:18, посмотрело: 1399

Добрый день, хабра.

Сегодня расскажу о том, как можно реализовать систему видимости и слышимости для ваших проектов. Получилось нечто схожее с игрой Commandos.
Немного скриншотов.
Unity3d. Реализация зон видимости и слышимости
Больше видимости.
Unity3d. Реализация зон видимости и слышимости


Я тебя вижу


Как можно увидеть объект? Вариантов можно перечислить множество. Встречаются варианты с видимостью по коллайдерами, разбором картинки через рендер текстуру, лучи по точкам и т.д. В данном примере рассмотрим вариант лучей по точкам.
Следовательно нам понадобится базовый класс с точками для системы видимости.
public abstract class UnitBase : GameObjectBase 
{
    public List<Transform> visiblePoints;
...
}

Теперь. Нам нужно сформулировать требования к системе видимости.
Очевидно у юнита(не важно что это, друг, враг или камера видео-наблюдения) должен быть угол обзора и дистанция на которой он различает объекты. Близорукие и дальнозоркие тоже могут быть. Да и персонаж может, например, одеть очки и видеть дальше. Может что-то принять и видеть чуть шире боковым зрением. Следовательно параметры нам нужны цель, глаза, дальность и угол обзора.
  public static bool IsVisibleUnit<T>(T unit, Transform from, float angle, float distance, LayerMask mask) where T : UnitBase
    {
        bool result = false;
        if (unit != null)
        {
            foreach (Transform visiblePoint in unit.visiblePoints)
            {
                if (IsVisibleObject(from, visiblePoint.position, unit.gameObject, angle, distance, mask))
                {
                    result = true;
                    break;
                }
            }
        }
        return result;
    }

LayerMask — нужен для лучей. Например на окно среагирует пуля но не зрение. Тоже самое с заборами или другими объектами. Следовательно, видимость игнорирует не нужные или прозрачные объекты. А спрятавшись в листве, можно обнулить список видимых точек. Также можно расширить или сузить список точек, в зависимости от логики самой игры. Например камуфляж или еще что-то.

  public static bool IsVisibleObject(Transform from, Vector3 point, GameObject target, float angle, float distance, LayerMask mask)
    {
        bool result = false;
        if (IsAvailablePoint(from, point, angle, distance))
        {
            Vector3 direction = (point - from.position);
            Ray ray = new Ray(from.position, direction);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, distance, mask.value))
            {
                if (hit.collider.gameObject == target)
                {
                    result = true;
                }
            }
        }
        return result;
    }


Тут стоит обратить внимание на условие (hit.collider.gameObject == target). О том почему это так выглядит, будет понятно на примере использования. Системе отравляем желаемого юнита, и проверяем, реально ли мы можем его увидеть. Именно того которого хотим.

    public static bool IsAvailablePoint(Transform from, Vector3 point, float angle, float distance)
    {
        bool result = false;

        if (from != null && Vector3.Distance(from.position, point) <= distance)
        {
            Vector3 direction = (point - from.position);
            float dot = Vector3.Dot(from.forward, direction.normalized);
            if (dot < 1)
            {
                float angleRadians = Mathf.Acos(dot);
                float angleDeg = angleRadians * Mathf.Rad2Deg;
                result = (angleDeg <= angle);
            }
            else
            {
                result = true;
            }
        }
        return result;
    }

Тут не использовались хитрости с magnitude или преобразованием углов. Находим скалярное произведение. Если 1, значит точки направлены в одну сторону и угол можно опустить, иначе получаем угол и проверяем пределы.

А теперь я тебя еще и слышу


С системой слышимости все обстоит гораздо проще. На любой звук, мы перебираем всех допустимых юнитов (опустим как это реализовано. Главное что в текущей зоне или всей локации, есть какое-то количество юнитов) и передаем точку шума, ее радиус, и в данном случае еще и тип шума. Например на звук выстрела и звук падающего камня аи может реагировать по разному. Это зависит то того как вы это реализуете.
[code] public virtual void ApplyNoise(Vector3 target, float radius, NoiseType type)
{
ListUnity scripting

Источник: Хабрахабр

Категория: Программирование » Game Development

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *