gpt4 book ai didi

javascript - 将缓动纳入基于时间的移动

转载 作者:行者123 更新时间:2023-12-03 00:02:54 24 4
gpt4 key购买 nike

我的目标是将缓动纳入我的项目中基于时间的移动中,并且可能需要一些帮助。

目前我正在使用每秒 x 像素的简单公式。

...
speed: 100,
now: undefined,
delta: undefined,
then: undefined,
setDelta: function() {
this.now = Date.now();
this.delta = (this.now - this.then) / 1000;
this.then = this.now;
},
...

var slice = this.speed * this.delta;
this.x += Math.cos(rad) * slice;
this.y += Math.sin(rad) * slice;

通过这样做,我的对象以每秒 100 像素的速度移动。然而,动画非常无聊,因此有一个想法,让它变得更有趣,让它开始缓慢,加速到一半距离,然后再次开始减速,直到到达目的地。

我找到了 javascript 缓动函数列表 click .

我认为看起来准确的应该是一些平滑的正弦,就像这样:

easeInOutSin: function (t) {
return (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;
}

问题是我无法弄清楚如何将此公式“连接”到我的代码(如上所述)。

在链接上,人们声称 t 是从 01 的参数,我认为可能需要改变的是速度。也许有人可以帮忙。

这是一个用于实验的演示片段:

let distance = (p) => Math.sqrt((p.x - p.dx) * (p.x - p.dx) + (p.y - p.dy) * (p.y - p.dy)),
rftv = (p) => Math.atan2(p.dy - p.y, p.dx - p.x);

let cvs = document.createElement('canvas'),
ctx = cvs.getContext('2d'),
w = cvs.width = 700,
h = cvs.height = 200,
cx = w / 2,
cy = h / 2;

let obj = {
x: 100,
y: cy,
speed: 100,
dx: 600,
dy: cy,
run: function() {
if(!this.moving) { return; }
let d = distance(this);
if(d < 1) {
this.end();
}
this.setDelta();
var slice = this.speed * this.delta;
let rad = rftv(this);
this.x += Math.cos(rad) * slice;
this.y += Math.sin(rad) * slice;
},
now: undefined,
delta: undefined,
then: undefined,
setDelta: function() {
this.now = Date.now();
this.delta = (this.now - this.then) / 1000;
this.then = this.now;
},
moving: false,
start: function() {
this._started_ = Date.now();
this.then = Date.now();
this.moving = true;
},
end: function() {
this.moving = false;
console.log( Date.now() - this._started_, 'should be close to 5000' );
}
};

let render = () => {
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);

ctx.beginPath();
ctx.arc(obj.x, obj.y, 10, 0, Math.PI * 2);
ctx.closePath();
ctx.strokeStyle = 'red';
ctx.stroke();
obj.run();

requestAnimationFrame(render);
};

document.body.appendChild(cvs);
render();

obj.start();

最佳答案

您选择的缓动函数只是时间的函数。这意味着它返回一个从 0 到 1 的比率,具体取决于时间,该时间也在 0 到 1 的范围内。这意味着您必须计算耗时与所需的总动画时间的比率。然后,要计算位置,您需要将返回的比率应用到您想要行驶的总距离 (this.dx - this.startX) 并将其添加到起始位置。

请注意,在下面的示例中,我忽略了您的 radthis.then 计算,我并没有真正明白您对 rad 的含义>,正如您所看到的,缓动必须是总移动距离和总动画时间的函数。因此,也没有速度的概念,或者您必须将其应用于总距离/动画时间。

let distance = (p) => Math.sqrt((p.x - p.dx) * (p.x - p.dx) + (p.y - p.dy) * (p.y - p.dy)),
rftv = (p) => Math.atan2(p.dy - p.y, p.dx - p.x),
easeInOutSin = function (t) {
return (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;
};

let cvs = document.createElement('canvas'),
ctx = cvs.getContext('2d'),
w = cvs.width = 700,
h = cvs.height = 200,
cx = w / 2,
cy = h / 2;

let obj = {
x: 100,
startX: 100,
y: cy,
//speed: 100,
dx: 600,
dy: cy,
run: function() {
if(!this.moving) { return; }
let d = distance(this);
if(d < 1) {
this.end();
}
this.setDelta();
/*var slice = this.speed * this.delta;
let rad = rftv(this);
this.x += Math.cos(rad) * slice;*/
this.x = this.startX + (this.delta * (this.dx - this.startX));
//this.y += Math.sin(rad) * slice;
},
now: undefined,
delta: undefined,
//then: undefined,
setDelta: function() {
this.now = Date.now();
this.delta = easeInOutSin( (this.now - this._started_) / 5000 ); //(this.now - this.then) / 1000;
//this.then = this.now;
},
moving: false,
start: function() {
this._started_ = Date.now();
this.then = Date.now();
this.moving = true;
},
end: function() {
this.moving = false;
console.log( Date.now() - this._started_, 'should be close to 5000' );
}
};

let render = () => {
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);

ctx.beginPath();
ctx.arc(obj.x, obj.y, 10, 0, Math.PI * 2);
ctx.closePath();
ctx.strokeStyle = 'red';
ctx.stroke();
obj.run();

if(obj.moving){ requestAnimationFrame(render); }
};

document.body.appendChild(cvs);

obj.start();

render();

这是第二个示例,具有更高级的缓动函数,改编自 this answer它有 4 个参数:耗时、开始值和结束值以及动画总时间。返回值直接是您的 x 位置。编辑:固定应用参数,应为 0 和总距离,然后将其添加到起始位置。

let distance = (p) => Math.sqrt((p.x - p.dx) * (p.x - p.dx) + (p.y - p.dy) * (p.y - p.dy)),
rftv = (p) => Math.atan2(p.dy - p.y, p.dx - p.x),
easeInOutSine = (t, startVal, endVal, totalTime) => (-endVal/2 * (Math.cos(Math.PI*t/totalTime) - 1) + startVal);

let cvs = document.createElement('canvas'),
ctx = cvs.getContext('2d'),
w = cvs.width = 700,
h = cvs.height = 200,
cx = w / 2,
cy = h / 2;

let obj = {
x: 100,
startX: 100,
y: cy,
//speed: 100,
dx: 600,
dy: cy,
run: function() {
if(!this.moving) { return; }
let d = distance(this);
if(d < 1) {
this.end();
}
this.setDelta();
/*var slice = this.speed * this.delta;
let rad = rftv(this);
this.x += Math.cos(rad) * slice;*/
this.x = this.startX + this.delta;
//this.y += Math.sin(rad) * slice;
},
now: undefined,
delta: undefined,
//then: undefined,
setDelta: function() {
this.now = Date.now();
this.delta = easeInOutSine((this.now - this._started_), 0, (this.dx - this.startX), 5000);//(this.now - this.then) / 1000;
//this.then = this.now;
},
moving: false,
start: function() {
this._started_ = Date.now();
this.then = Date.now();
this.moving = true;
},
end: function() {
this.moving = false;
console.log( Date.now() - this._started_, 'should be close to 5000' );
}
};

let render = () => {
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);

ctx.beginPath();
ctx.arc(obj.x, obj.y, 10, 0, Math.PI * 2);
ctx.closePath();
ctx.strokeStyle = 'red';
ctx.stroke();
obj.run();

if(obj.moving){ requestAnimationFrame(render); }
};

document.body.appendChild(cvs);

obj.start();

render();

希望您更好地理解它是如何工作的,祝你好运!

补充说明:我还颠倒了 obj.start();render(); 并向 requestAnimationFrame 添加了一个条件以避免无限循环。

关于javascript - 将缓动纳入基于时间的移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55097986/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com