Как сделать движение обьекта с ускорением?
У меня есть пила, которая двигается туда-сюда с ускорением. На половине пути меняет ускорение на противоположное.
Проблема в том, что нет плавности и дергается. Та и когда пила доходит до половины пути, параметры далеко от нужных.

(Или же, если вы предложите свою реализацию равномерно ускоренного движения, буду очень рад :) )
P.S Я новичок, не бейте палками :)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SawAcceleration : Saw
{
private double maxSpeed;
private double startSpeed;
private double acceleration;
private double timeForMaxSpeed;
private Vector2 halfDistance; // когда пила прошла половину пути, сменить ускорение
private double currentSpeed;
private double currentTime;
private bool insideTheMiddle = false; // когда пила заходит в эпсилон-окрестность центра пути
private void Start()
{
start = transform.position;
target = start + transform.right * distance * (goRight ? 1 : -1);
halfDistance = (start + target) / 2;
maxSpeed = speed;
startSpeed = 0;
acceleration = (maxSpeed * maxSpeed - startSpeed * startSpeed) / (2 * distance);
timeForMaxSpeed = (maxSpeed - startSpeed) / acceleration;
}
private void Update()
{
currentTime += Time.deltaTime;
if (currentTime >= timeForMaxSpeed)
currentTime = 0;
if (Vector2.Distance(transform.position , halfDistance) <= 0.01 && !insideTheMiddle) // когда пила прошла половину пути
{
ChangeAcceleration(maxSpeed);
}
if (Vector2.Distance(transform.position, target) <= Mathf.Epsilon) // когда пила прошла весь путь
{
ChangeAcceleration(0);
ChangeTarget();
}
currentSpeed = startSpeed + acceleration * currentTime;
transform.position = Vector2.MoveTowards(transform.position, target, (float)currentSpeed * Time.deltaTime);
}
private void ChangeAcceleration(double speed)
{
startSpeed = speed;
acceleration = -acceleration;
insideTheMiddle = !insideTheMiddle;
currentTime = 0;
}
}
Ответы (2 шт):
Автор решения: Yaroslav
→ Ссылка
Не проще использовать синусоиду?
public class Saw : MonoBehaviour {
[SerializeField] private float _speed = 10f;
[SerializeField] [Range(0, 2)] private float _startRate = 0f; // стартовая позиция (A>B>A-0>1>2)
[SerializeField] private Transform _pointA; // пустой gameObject
[SerializeField] private Transform _pointB; // пустой gameObject
private Transform _transform;
private float _distance;
private float _way;
private void Start () {
_transform = transform; // кешируем трансформ, что бы не запрашивать заново
if (_pointA != null && _pointB != null)
_distance = Vector3.Distance(_pointA.position, _pointB.position);
_way = _startRate*_distance;
}
private void Update () {
if (_distance > 0) {
_way += _speed*Time.deltaTime;
// _distance*2f путь до B и обратно
// % - остаток от деления
_way %= _distance*2f;
// нормализованное значение (A>B-0>1) (A>B>A-0>1>2)
float WayRate = _way/_distance;
// линейныое движение (A>B>A-0>1>0)
/*if (WayRate > 1)
WayRate = 1-(WayRate-1);*/
// синусойдное движение
WayRate = 0.5f-Mathf.Cos(WayRate*Mathf.PI)*0.5f;
_transform.position = Vector3.Lerp(_pointA.position, _pointB.position, WayRate);
}
}
}
Автор решения: Денис
→ Ссылка
Решил проблему все-таки) Идею взял у автора выше. Но реализацию немного поменял
public class SawAcceleration : Saw
{
/*
Взял за основу функцию f(x) = (1 - cos(a * x) ) / 2 , где a - параметр
В нашем случае скорость. Чем больше a, тем более "сплюснутая" функция, тем
быстрее пила
Область значения f = [0 , 1]
Аргумент функции x - время
Значение функции - пройденный путь пилы
Период f = 2PI / a
*/
private float time;
private float lerp;
private double period;
private void Start()
{
start = transform.position; // point A
target = start + transform.right * distance * (goRight ? 1 : -1); // point B
period = 2 * Math.PI / speed;
}
private void Update()
{
time += Time.deltaTime;
if (time >= period)
time = 0;
lerp = (float)(1 - Math.Cos(speed * time)) / 2;
transform.position = Vector3.Lerp(start, target, lerp);
}
}
