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

时间:2014-10-15 16:46:17

标签: javascript canvas html5-canvas

我有一些浮动云和下降框的画布动画:

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/

当调整窗口大小(浏览器窗口或移动设备更改方向)时,我要么重新启动动画,要么最好从同一点继续,但云和框应该获得新文档宽度和高度。此外,如果框已经停在底部,则不应再次设置动画。但我现在所拥有的是一些奇怪的动画在调整窗口大小时加速。

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

我遇到了同样的问题,但实现方式不同, 我只是通过在窗口调整大小上调用 requestAnimationFrame(render) 而不是函数本身来解决它

function render {
    ...
}

requestAnimationFrame(render)

window.addEventListener('resize', requestAnimationFrame(render))

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