Поворот 2D объекта по оси Z и Y

Нужно поворачивать 2D объект вокруг оси Z, а так же сделать мнимое только визуальное вращение вокруг оси Y. Дополнительно нужно было сделать остановку поворота по Y при выборе объекта (сделано через GetMouseButtonDown(0)) и подвязать логику автоматического режима (метод AutoShoot).

Я решил, что плавно вращаться вокруг оси Y будет только sprite, а часть объекта GunScript будет резко поворачиваться в нужную позицию, чтобы избегать ошибок (вложенность и начальное положение приведены на изображении). Итоговый результат работает, но крайне грязно и неграмотно реализован.

Как лучше реализовать такой формат поворота объекта? Есть ли альтернативное простое решение (поворот по Y с помощью Animation или смена 2D изображений, создающие иллюзию трёхмерности)? Я указал дополнительные задачи для более подробного описания цели, их реализую сам.

public class GunControls : MonoBehaviour
{
    [SerializeField] private GunScript _gun;
    private GunStruct _planetGun;

    [SerializeField, Range(0.5f, 10f)] private float _timePlanetHalfRotation;
    [SerializeField, Range(0.005f, 10f)] private float _deltaTimePlanetRotation;
    [SerializeField, Range(0.005f, 10f)] private float _speedSpritsRotate;

    private Camera _mainCamera;

    private static GunScript selectedGun = null;
    [SerializeField] private int numberOfSelectedWeapon = 0;

    void Start()
    {
        _mainCamera = Camera.main;
        _planetGun = new WeaponStruct { weapon = _gun, timeShoot = _timePlanetHalfRotation, nextViewType = _gun.FieldViewVector.GetOpposite() };
    }

    void Update()
    {
        Vector3 worldMousePosition = _mainCamera.ScreenToWorldPoint(UnityEngine.Input.mousePosition);

        if (Input.GetMouseButtonDown(0))
        {
            selectedGun = _planetGun.weapon;
            if ((worldMousePosition.x > 0 && selectedGun.transform.right.x > 0) || (worldMousePosition.x < 0 && selectedGun.transform.right.x < 0))
            { }
            else {
                selectedGun.transform.localRotation = Quaternion.Euler(0f, 0f, 180f - selectedGun.transform.eulerAngles.z);
            }
            //установление направления и поворота по умолчанию
            selectedGun.FieldViewVector = MainFieldViewType.Right;
            selectedGun.SpriteRotationY.localRotation = Quaternion.Euler(Vector3.zero);
            return;
        }

        if (selectedGun != null)//управление выбранным орудием
        {
            RotateWeapon_Z(selectedGun, CalculateRotation_Z(worldMousePosition, selectedGun.transform.position), Time.deltaTime);

            if (Input.GetMouseButtonDown(1))
            {
                _planetGun.timeShoot = _timePlanetHalfRotation;
                _planetGun.nextViewType = _planetGun.nextViewType.GetOpposite();
                selectedGun = null;
            }
        }

        AutoShoot(Time.deltaTime);
    }

    private void AutoShoot(float deltaTime)
    {
        GunScript weapon = _planetGun.weapon;
        //Debug.Log("оружие перезаряжается (отчитывается время перезарядки до 0f)");
        if (weapon != selectedGun)
        {
            _planetGun.timeShoot -= deltaTime;
            //если в моментах, когда может самостоятельно стрелять
            if (_planetGun.timeShoot >= _timePlanetHalfRotation - _deltaTimePlanetRotation || _planetGun.timeShoot <= _deltaTimePlanetRotation)
            {
                //если повернулся: перешел из состояния 'смотрит вправо' в 'смотрит влево' и наоборот
                if (_planetGun.timeShoot <= _timePlanetHalfRotation / 2f && _planetGun.nextViewType != weapon.FieldViewVector)
                {
                    weapon.FieldViewVector = _planetGun.nextViewType;
                    weapon.transform.localRotation = Quaternion.Euler(0f, 0f, 180f - weapon.transform.eulerAngles.z);
                }
                //если началась новая половина оборота
                if (_planetGun.timeShoot <= 0)
                {
                    _planetGun.timeShoot = _timePlanetHalfRotation;
                    _planetGun.nextViewType = _planetGun.nextViewType.GetOpposite();
                }
                else
                {
                    //Debug.Log("стреляет автоматически (по очереди вправо/влево)");
                }
            }
            RotateWeapon_Y(weapon);
        }
    }

    private float CalculateRotation_Z(Vector3 finalPosition, Vector3 position)//подсчет угла поворота
    {
        Vector3 diference = finalPosition - position;
        float rotateZ = Mathf.Atan2(diference.y, diference.x) * Mathf.Rad2Deg;
        return rotateZ;
    }
    private void RotateWeapon_Z(GunScript weapon, float rotateZ, float deltaTime)//поворот по оси Z
    {
        weapon.transform.localRotation = Quaternion.Slerp(weapon.transform.localRotation, Quaternion.Euler(0f, 0f, rotateZ), weapon.RotationSpeed * deltaTime);
        weapon.SpriteRotationZ.localRotation = Quaternion.Euler(0f, 0f, weapon.transform.localEulerAngles.z);
    }
    private void RotateWeapon_Y(GunScript weapon)//поворот по оси Y (никак не синхронизирован с поворотом 'логики' в методе AutoShoot)
    {
        weapon.SpriteRotationY.localRotation *= Quaternion.Euler(Vector3.up * _speedSpritsRotate);
    }
}

public struct GunStruct
{
    public GunScript weapon;
    public float timeShoot;
    public MainFieldViewType nextViewType;//указатель следующего направления
}

public enum MainFieldViewType//указатель направления орудия
{
    Right, Left
}
public static class FieldViewType
{
    public static MainFieldViewType GetOpposite(this MainFieldViewType a)
    {
        return (MainFieldViewType)((-1) * (int)a);
    }
}

public class GunScript : MonoBehaviour
{
    public MainFieldViewType FieldViewVector;

    public Transform SpriteRotationY;
    public Transform SpriteRotationZ;

    public float RotationSpeed;
}

введите сюда описание изображения


Ответы (0 шт):