Rotation Helper с ограничителями

Программирование на Юнити.

Rotation Helper с ограничителями

Сообщение MeryString 25 мар 2018, 11:26

Делаю маленький вспомогательный класс, что бы потом все могли упростить себе жизнь. Класс этот должен поворачивать объект к цели, но ни как Transform.LookAt(), а плавно, с конкретной скоростью, и ограничителями. Но никак не могу заставить его корректно работать с ограничителями, всё время что-то неправильно. На данный момент класс выглядит так:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//  ИСПРАВЬ: ограничители

/// <summary>
/// Этот класс помогает поворачивать объект с постоянной скоростью и ограничителями
/// </summary>
public class RotationHelper : MonoBehaviour
{
    /// <summary>
    /// Цель, к которой надо повернуться
    /// </summary>
    public Transform target;
    /// <summary>
    /// Ось тангажа
    /// </summary>
    public Transform axisPitch;
    /// <summary>
    /// Ось рыскания
    /// </summary>
    public Transform axisYaw;
    /// <summary>
    /// Заморожен ли тангаж
    /// </summary>
    public bool rotationFreezePitch;
    /// <summary>
    /// Заморожено ли рыскание
    /// </summary>
    public bool rotationFreezeYaw;
    /// <summary>
    /// Ограничен ли тангаж
    /// </summary>
    public bool limitPitch;
    /// <summary>
    /// Ограничено ли рыскание
    /// </summary>
    public bool limitYaw;
    /// <summary>
    ///  Верхний ограничитель тангажа
    /// </summary>
    public float limitMinusAnglePitch;
    /// <summary>
    /// Нижний ограничитель тангажа
    /// </summary>
    public float limitPlusAnglePitch;
    /// <summary>
    ///  Левый ограничитель рыскания
    /// </summary>
    public float limitMinusAngleYaw;
    /// <summary>
    /// Правый ограничитель рыскания
    /// </summary>
    public float limitPlusAngleYaw;
    /// <summary>
    /// Угловая скорость тангажа
    /// </summary>
    public float degreesPerSecondPitch;
    /// <summary>
    /// Угловая скорость рыскания
    /// </summary>
    public float degreesPerSecondYaw;
    /// <summary>
    /// Необходимый угол тангажа
    /// </summary>
    private float anglePitch;
    /// <summary>
    /// Необходимый угол рыскания
    /// </summary>
    private float angleYaw;
    /// <summary>
    /// Последний раз цель была здесь
    /// </summary>
    private Vector3 lastTargetPosition;
    /// <summary>
    /// Максимально допустимое отклонение от цели
    /// </summary>
    public float deviationTarget;

    /// <summary>
    /// Инициализация класса RotationHelper происходит здесь
    /// </summary>
    void Start()
    {
        if (degreesPerSecondPitch == 0)
            Debug.LogWarning("WARNING! Degrees Per Second Pitch = 0");
        if (degreesPerSecondYaw == 0)
            Debug.LogWarning("WARNING! Degrees Per Second Yaw = 0");
        if (axisPitch == null)
            Debug.LogWarning("WARNING! Axis Pitch = null");
        if (axisYaw == null)
            Debug.LogWarning("WARNING! Axis Yaw = null");
    }

    /// <summary>
    /// Вызывается каждый кадр
    /// </summary>
    void Update()
    {
        float _delta = Time.deltaTime;

        if (!rotationFreezePitch && anglePitch != 0)// Если тангаж не заморожен и ещё надо поворачиваться
            axisPitch.localEulerAngles = new Vector3(axisPitch.localEulerAngles.x + NextStepAngle(ref anglePitch, degreesPerSecondPitch, _delta),
                axisPitch.localEulerAngles.y, axisPitch.localEulerAngles.z);// Поворачиваемся с нужной скоростью

        if (!rotationFreezeYaw && angleYaw != 0)// Если рыскание не заморожено и ещё надо поворачиваться
            axisYaw.localEulerAngles = new Vector3(axisYaw.localEulerAngles.x, axisYaw.localEulerAngles.y + NextStepAngle(ref angleYaw, degreesPerSecondYaw, _delta),
                axisYaw.localEulerAngles.z);// Поворачиваемся с нужной скоростью

        if ((lastTargetPosition - target.position).magnitude > deviationTarget)// Если цель сильно сместилась
        {
            ReTarget();// Перенацеливаемся
            lastTargetPosition = target.position;// Запоминаем новую позицию цели
        }
    }

    /// <summary>
    /// Обновление цели
    /// </summary>
    public void ReTarget()
    {
        if (limitPitch)// Если тангаж ограничен
        {
            if (!rotationFreezePitch)// Если тангаж не заморожен
                anglePitch = ReCalculateLimitedAngleToTarget(target.position, axisPitch, axisPitch.localEulerAngles.x, limitMinusAnglePitch, limitPlusAnglePitch, Axis.Pitch);// Расчитываем требуемый угол тангажа с учётом ограничителей
            Debug.Log(name + " Pitch " + anglePitch);
        }
        else
        {
            anglePitch = ReCalculateAngleToTarget(target.position, axisPitch, Axis.Pitch);
        }// Расчитываем требуемый угол тангажа без учёта ограничителей

        if (limitYaw)// Если рыскание ограничено
        {
            if (!rotationFreezeYaw)// Если рыскание не заморожено
                angleYaw = ReCalculateLimitedAngleToTarget(target.position, axisYaw, axisYaw.localEulerAngles.y, limitMinusAngleYaw, limitPlusAngleYaw, Axis.Yaw);// Расчитываем требуемый угол раскания с учётом ограничителей
            Debug.Log(name + " Yaw " + angleYaw);
        }
        else
        {
            angleYaw = ReCalculateAngleToTarget(target.position, axisYaw, Axis.Yaw);
        }// Расчитываем требуемый угол раскания без учёта ограничителей
    }

    /// <summary>
    /// Эта функция расчитывает и возвращает угол, на который нужно повернуть ось, что бы повернуться к указанной цели. Ограничители не учитываются.
    /// </summary>
    /// <param name="_target">Цель</param>
    /// <param name="_axisTransform">Ось</param>
    /// <param name="_axis">Вокруг этой оси поворачиваем</param>
    /// <returns>Угол, на который нужно повернуться</returns>
    public float ReCalculateAngleToTarget(Vector3 _target, Transform _axisTransform, Axis _axis)
    {
        float _angle = 0f;// Подготавливаем угол
        _target = _axisTransform.InverseTransformPoint(_target);// Переносим цель в нашу систему координат
        switch (_axis)// Выбираем ось
        {
            case Axis.Pitch:// Тангаж
                _angle = PreparationPitch(_target);
                break;// И всё

            case Axis.Yaw:// Рыскание
                _angle = PreparationYaw(_target);// Вычисляем угол между носом и целью
                break;// И всё

            case Axis.Roll:// Крен
                _angle = PreparationRoll(_target);// Вычисляем угол между носом и целью
                break;// И всё
        }
        return _angle;// Возвращаем угол, на который надо повернуться
    }

    /// <summary>
    /// Эта функция расчитывает и возвращает угол, на который нужно повернуть ось, что бы повернуться к указанной цели. Ограничители учитываются.
    /// </summary>
    /// <param name="_target">Цель</param>
    /// <param name="_axisTransform">Ось</param>
    /// <param name="_currentAngleAxis">Текущий угол поворота оси</param>
    /// <param name="_limitMinus">Ограничитель оси слева</param>
    /// <param name="_limitPlus">Ограничитель оси справа</param>
    /// <param name="_axis">Вокруг этой оси поворачиваем</param>
    /// <returns>Угол, на который нужно повернуться</returns>
    public float ReCalculateLimitedAngleToTarget(Vector3 _target, Transform _axisTransform, float _currentAngleAxis, float _limitMinus, float _limitPlus, Axis _axis)
    {
        float _angle = 0f;// Подготавливаем угол
        _target = _axisTransform.InverseTransformPoint(_target);// Переносим цель в нашу систему координат
        switch (_axis)// Выбираем ось
        {
            case Axis.Pitch:// Тангаж
                _angle = PreparationPitch(_target);
                break;// И всё

            case Axis.Yaw:// Рыскание
                _angle = PreparationYaw(_target);// Вычисляем угол между носом и целью
                break;// И всё

            case Axis.Roll:// Крен
                _angle = PreparationRoll(_target);// Вычисляем угол между носом и целью
                break;// И всё
        }
        float _limit;// Подготавливаем единый лимит

        if((_angle + _currentAngleAxis) < 0f)// Если угол отрицательный
            _limit = _limitMinus;// Устанавливаем единый лимит
        else if((_angle + _currentAngleAxis) > 0f)// Если угол положительный
            _limit = _limitPlus;// Устанавливаем единый лимит
        else// Иначе
            return 0f;// Не надо никуда поворачивать

        if (Mathf.Abs(_angle + _currentAngleAxis) > Mathf.Abs(_limit))// Если превышен лимит поворота
            _angle = _limit - _currentAngleAxis;// Ограничиваем поворот

        return _angle;// Возвращаем угол, на который надо повернуться
    }

    /// <summary>
    /// Эта функция расчитывает и возвращает угол на который надо повернуться за один кадр
    /// </summary>
    /// <param name="_angle">Оставшийся угол, на который надо повернуться</param>
    /// <param name="_degreesPerSecond">Скорость поворота в градусах/в_секунду</param>
    /// <returns>Угол, на который надо повернуться</returns>
    public float NextStepAngle(ref float _angle, float _degreesPerSecond, float deltaTime)
    {
        float _angleStep = 0;// Подготавливаем шаг поворота
        int _plusMinus;// Подготавливаем изменятель знака
        if (_angle > 0)// Если угол положительный
            _plusMinus = 1;// Устанавливаем изменятель знака
        else if (_angle < 0)// Если угол отрицательный
            _plusMinus = -1;// Устанавливаем изменятель знака
        else// Иначе
            return 0f;// Не надо никуда поворачивать
        _angleStep = _plusMinus * (deltaTime * _degreesPerSecond);// Поворачиваться будем с постоянной угловой скоростью
        if (Mathf.Abs(_angleStep) > Mathf.Abs(_angle))// Если проскочили
            _angleStep = _angle;// Сдаём назад
        _angle -= _angleStep;// Уменьшаем оставшийся угол
       
        return _angleStep;//
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол тангажа
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    public float PreparationPitch(Vector3 _target)
    {
        float _x = 0f;// Цель всегда должна быть точно перед нами
        float _y = _target.y;// Устанавливаем компоненту Y
        _target.y = 0f;// Обнуляем высоту цели
        float _z = _target.magnitude;// Устанавливаем компоненту Z
        _target = new Vector3(_x, _y, _z);// Устанавливаем новую позицию цели
        //if (_y > 0)// Если цель выше носа
        //    return -Vector3.SignedAngle(Vector3.forward, _target, Vector3.right);// Вычисляем угол между носом и целью
        //else// Иначе
        //    return Vector3.SignedAngle(Vector3.forward, _target, Vector3.right);// Вычисляем угол между носом и целью
        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.right);// Вычисляем угол между носом и целью
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол рыскания
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    public float PreparationYaw(Vector3 _target)
    {
        float _x = _target.x;// Устанавливаем компоненту X
        float _y = 0f;// Высота цели на уровне носа
        float _z = _target.z;// Устанавливаем компоненту Z
        _target = new Vector3(_x, _y, _z);// Устанавливаем новую позицию цели

        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.up);
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол крена
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    public float PreparationRoll(Vector3 _target)
    {
        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.forward);
    }
}

/// <summary>
/// Перечисление осей, а точнее поворотов вокруг них
/// </summary>
public enum Axis
{
    Pitch, // Тангаж
    Yaw, // Рыскание
    Roll // Крен
}
 


Прикладываю RotationHelper.UnityPackage со скриптом и демо-сценой. Размер 169 КБ, а создано оно в Unity 2017.3.1f1, но должно заработать и в других версиях.
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение MeryString 25 мар 2018, 14:07

В упор не вижу, что мешает правильно работать ограничителям?
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение 1max1 25 мар 2018, 15:47

А что именно должны делать ограничения? в двух словах если можно.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Rotation Helper с ограничителями

Сообщение MeryString 25 мар 2018, 20:17

Ограничители вроде тех что ограничивают наводку стационарных орудий. Возможно создать условия, при которых ограничители не нужны, но иногда они всё таки требуются.
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение 1max1 25 мар 2018, 21:50

в Start задай стартовый поворот в виде эйлера, потом в Update проверяй, если, к примеру, Х > limitX, то Х = limitX
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Rotation Helper с ограничителями

Сообщение MeryString 25 мар 2018, 22:56

Блин, а я уже библиотеки .NET распотрошила, невнимательность — это беда.
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение MeryString 26 мар 2018, 05:41

RotationAssistant готов, не всё задумки реализованы, но самый требуемый функционал обеспечен. Можно вешать на турели, камеры и всё, что должно вертеться с конкретной скоростью, в определённых предельных углах. Архив размером 162.9 КБ содержит демо-сцену и вот эти два скрипта:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Этот класс помогает поворачивать объект с постоянной скоростью и ограничителями
/// </summary>
public class SlowLookAt : MonoBehaviour
{
    /// <summary>
    /// Цель, к которой надо повернуться
    /// </summary>
    public Transform target;
    /// <summary>
    /// Ось тангажа
    /// </summary>
    public AxisRotation pitch;
    /// <summary>
    /// Ось рыскания
    /// </summary>
    public AxisRotation yaw;
    /// <summary>
    /// Ось крена
    /// </summary>
    public AxisRotation roll;
    /// <summary>
    /// Последний раз цель была здесь
    /// </summary>
    private Vector3 lastTargetPosition;
    /// <summary>
    /// Максимально допустимое отклонение от цели
    /// </summary>
    public float deviationTarget;

    /// <summary>
    /// Инициализация класса RotationHelper происходит здесь
    /// </summary>
    void Start()
    {
        if (pitch.degreesPerSecond == 0)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Degrees Per Second Pitch = 0");// То тангажа не будет
        if (yaw.degreesPerSecond == 0)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Degrees Per Second Yaw = 0");// То рыскания не будет
        if (roll.degreesPerSecond == 0)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Degrees Per Second Roll = 0");// То крена не будет
        if (pitch.axis == null)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Axis Pitch = null");// То нечем будет клевать
        if (yaw.axis == null)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Axis Yaw = null");// То нечем будет рыскать
        if (roll.axis == null)// Если этот параметр не установлен
            Debug.LogWarning("WARNING! Axis Roll = null");// То нечему будет крениться
    }

    /// <summary>
    /// Вызывается каждый кадр
    /// </summary>
    void Update()
    {
        float _delta = Time.deltaTime;// Это что бы передать её дальше
        pitch.NextStepAngle(_delta);//
        yaw.NextStepAngle(_delta);//
        if ((lastTargetPosition - target.position).magnitude > deviationTarget)// Если цель сильно сместилась
        {
            pitch.ReTarget(target.position);// Перенацеливаемся
            yaw.ReTarget(target.position);// Перенацеливаемся
            roll.ReTarget(target.TransformPoint(Vector3.up));// Перенацеливаемся
            lastTargetPosition = target.position;// Запоминаем новую позицию цели
        }
    }
}

/// <summary>
/// Перечисление осей, а точнее поворотов вокруг них
/// </summary>
public enum Axis
{
    Pitch, // Тангаж
    Yaw, // Рыскание
    Roll // Крен
}

/// <summary>
/// Этот класс хранит, нацеливает и вертит ось
/// </summary>
[System.Serializable]
public class AxisRotation
{
    /// <summary>
    /// Заморожена ли ось
    /// </summary>
    public bool rotationFreeze;
    /// <summary>
    /// Угловая скорость вращения
    /// </summary>
    public float degreesPerSecond;
    /// <summary>
    /// Ось, которую надо вращать
    /// </summary>
    public Transform axis;
    /// <summary>
    /// Что это за ось
    /// </summary>
    public Axis axisType;
    /// <summary>
    /// Необходимый угол
    /// </summary>
    private float angle;

    /// <summary>
    /// Конструктор класса AxisRotation
    /// </summary>
    /// <param name="_rotationFreeze">Заморожена ли ось</param>
    /// <param name="_degreesPerSecond">Скорость вращения оси</param>
    /// <param name="_axis">Что за ось</param>
    public AxisRotation(bool _rotationFreeze, float _degreesPerSecond, Axis _axis)
    {
        rotationFreeze = _rotationFreeze;// Устанавливаем параметр
        degreesPerSecond = _degreesPerSecond;// Устанавливаем параметр
        axisType = _axis;// Устанавливаем параметр
        angle = 0f;// Устанавливаем параметр
    }

    /// <summary>
    /// Обновление цели
    /// </summary>
    /// <param name="_target">Цель</param>
    public void ReTarget(Vector3 _target)
    {
        if (!rotationFreeze)// Если ось не заморожена
            angle = ReCalculateAngleToTarget(_target);// Расчитываем требуемый угол
    }

    /// <summary>
    /// Эта функция расчитывает угол на который надо повернуться за один кадр, и поворачивает
    /// </summary>
    /// <param name="_deltaTime">Time.deltaTime</param>
    public void NextStepAngle(float _deltaTime)
    {
        int _plusMinus;// Подготавливаем изменятель знака
        if (angle > 0)// Если угол положительный
            _plusMinus = 1;// Устанавливаем изменятель знака
        else// Иначе
            _plusMinus = -1;// Устанавливаем изменятель знака
        float _angleStep = _plusMinus * (_deltaTime * degreesPerSecond);// Поворачиваться будем с постоянной угловой скоростью
        if (Mathf.Abs(_angleStep) > Mathf.Abs(angle))// Если проскочили
            _angleStep = angle;// Сдаём назад
        angle -= _angleStep;// Уменьшаем оставшийся угол
        Vector3 _rotate = Vector3.zero;// Подготавливаем вектор
        switch (axisType)// Выбираем ось
        {
            case Axis.Pitch:// Тангаж
                _rotate = new Vector3(_angleStep, 0f, 0f);// Создаём правильный вектор
                break;// Всё
            case Axis.Yaw:// Рыскание
                _rotate = new Vector3(0f, _angleStep, 0f);// Создаём правильный вектор
                break;// Всё
            case Axis.Roll:// Крен
                _rotate = new Vector3(0f, 0f, _angleStep);// Создаём правильный вектор
                break;// Всё
        }
        axis.Rotate(_rotate);// Поворачиваемся с нужной скоростью
    }

    /// <summary>
    /// Эта функция расчитывает и возвращает угол, на который нужно повернуть ось, что бы повернуться к указанной цели.
    /// </summary>
    /// <param name="_target">Цель</param>
    /// <returns>Угол, на который нужно повернуться</returns>
    private float ReCalculateAngleToTarget(Vector3 _target)
    {
        float _angle = 0f;// Подготавливаем угол
        _target = axis.InverseTransformPoint(_target);// Переносим цель в нашу систему координат
        switch (axisType)// Выбираем ось
        {
            case Axis.Pitch:// Тангаж
                _angle = PreparePitch(_target);// Расчитываем угол
                break;// И всё

            case Axis.Yaw:// Рыскание
                _angle = PrepareYaw(_target);// Расчитываем угол
                break;// И всё

            case Axis.Roll:// Крен
                _angle = PrepareRoll(_target);// Расчитываем угол
                break;// И всё
        }
        return _angle;// Возвращаем угол, на который надо повернуться
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол тангажа
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    private float PreparePitch(Vector3 _target)
    {
        float _x = 0f;// Цель всегда должна быть точно перед нами
        float _y = _target.y;// Устанавливаем компоненту Y
        _target.y = 0f;// Обнуляем высоту цели
        float _z = _target.magnitude;// Устанавливаем компоненту Z
        _target = new Vector3(_x, _y, _z);// Устанавливаем новую позицию цели
        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.right);// Вычисляем угол между осью и целью
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол рыскания
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    private float PrepareYaw(Vector3 _target)
    {
        float _x = _target.x;// Устанавливаем компоненту X
        float _y = 0f;// Высота цели на уровне носа
        float _z = _target.z;// Устанавливаем компоненту Z
        _target = new Vector3(_x, _y, _z);// Устанавливаем новую позицию цели
        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.up);// Вычисляем угол между осью и целью
    }

    /// <summary>
    /// Корректирует положение цели и возвращает угол крена
    /// </summary>
    /// <param name="_target">Цель в локальной системе координат оси</param>
    /// <returns>Угол, на который надо повернуть</returns>
    private float PrepareRoll(Vector3 _target)
    {
        float _x = _target.x;// Устанавливаем компоненту X
        float _y = _target.y;// Устанавливаем компоненту Y
        float _z = _target.z;// Устанавливаем компоненту Z
        _target = new Vector3(_x, _y, _z);// Устанавливаем новую позицию цели
        return Vector3.SignedAngle(Vector3.forward, _target, Vector3.forward);// Вычисляем угол между осью и целью
    }
}

Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Этот класс ограничивает вращение осей
/// </summary>
public class RotationLimit : MonoBehaviour
{
    /// <summary>
    /// Ограничен ли тангаж
    /// </summary>
    public bool pitchIsLimited;
    /// <summary>
    /// Ось тангажа
    /// </summary>
    public Transform axisPitch;
    /// <summary>
    /// Ограничения тангажа
    /// </summary>
    public Limit limitPitch;
    /// <summary>
    /// Ограничено ли рыскание
    /// </summary>
    public bool yawIsLimited;
    /// <summary>
    /// Ось рыскания
    /// </summary>
    public Transform axisYaw;
    /// <summary>
    /// Ограничения рыскания
    /// </summary>
    public Limit limitYaw;
    ///// <summary>
    ///// Ограничен ли крен
    ///// </summary>
    //public bool rollIsLimited;
    /// <summary>
    /// Ось крена
    /// </summary>
    public Transform axisRoll;
    ///// <summary>
    ///// Ограничения крена
    ///// </summary>
    //public Limit limitRoll;

    /// <summary>
    /// Вызывается каждый кадр
    /// </summary>
    void Update()
    {
        if (pitchIsLimited)// Если тангаж ограничен
            axisPitch.localEulerAngles = new Vector3(limitPitch.LimitAngle(axisPitch.localEulerAngles.x), axisPitch.localEulerAngles.y, axisPitch.localEulerAngles.z);// Получаем новый, уже ограниченый угол тангажа
        if (yawIsLimited)// Если рыскание ограничено
            axisYaw.localEulerAngles = new Vector3(axisYaw.localEulerAngles.x, limitYaw.LimitAngle(axisYaw.localEulerAngles.y), axisYaw.localEulerAngles.z);// Получаем новый, уже ограниченый угол рыскания
        //if (rollIsLimited)// Если крен ограничен
        //    axisRoll.localEulerAngles = new Vector3(limitRoll.LimitAngle(axisRoll.localEulerAngles.x), axisRoll.localEulerAngles.y, axisRoll.localEulerAngles.z);// Получаем новый, уже ограниченый угол крена
        axisRoll.localEulerAngles = new Vector3(axisRoll.localEulerAngles.x, axisRoll.localEulerAngles.y, 0f);
    }
}

/// <summary>
/// Этот класс хранит параметры ограничения и ограничевает углы
/// </summary>
[System.Serializable]
public class Limit
{
    /// <summary>
    /// Левый ограничитель, должен быть от 180 до 360 градусов
    /// </summary>
    public float limitOver180Degrees;
    /// <summary>
    /// Правый ограничитель, должен быть от 0 до 180 градусов
    /// </summary>
    public float limitUnder180Degrees;

    /// <summary>
    /// Конструктор класса Limit
    /// </summary>
    /// <param name="_limitOver180Degrees"></param>
    /// <param name="_limitUnder180Degrees"></param>
    public Limit(float _limitOver180Degrees, float _limitUnder180Degrees)
    {
        limitOver180Degrees = _limitOver180Degrees;
        limitUnder180Degrees = _limitUnder180Degrees;
    }

    /// <summary>
    /// Ограничевает угол
    /// </summary>
    /// <param name="_angle"> Не ограниченный угол</param>
    /// <returns>Ограниченный угол</returns>
    public float LimitAngle(float _angle)
    {
        if ((_angle < limitOver180Degrees) && (_angle > limitUnder180Degrees))// Если угол надо ограничить
        {
            if (_angle >= 180f)// Если угол в той половине
                return limitOver180Degrees;// Принимаем это ограничение
            else// Иначе
                return limitUnder180Degrees;// Принимаем вот это ограничение
        }
        else return _angle;// Иначе возвращаем как есть

    }
}
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение djon801 26 мар 2018, 11:41

(3A4OT) Хорошая работа!
Аватара пользователя
djon801
Старожил
 
Сообщения: 506
Зарегистрирован: 03 май 2014, 15:08

Re: Rotation Helper с ограничителями

Сообщение MeryString 30 мар 2018, 15:28

Позже ещё доработаю.
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41

Re: Rotation Helper с ограничителями

Сообщение lawsonilka 30 мар 2018, 15:45

;)
lawsonilka
UNIверсал
 
Сообщения: 390
Зарегистрирован: 21 окт 2014, 14:48

Re: Rotation Helper с ограничителями

Сообщение MeryString 03 апр 2018, 15:24

Хотелось добавить угловую поправку на тот случай, когда повернуться нужно не носом, а, к примеру, ухом. Но начинаю сомневаться, стоит ли, ведь создать правильную иерархию объектов не является проблемой. Так же хотелось добавить сдвиг на тот случай, когда нос объекта смещён в сторону. Линейная поправка мне кажется нужной вещью, а угловая лишней. А что вы думаете по этому поводу?
Аватара пользователя
MeryString
UNIт
 
Сообщения: 100
Зарегистрирован: 18 май 2014, 19:41


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11