requestAnimationFrame()多个对象的动画同步问题

问题描述 投票:0回答:1

任务是制作模拟下雨的下落矩形的动画,enter image description here当矩形 - 喷气机接触地面 - 绘制星星时。为了实现它,有 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

结果令人非常失望,我怀疑我的动画方法是否正确?请帮助理解这种奇怪的双向行为

  1. 如何在动画过程中修改渲染形状列表?

  2. 为什么尽管根据时间段计算速度,但当用户使用界面(它还有一些其他控制器来修改飞行中的动画)时,动画会出现抖动,特别尖锐和干扰。同时:根据执行之间的时间差进行计算

    requestAnimationFrame()
    会产生巨大的误差。

  3. 我看到

    requestAnimationFrame()
    提供了相对较高的FPS每帧16-17ms,是否可以将其设置得较低以牺牲更新频率以牺牲性能?

构建无缝动画,可以在动画时添加和删除新形状以渲染列表。

javascript animation graphics synchronization requestanimationframe
1个回答
0
投票

关于您的问题清单中的 2 个问题: 你处理时间的方式是错误的。 requestAnimationFrame() 将当前时间传递到回调函数中,而不是之前的时间。您在一个地方调用它 newTime,然后调用 previousTime 并将其用作回调中的上一个时间。所以...

在构造函数中添加 previousTime 属性

this.previousTime = performance.now()

将回调中的参数名称更改为 currentTime

animate(currentTime) {

最后,适当更改 delta_ms 计算

this.delta_ms = currentTime - this.previousTime
this.previousTime = currentTime
© www.soinside.com 2019 - 2024. All rights reserved.