Формулы для движения по окружности и винтовой линии с переменным ускорением

Знает кто формулы для движения по окружности и винтовой линии с переменным ускорением? Не могу в инете ничего найти, а в вузе нет нужной формулы в учебнике. В идеале это реализовать в скрипте, но формулы будет достаточно. Вот код с примером движения с постоянным ускорением

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Utils;

public class AccelerationPermanent : MonoBehaviour
{
    [Header("Настройки")] 
    [Tooltip("Ускорение")]
    [SerializeField] private float _acceleration = 0;
    [Tooltip("Скорость")]
    [SerializeField] private float _velocity = 0;
    [Tooltip("Время начала движения")]
    [SerializeField] private float _timeToStartSpinning;
    [Tooltip("Время таймера")]
    [SerializeField] private float _time = 10;
    [Tooltip("Объект вокруг которого движется таймер")]
    [SerializeField] private Transform _target;
    
    private float _radius;
    private float _timePassed;
    private float _accelerationLinear;
    private float _velocityLinear; // разложение результирующей скорости
    private const float PI = 3.14f;
    private bool _t1 = true;

    void Start()
    {
        _radius = Vector3.Distance(_target.position, transform.position);
        _accelerationLinear = _acceleration / Mathf.Sqrt(2);
        _velocityLinear = _velocity / Mathf.Sqrt(2);
    }
    
    void FixedUpdate()
    {
        if (Timer.IsTimerOff(ref _timeToStartSpinning) && _t1)
        {
            _t1 = false;
        }

        if (!_t1)
        {
            Move();
            if (Timer.IsTimeOver(ref _time)) // Каждый промежуток времени выводим пройденное расстояние
            {
                float S = 0;
                if (_acceleration * _velocity > 0)
                    S = _velocity * _timePassed +
                        _acceleration * _timePassed * _timePassed / 2;
                else if (_acceleration == 0)
                {
                    S = Mathf.Abs(_velocity) * _timePassed;
                }
                else if(_acceleration == 0 && _velocity == 0)
                {
                    S = 0;
                }
                else
                    S = (Mathf.Abs(_velocity * _velocity) / Mathf.Abs(2 * _acceleration)) 
                        + Mathf.Abs(_acceleration) * (_timePassed - Mathf.Abs(_velocity) 
                            / Mathf.Abs(_acceleration)) * (_timePassed - Mathf.Abs(_velocity) / Mathf.Abs(_acceleration)) / 2;
                Debug.Log($"S = {S}, position = {transform.position}, time = {_timePassed}");
                Time.timeScale = 0;
            }
        }
    }
    
    private void Move()
    {
        if (_velocity == 0 && _acceleration == 0)
            return;
        _timePassed += Time.fixedDeltaTime;
        var height = 2 * PI * _radius;
        var x = _radius * Mathf.Cos((_velocityLinear / _radius) * _timePassed + _accelerationLinear * _timePassed * _timePassed / (2 * _radius));
        var y = (height / (2 * Mathf.PI)) * ((_velocityLinear / _radius) * _timePassed + _accelerationLinear * _timePassed * _timePassed / (2 * _radius));
        var z = _radius * Mathf.Sin((_velocityLinear / _radius) * _timePassed + _accelerationLinear * _timePassed * _timePassed / (2 * _radius));
        
        transform.position = new Vector3(x, y, z);
    }
}

Была мысль просто каждый фрейм пересчитывать ускорение, но не уверен что это так работает.


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

Автор решения: Yaroslav

Движение по спирали это движение по окружности с смещением по третей оси! Движение по окружности можешь в школьном учебнике за 9 класс, если не ошибаюсь.

x: Cos(radian) 
y: Sin(radian)
  • зачем тебе _target, если можно просто сделать объект дочерним к нему и менять локальную позицию?
  • почему FixedUpdate если ты тут не работаешь с физикой тел?

Движение по окружности и смещение это соответственно две разные скорости. Менять их можно тупо установив общий коэффициент скорости SpeedMultiplayer.

public class SpiralMovement : MonoBehaviour
{
    public float SpeedMultiplayer = 1;
    [SerializeField] private float _angularSpeed = 180;
    [SerializeField] private float _offsetSpeed = -0.5f;
    [Space]
    [SerializeField] private float _radius = 1;
    private float _currentRadian;
    private float _currentOffset;

    private void Update ()
    {
        float delta = Time.deltaTime*SpeedMultiplayer;
        _currentRadian += _angularSpeed*Mathf.Deg2Rad*delta;
        _currentOffset += _offsetSpeed*delta;

        transform.localPosition = new Vector3(Mathf.Cos(_currentRadian), _currentOffset, Mathf.Sin(_currentRadian));
    }
} 

Меняем

→ Ссылка
Автор решения: mefchik

Вот решение. Мб кому пригодится.

``

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Utils;

public class AccelerationChangable : MonoBehaviour
{
    [Header("Настройки")] 
    [Tooltip("Коэффициент A")]
    [SerializeField] private float _A = 0;
    [Tooltip("Коэффициент B")]
    [SerializeField] private float _B = 0;
    [Tooltip("Скорость")]
    [SerializeField] private float _velocity = 0;
    [Tooltip("Время начала движения")]
    [SerializeField] private float _timeToStartSpinning;
    [Tooltip("Время таймера")]
    [SerializeField] private float _time = 10;
    [Tooltip("Объект вокруг которого движется таймер")]
    [SerializeField] private Transform _target;
    private float _radius;
    private float _timePassed;
    private float _acceleration;
    private float _accelerationLinear;
    private float _velocityLinear; // разложение результирующей скорости
    private const float PI = 3.14f;
    private bool _t1 = true;
    private float _distance;

    void Start()
    {
        _radius = Vector3.Distance(_target.position, transform.position);
        _velocityLinear = _velocity / Mathf.Sqrt(2);
        _acceleration = _A + _B * _timePassed;
    }
    
    void FixedUpdate()
    {
        if (Timer.IsTimerOff(ref _timeToStartSpinning) && _t1)
        {
            _t1 = false;
        }

        if (!_t1)
        {
            Move();
            if (Timer.IsTimeOver(ref _time)) // Каждый промежуток времени выводим пройденное расстояние
            {
                float S = 0;
                Debug.Log($"S = {_distance}, position = {transform.position}, time = {_timePassed}");
                Time.timeScale = 0;
            }
        }
    }
    
    private void Move()
    {
        if (_velocity == 0 && _acceleration == 0)
            return;
        _timePassed += Time.fixedDeltaTime;
        var height = 2 * PI * _radius;
        var x = _radius * Mathf.Cos((_velocityLinear * _timePassed + (Mathf.Sqrt(2) / 4) * _A * _timePassed * _timePassed + (Mathf.Sqrt(2) / 12) * _B * _timePassed * _timePassed * _timePassed) * 2 * Mathf.PI / height);
        var y = _velocityLinear * _timePassed + (Mathf.Sqrt(2) / 4) * _A * _timePassed * _timePassed + (Mathf.Sqrt(2) / 12) * _B * _timePassed * _timePassed * _timePassed;
        var z = _radius * Mathf.Sin((_velocityLinear * _timePassed + (Mathf.Sqrt(2) / 4) * _A * _timePassed * _timePassed + (Mathf.Sqrt(2) / 12) * _B * _timePassed * _timePassed * _timePassed) * 2 * Mathf.PI / height);
        _distance += Vector3.Distance(transform.position, new Vector3(x, y, z));
        transform.position = new Vector3(x, y, z);
    }
}

``

→ Ссылка