调整窗口大小后,画布动画速度加快

Canvas animation speeds up after window resized

本文关键字:动画 速度 窗口大小 布动画 调整      更新时间:2023-09-26

我有一个关于一些浮云和降落箱的画布动画:

var canvas, canvas_overlay, context, ctx_overlay, clouds, 
docWidth, docHeight, img_box, img_cloud1, img_cloud2, img_cloud3, img_ground;
img_box = new Image();
img_cloud1 = new Image();
img_cloud2 = new Image();
img_cloud3 = new Image();
img_ground = new Image();
img_box.src = 'images/gift_box_small.png';
img_cloud1.src = 'images/cloud1.png';
img_cloud2.src = 'images/cloud2.png';
img_cloud3.src = 'images/cloud3.png';
img_ground.src = 'images/ground_pattern_small.jpg';
var mustBeReadyCount = 6; // must load image and window
img_box.onload = launchWhenReady;
img_cloud1.onload = launchWhenReady;
img_cloud2.onload = launchWhenReady;
img_cloud3.onload = launchWhenReady;
img_ground.onload = launchWhenReady;
window.onload = launchWhenReady;
function launchWhenReady() {
    mustBeReadyCount--;
    if (mustBeReadyCount) return;
    init();
};
function init(){
    docWidth = window.innerWidth;
    docHeight =  window.innerHeight;
    canvas = document.getElementById('canvas');
    canvas_overlay = document.getElementById('canvas_overlay');
    context = canvas.getContext('2d');
    ctx_overlay = canvas_overlay.getContext('2d');
    resizeCanvas(docWidth, docHeight);
    drawGround();
    var cloud1 = new Cloud(0, 10, docWidth, docHeight, img_cloud1, 3, 24);
    var cloud2 = new Cloud(Math.floor(docWidth/4*3), 48, docWidth, docHeight, img_cloud2, 5, 24);
    var cloud3 = new Cloud(Math.floor(docWidth/2), 90, docWidth, docHeight, img_cloud3, 1, 24);
    clouds = [cloud1, cloud2, cloud3];
    boxAnimationData.animationStep = 'falling';
    boxAnimationData.bounceHeight = (docHeight / 2 - img_box.height)-25;
    setInterval(createAnimations, 24);
}
var animationStep = '';
var boxAnimationData = {
    animationStep: '',
    y: 0-img_box.naturalHeight,
    maxY: 0,
    bounceCount: 10,
    direction: -1,
    bounceHeight: 0
};
window.onresize = function(){
    init();
}
function resizeCanvas(width, height){        
    canvas.width = canvas_overlay.width = docWidth;
    canvas.height = canvas_overlay.height = docHeight;
}
function drawGround(){
    var pattern=context.createPattern(img_ground,"repeat");
    context.rect(0,docHeight-50,docWidth,50);
    context.fillStyle=pattern;
    context.fill();
}
function drawClouds(clouds, width, height){
    var img;
    var arrLength = clouds.length;
    context.clearRect(0,0,width,height-50);
    for(var i=0; i<arrLength; i++){
        var cloud = clouds[i];
        img = cloud.getFilename();
        imageWidth = img.naturalWidth;
        imageHeight = img.naturalHeight;
        context.drawImage(img, cloud.getX()-imageWidth, cloud.getY());
        clouds[i].moveCloud(imageWidth);
    }       
}
function createAnimations() {
    drawClouds(clouds, docWidth, docHeight);
    if (boxAnimationData.animationStep == 'falling') dropBox();
    else if (boxAnimationData.animationStep == 'bouncing') bounceBox();
}
function dropBox() {
    ctx_overlay.clearRect(0, 0, docWidth, docHeight);
    boxAnimationData.y += 3;
    if (boxAnimationData.y + img_box.height + 25 > docHeight) {
        boxAnimationData.animationStep = 'bouncing';
    }
    ctx_overlay.drawImage(img_box, (docWidth / 2) - (img_box.width / 2), boxAnimationData.y);
}

function bounceBox() {
    ctx_overlay.clearRect(0, 0, docWidth, docHeight);
    boxAnimationData.y += boxAnimationData.direction * 3;
    if (boxAnimationData.y + img_box.height + 25 > docHeight) {
        // reached floor? swap direction
        boxAnimationData.direction *= -1;
        //  and reduce jump height
        boxAnimationData.bounceHeight *= 10 / 9;
        boxAnimationData.bounceCount--;
        if (!boxAnimationData.bounceCount) boxAnimationData.animationStep = '';
    } else if (boxAnimationData.y < boxAnimationData.bounceHeight) {
        boxAnimationData.direction *= -1;
    }
    ctx_overlay.drawImage(img_box, (docWidth / 2) - (img_box.width / 2), boxAnimationData.y);
}
function Cloud (x, y, width, height, filename, velocity, rate) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.filename = filename;
    this.velocity = velocity;
    this.rate = rate;
}
Cloud.prototype = {
    constructor:Cloud,
    moveCloud:function(imageWidth){
        if(this.x >= this.width+imageWidth){
            this.x=0-imageWidth/2;
        } else {
            this.x += this.velocity;
        }
    },
    getFilename:function(){
        return this.filename;
    },
    getX:function(){
        return this.x;
    },
    getY:function(){
        return this.y;
    }
}   

你可以在这里观看直播:http://jsfiddle.net/f2pd36yq/

调整窗口大小时(浏览器窗口或移动设备更改方向),我希望重新启动动画,或者最好从同一点继续,但云和框应该获得新的文档宽度和高度。此外,如果长方体已停止在底部,则不应再次为其设置动画。但我现在看到的是一些奇怪的动画在调整窗口大小时加速了。

为什么会发生这种情况,如何解决?

每次调整大小时都会触发init函数,因此每次调整大小事件都会再次触发函数底部的setInterval(createAnimations, 24);

要解决此问题,只需将setInterval移到init函数之外,或者只在实际初始化时调用init,并在调整大小时使用单独的函数更新其他变量

我有同样的问题,但有不同的实现,我只是通过在窗口大小调整时调用requestAnimationFrame(render)而不是函数render本身来解决这个问题

function render {
    ...
}
requestAnimationFrame(render)
window.addEventListener('resize', requestAnimationFrame(render))

它将向animationFrame堆栈添加渲染功能,并且不会加速场景本身