Вход

Просмотр полной версии : requestAnimationFrame - замедление обьекта


potatosboxon
03.02.2020, 19:13
Здравствуйте.

Код ниже демонстрирует ускоренеи элемента.

https://jsfiddle.net/sLy4dz7p/1/

<body style="background-color:#000;">
<div id="test" style="position:absolute;top:50%;left:50%;transform:trans late(50%,50%);width:20px;height:20px;background-color:#fff;"></div>
</body>
<script>
window.onload = function(){
var element = document.getElementById('test');
var start;

var minSpeed=1;
var maxSpeed=5;
var minPosY=0;
var maxPosY=250;
var thisPosY=50;

//Движение
function moveMe(speed,pxY){
//Шаг
function step(timestamp){
if (!start) {
start = timestamp;
};
time=timestamp-start;
var px = time * speed / 10;
element.style.transform = "translate("+0+"px,"+px+"px)";
if (px < pxY){
requestAnimationFrame(step);
speed=speed+0.5;
return;
}
console.log("Приехали");
return;
}
requestAnimationFrame(step);
}
moveMe(5,500);
}
</script>
Никак не могу решить задачу.
Необходимо плавно менять скорость перемещения относительно текущей позиции. То-есть если элемент находится на minPosY=0 то необходимо задать minSpeed=1, по мере увеличения Y в +, необходимо плавно наращивать скорость, пока она не станет равной 5 или не будет превышен maxPosY.

По существу, представим поле, сверху обьект движется с минимальной скоростью, внизу с максимальной. Между минимумом и максимумом скорость меняется плавно.

Help!

рони
03.02.2020, 19:44
potatosboxon,
Структура анимации (https://learn.javascript.ru/js-animation#struktura-animatsii)

ставите нужную Функцию расчёта времени(easing) и всё.

MallSerg
03.02.2020, 19:45
google (https://www.google.com/search?ei=4U44XvDdBdKDk74Px9Wo4AY&q=js+ease&oq=js+ease&gs_l=psy-ab.3..0j0i67j0l2j0i22i30l3j0i22i10i30j0i22i30l2.26 488.26488..26781...0.2..0.81.81.1......0....1..gws-wiz.......0i71.Mp-kmSjayuk&ved=0ahUKEwiw0uiM67XnAhXSwcQBHccqCmwQ4dUDCAs&uact=5)

или лучше https://learn.javascript.ru/js-animation#funktsii-raschyota-vremeni

potatosboxon
03.02.2020, 19:51
А средствами чистого javascript этот вопрос никак не решить?

MallSerg
03.02.2020, 20:08
А для тебя JS по всем приведенным ссылкам не достаточно чистый?
там даже каких либо подключенных библиотек нету =(.

potatosboxon
03.02.2020, 21:33
Не крутил я animate. Он вроде как совсем новехенький.
Короч спутал я WEB Animate API и временную функцию.
В общем на сколько я сейчас разобрался, надо сделать следующее.
Найти начальную позицию.
Расчитать оставшееся время.
Задать параметры времеени и запустить элемент в путь.
Надо найти ease функцию.
Вот эта вроде как не то что надо
function inOutQuad(n){
n *= 2;
if (n < 1) return 0.5 * n * n;
return - 0.5 * (--n * (n - 2) - 1);
};
Только не понятно, как каждый раз актуализировать оставшееся растояние, текущую позицию, и скоростью преодаления пути.

рони
03.02.2020, 23:58
potatosboxon,
<!DOCTYPE html>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<style type="text/css">
body{
background-color: hsla(0, 0%, 66%, 1);
margin: 0;
}

div{
display: inline-block;
}

</style>
<script>
document.addEventListener( "DOMContentLoaded" , function() {
function animate({timing, draw, duration}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
let progress = timing(timeFraction);
draw(progress);
if (timeFraction < 1) {
requestAnimationFrame(animate);
}

});
}
function inOutQuad(n){
n *= 2;
if (n < 1) return 0.5 * n * n;
return - 0.5 * (--n * (n - 2) - 1);
};
function easeOutExpo( t ) {

if( t === 1 ) {
return 1;
}

return ( -Math.pow( 2, -10 * t ) + 1 );

}
class Boulder extends HTMLDivElement{
constructor(color, left = 100, size = 15) {
super();
this.color = color;
this.left = left;
this.size = size;
this.style.background = this.color;
this.style.width = `${this.size}px`;
this.style.height = `${this.size}px`;
this.style.transform = `translate(${this.left}px, 0px)`;
this.option = {timing : easeOutExpo, draw : this.draw.bind(this), duration : 5000};
animate(this.option);
}
draw(progress){
this.style.transform = `translate(${this.left}px, ${(window.innerHeight - this.size) * progress|0}px)`;
}

}
customElements.define("custom-box", Boulder, { extends: "div" });

for (let i = 0; i < 7; i++) {
const color = '#' + ('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);
const left = (window.innerWidth - 15) * Math.random()|0;
const box = new Boulder(color, left);
document.querySelector("body").append(box);
}


});
</script>
</head>
<body>
</body>
</html>

potatosboxon
04.02.2020, 09:18
Че то не получается у меня точно сформулировать мысль. Надо подумать прежде чем вопрос задавать.
Надо начать с простого.
Пример демонстрирует ускорение.
function ease(n){
return Math.pow(n, 2)
};
function startAnimation(){
var element = document.getElementById('test');
var stop = false;

// animating x (margin-left) from 20 to 300, for example
var startx = 0;
var destx = 250;
var duration = 1500;
var start = null;
var end = null;

function startAnim(timeStamp) {
start = timeStamp;
end = start + duration;
draw(timeStamp);
}

function draw(now) {
if (stop) return;
if (now - start >= duration) stop = true;
var p = (now - start) / duration;
val = ease(p);
var px = startx + (destx - startx) * val;
element.style.transform = "translate("+0+"px,"+px+"px)";
requestAnimationFrame(draw);
}

requestAnimationFrame(startAnim);
}
startAnimation();
Как в данном случае замедлять элемент?

рони
04.02.2020, 11:19
замедлять элемент
смотрите пример выше #7, заменил inOutQuad на easeOutExpo.

potatosboxon
04.02.2020, 11:36
Не решить мою задачу банальной t функцией.
Это хорошо эффектики всякие запускать, снежок там замедлять, ракету, но у меня совсем иная задача.
У меня сетка 5x5.
На 0:Y обьект должен перемещаться со скоростью 1.
На 5:Y обьект должен перемещаться со скоростью 5.
При движении от 0 к 5, от 5 к 0 - должна меняться скорость.
При перемещении по X скорость должна сохраняться заданная при перемещении по Y.
Спасибо за ответы, буду копать.

рони
04.02.2020, 11:54
На 0:Y обьект должен перемещаться со скоростью 1.
На 5:Y обьект должен перемещаться со скоростью 5.
При движении от 0 к 5, от 5 к 0 - должна меняться скорость.
При перемещении по X скорость должна сохраняться заданная при перемещении по Y.

не осилил.

Malleys
05.02.2020, 10:50
У меня сетка 5x5.
На 0:Y обьект должен перемещаться со скоростью 1.
На 5:Y обьект должен перемещаться со скоростью 5.
При движении от 0 к 5, от 5 к 0 - должна меняться скорость.

Т. е. вам нужно такое перемещение объекта, чтобы находясь в верхней части его скорость была 1 ячейка сетки / сек., а находясь в нижней части — 5 ячеек сетки / сек. Объект проходит 5 ячеек. Притом должно быть поступательное движение.

Давайте разбираться. Получается, что начальная скорость v₀ = 1, конечная скорость v₁ = 5. Объект начинает двигаться от точки s₀ = 0 и завершает своё движение в точке s₁ = 5. Движение начинается в момент времени t₀ = 0 и завершается в t₁, которое мы можем вычислить основываясь на том, что объект движется равноускоренно, т. е. ускорение a₀ постоянно.

Время окончания движения можно вычислить по формуле равноускоренного движения (https://ru.wikipedia.org/wiki/%D0%A3%D1%81%D0%BA%D0%BE%D1%80%D0%B5%D0%BD%D0%B8%D 0%B5#%D0%A0%D0%B0%D0%B2%D0%BD%D0%BE%D1%83%D1%81%D0 %BA%D0%BE%D1%80%D0%B5%D0%BD%D0%BD%D0%BE%D0%B5_%D0% B4%D0%B2%D0%B8%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5). Вычислив время завершения t₁, можно узнать ускорение a₀. Теперь у нас есть все константы, чтобы вычислить пройденный путь s и скорость v (для проверки) объекта в любой момент времени t.

Поскольку вас интересует только движение на отрезке времени [t₀; t₁], то можно через каждые t₁ - t₀ секунд оборачивать время вспять. Например при помощи обратных тригонометрических функции (https://en.wikipedia.org/wiki/Inverse_trigonometric_functions).

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>

#grid {
position: relative;
width: 500px;
height: 500px;
background:
repeating-linear-gradient( 0deg, var(--r)),
repeating-linear-gradient(-90deg, var(--r));
--c: 5;
--w: 1px;
--r: transparent 0 var(--w), rgba(0, 0, 0, 0.05) 0 calc(100% / var(--c));
}

#grid > .circle {
width: 20px;
height: 20px;
background: yellowgreen;
border-radius: 50%;
margin: -10px 0 0 -10px;
position: absolute;
left: 50%;
}

#grid > .info::after {
position: absolute;
content: "v = " var(--v);
white-space: nowrap;
background: black;
color: white;
font: 1em monospace;
border-radius: 0.25em;
margin: 0.5em;
padding: 0.2em 0.5em;
right: 0;
top: 0;
}

</style>
</head>
<body>
<div id="grid">
<div class="info"></div>
<div class="circle"></div>
</div>

<script>

const v0 = 1;
const v1 = 5;

const s0 = 0;
const s1 = 5;

const t0 = 0;
const t1 = 2 * s1 / (v0 + v1);

const a0 = (v1 - v0) / (t1 - t0);

function s(t) {
return 0.5 * a0 * t ** 2 + v0 * t + s0;
}

function v(t) {
return a0 * t + v0;
}

function F(x) {
return t1 * (Math.acos(Math.cos(Math.PI * x / t1))) / Math.PI;
}

const circle = document.querySelector("#grid > .circle");
const info = document.querySelector("#grid > .info");
(function loop(time) {
circle.style.transform = `translateY(${100 * s(F(time / 1000))}px)`;
info.style.setProperty("--v", `"${v(F(time / 1000)).toFixed(2)}"`);

requestAnimationFrame(loop);
})(performance.now());

</script>
</body>
</html>

ЕЩЁ Упомянутые графики — https://www.desmos.com/calculator/dejdiypcao