繁体   English   中英

无法使用 javascript 为元素的多个实例设置动画。 只会执行第一个动画

[英]Can´t animate multiple instances of an element with javascript. Only the first animation will be executed

我创建了一个名为 Particlel 的元素。 此元素的单个动画也有效。 但是一旦我尝试运行多个动画,只会执行一个动画。 我认为问题是 requestAnimationFrame(this.animate.bind(this)) 调用,但我不知道如何更改它以一次接受多个动画。 任何想法如何解决这一问题?

js代码

//gloabl vars
let particels = [];
let numberParticels = 120;
let canvas; 
let ctx;
let title;
let mesaureTitle;
let boundRadius;
let animations;

window.onload = function () {
    this.init();
    for(let i = 0; i < numberParticels; i++){
        particels[i].update();
        particels[i].draw();
        particels[i].animate(0);
    }
  
}

function init(){
    canvas = document.getElementById("c");
    ctx = canvas.getContext("2d");
    title = document.getElementById("title");
    mesaureTitle = title.getBoundingClientRect();
    bound = {
        x: mesaureTitle.x,
        y: mesaureTitle.y,
        width: mesaureTitle.width,
        height: mesaureTitle.height,
    };
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    for(let i = 0; i < numberParticels; i++){
        let x = Math.floor(Math.random() * window.innerWidth);
        let y = Math.floor(Math.random() * window.innerHeight);
        let size = Math.floor(Math.random() * 25) + 3;
        let weight = Math.floor(Math.random() * 11) + 2;
        particels.push(new Particel(x, y, size, weight));
    }
}

class Particel {
    constructor (x,y,size, weight) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.directionX = 0.15332;
        this.resetWeight = weight;
        this.weight = weight;
        this.lastTime = 0;
        this.interval = 1000/60;
        this.timer = 0;
    }

    update(){
        this.weight += 0.02;
        this.y = this.y + this.weight;
        this.x += this.directionX;
        //check for collision with textField
        if (this.x < bound.x + bound.width
            && this.x + this.size > bound.x &&
            this.y < bound.y + bound.height &&
            this.y + this.size > bound.y) {
                this.y -= 3;
                this.weight *= -0.3;
        }
    }

    draw(){
        if(this.y > canvas.height){
            this.y = 0 - this.size;
            this.weight = this.resetWeight;
            //create random start point
            this.x = Math.floor(Math.random() * canvas.width);
        }
          ctx.fillStyle = "rgb(0, 180, 97)";
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
          ctx.closePath();
          ctx.fill();
    }

    animate(timeStamp){
        const deltaTime = timeStamp - this.lastTime;
        this.lastTime = timeStamp;
        if(this.timer > this.interval){
            ctx.clearRect(0,0, canvas.width, canvas.height);
            this.update();
            this.draw();
            this.timer = 0;
        }else {
            this.timer += deltaTime;
        }
        ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
        requestAnimationFrame(this.animate.bind(this));
    }
}```

主要问题是清除每个粒子的animate方法内的画布。 因此,如果您绘制多个粒子,则每次粒子update调用都会清除画布,覆盖之前的粒子数据,只保留最后一个粒子可见。

您可以尝试删除

ctx.clearRect(0,0, canvas.width, canvas.height);

从它所在的位置开始,并在init创建一个createAnimationFrame回调以在动画粒子之前清除画布:

function init() {
    // ....

   requestAnimationFrame( ()=> ctx.clearRect(0,0, canvas.width, canvas.height));
   // existing for loop:
   for(let i = 0; i < numberParticels; i++){
   // ... .
}

但是,这会创建(一加粒子数)对动画帧的请求。 一个更好的解决办法是从移除请求动画帧Particel类和创建单个requestAnimationFrame回调其穿过particels数组,并调用一类方法来重绘与更新的位置在画布上每个颗粒。


此外,该代码在严格模式下会生成一个错误,即尚未声明bound 我建议在全局范围内声明它,而不是依赖于草率模式 JavaScript 将其创建为window属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM