任务是制作模拟下雨的下落矩形的动画,当矩形 - 喷气机接触地面 - 绘制星星时。为了实现它,有 3 个类:GitHub 存储库。
// Shapes:
class WaterJet { // falling rectangles
class RandomStar { // stars
//Each shape has
isAlive = true; // variable defines if shape still need o be rendered
draw(delta_ms) // method to draw shape obaining time from last draw
和引擎对数组中收集的所有形状进行动画处理
animatedItems
requestAnimationFrame
:
class AnimateBatch {
constructor() {
this.animatedItems = []; // Container to store entities to draw )
this.delta_ms = 0; // Delta between draw() methods run
}
//Method to animate batch of shapes
#animate(previousTime) {
const currentTime = performance.now();
this.delta_ms = previousTime ? currentTime - previousTime : 0;
// Draw and filter only "alive" shapes
this.animatedItems = this.animatedItems.filter((item) => {
item.draw(this.delta_ms);
return item.isAlive; // leave only shapes with isAlive=true
});
if (this.animatedItems.length > 0) {
this.requestId = requestAnimationFrame((newTime) => this.#animate(newTime));
形状动画的速度是在draw()方法中根据
delta_ms
(距离上次绘制剩余的时间)计算的,
我需要捕捉一个形状过期的时刻,并在此事件中添加新形状到
AnimateBatch.animatedItems:
function addStar(){
animateBatch.add(newStar);
}
麻烦来了,当按钮的监听器添加这个形状时就可以了:
buttonDo.addEventListener('click', function() {
addStar();
});
渲染形状内容的循环打印显示星星已添加并位于数组中:
0. AnimatedItem-1 : true
1. WaterJet-1 : true
2. Anisothermal.html:250 ______________star added RandomStar-1
0. AnimatedItem-1 : true
1. WaterJet-1 : true
2. RandomStar-1 : true <<----added
0. AnimatedItem-1 : true
1. WaterJet-1 : true
2. RandomStar-1 : true <<---- and remains
但是当从侦听器实现相同的功能时:
jets[i].OnJetOutOfBorder( () => {
addStar();
});
在形状的监听器中:
class RandomStar {
constructor(ctx, centerX, centerY, spikeLength = 2) {
this.OnStarGone = null;
}
draw(delta_ms) {
if(!this.isAlive) { // When shape already finish life: execute listener
// Implement litener when star is expired
if(this.OnStarGone)this.OnStarGone();
return;
}
addOnStarGone(callback){
this.OnStarGone = callback;
}
形状添加到数组中但从数组中消失:
0. AnimatedItem-1 : true
1. WaterJet-1 : true
0. AnimatedItem-1 : true
1. WaterJet-1 : true
2. Anisothermal.html:228 _____________________________listener________
0. AnimatedItem-1 : true
1. WaterJet-1 : true
2. RandomStar-5 : true <<-- it is added
2. Anisothermal.html:250 ______________star added RandomStar-5
0. AnimatedItem-1 : true
1. WaterJet-1 : true
0. AnimatedItem-1 : true <<---- And not in array any more
1. WaterJet-1 : true
0. AnimatedItem-1 : true
1. WaterJet-1 : true
结果令人非常失望,我怀疑我的动画方法是否正确?请帮助理解这种奇怪的双向行为
如何在动画过程中修改渲染形状列表?
为什么尽管根据时间段计算速度,但当用户使用界面(它还有一些其他控制器来修改飞行中的动画)时,动画会出现抖动,特别尖锐和干扰。同时:根据执行之间的时间差进行计算
requestAnimationFrame()
会产生巨大的误差。
我看到
requestAnimationFrame()
提供了相对较高的FPS每帧16-17ms,是否可以将其设置得较低以牺牲更新频率以牺牲性能?
构建无缝动画,可以在动画时添加和删除新形状以渲染列表。
关于您的问题清单中的 2 个问题: 你处理时间的方式是错误的。 requestAnimationFrame() 将当前时间传递到回调函数中,而不是之前的时间。您在一个地方调用它 newTime,然后调用 previousTime 并将其用作回调中的上一个时间。所以...
在构造函数中添加 previousTime 属性
this.previousTime = performance.now()
将回调中的参数名称更改为 currentTime
animate(currentTime) {
最后,适当更改 delta_ms 计算
this.delta_ms = currentTime - this.previousTime
this.previousTime = currentTime