【问题标题】:Draw function causes flicker - Javascript绘图功能导致闪烁 - Javascript
【发布时间】:2013-12-30 07:10:51
【问题描述】:

我在 6 个月前制作了一个乒乓球游戏,当时我的编程能力要差得多。唯一的问题是它像 CRAZY 一样闪烁,这对我来说毁了它。

这里是一些涉及画布的绘制和清除的代码,所以可能在闪烁的背后:

canvas: document.getElementById( "canvas" ),
    // Get our 2D context for drawing
    ctx: canvas.getContext( "2d" ),
    // Frames-per-second
    FPS: 30,

draw: function() {
        if (preGameContent.isStartScreen === false && endOfGame.isEndOfGame === false) {
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.Banana1.draw();
            this.Banana2.draw();
            this.Banana3.draw();
            this.displayScore();
            this.player1Paddle.draw();
            this.player2Paddle.draw();
            this.ball.draw();
        }
    }

update: function() {
        if (preGameContent.isStartScreen === false && endOfGame.isEndOfGame === false) {
            this.player1Paddle.updatePaddle();
            this.player2Paddle.updatePaddle();
            this.ball.updateBall();
            if (this.ball.x < 0) {
                if (this.is2PlayerGame === true) {
                    this.pointScored.startNextSet("player2");
                    this.setUp("right");
                }
                else {
                    this.pointScored.startNextSet("computer");
                    this.setUp("right");
                }
            }
            if (this.ball.x + this.ball.width > this.canvas.width) {
                gameController.pointScored.startNextSet("player1");
                this.setUp("left");
            }
        }
    }

tick: function() {
        if (preGameContent.isStartScreen === false
            && endOfGame.isEndOfGame === false) {
            gameController.draw();
            gameController.update();
        }
    }

setInterval( gameController.tick, 1000 / gameController.FPS );

您是否看到可以采取任何措施来减少闪烁?谢谢。

编辑

查看我是如何通过在其 draw 方法中创建一个新图像来重绘每个图像的:

//This class is to construct anything with an image
//vx and vy are for the velocity along the x and y axis
function Item(xStartPos, yStartPos, vx, vy, width, height, imgSrc) {
    this.x = xStartPos;
    this.y = yStartPos;
    this.vx = vx;
    this.vy = vy;
    this.width = width;
    this.height = height;
    this.imgSrc = imgSrc;
    //this function draws the image to the canvas
    this.draw = function() { 
        var self = this;
        var img = new Image();  
        img.src = self.imgSrc;  
        img.onload = function(){
            gameController.ctx.drawImage(img, self.x, self.y);  
        };
    };
    //this function updates the position of the object on the canvas
    this.update = function() {
        // Divide velocity by gameController.FPS before adding it
        // onto the position.
        this.x += this.vx / gameController.FPS;
        this.y += this.vy / gameController.FPS;
         // wall collision detection
         //stop the object from going through the top and bottom walls,
         //but not the side walls, so the ball can go through them
        if ( (this.y) < 0 ) {
            this.y = 0;
        }
        if ( (this.y + this.height) > gameController.canvas.height) {
            this.y = gameController.canvas.height - this.height;
        }
    };
};

编辑 所以我这样做了:

function Item(xStartPos, yStartPos, vx, vy, width, height, imgSrc) {

    this.x = xStartPos;
    this.y = yStartPos;
    this.vx = vx;
    this.vy = vy;
    this.width = width;
    this.height = height;
    this.img = new Image();
    this.imgSrc = imgSrc;
    this.img.src = imgSrc;
    //this.loaded = false;
    //img.onload = function() { this.loaded = true; }
    //this function draws the image to the canvas
    this.draw = function() { 
        //if (this.loaded) 
           gameController.ctx.drawImage(this.img, this.x, this.y);  
    };

这使得它可以很好地绘制所有项目,除了根本不绘制的桨和球

【问题讨论】:

    标签: javascript canvas flicker


    【解决方案1】:

    如果不查看整个解决方案,很难说它到底在哪里闪烁,但我会责怪setInterval()。要走的路是使用这里描述的requestAnimationFrame 技术:http://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/ 通过使用这个代码模板,我能够实现非常流畅的动画:

     window.requestAnimFrame = (function(callback) {
            return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
            function(callback) {
              window.setTimeout(callback, 1000 / 60);
            };
          })();
    
          function animate() {
            var canvas = document.getElementById('myCanvas');
            var context = canvas.getContext('2d');
    
            // update
    
            // clear
            context.clearRect(0, 0, canvas.width, canvas.height);
    
            // draw stuff
    
            // request new frame
            requestAnimFrame(function() {
              animate();
            });
          }
          animate();
    

    一般来说,setInterval() 相当糟糕,每次重新绘制后使用setTimeout(),因为间隔可能会在最糟糕的时间出现。

    请注意,根据所需的浏览器版本支持,您可能希望完全删除 setTimeout,因为 requestAnimationFrame 现在已得到普遍支持。

    更新 在代码中不使用额外工具的情况下,一个简单的图像加载修复方法是这样的,尽管它可能会运行一些动画循环,直到所有图像都被加载:

    function Item(.. imgSrc) {
       ...
        this.img = new Image();
        this.imgSrc = imgSrc;
        var self = this;
        this.loaded = false;
        img.onload = function() { self.loaded = true; }
    
        //this function draws the image to the canvas
        this.draw = function() { 
            if (this.loaded) 
               gameController.ctx.drawImage(this.img, this.x, this.y);  
        };
    

    【讨论】:

    • 是的,这似乎是一种更好的方法,谢谢。我还进行了编辑,这是一个可能导致问题的新发现。
    • 问题是您尝试在每次绘制时加载每个图像。很可能涉及到涉及到服务器的旅行,但至少是一些磁盘 I/O。您需要在动画开始之前预先缓存图像。如果您使用 jQuery,有一种方法可以使用观察者模式:stackoverflow.com/questions/476679/… 否则可能值得单独提出一个问题。
    • 谢谢。我发现使用构造函数创建对象后更容易理解创建图像。但我不能在 JavaScript 中做到这一点。在过去的 6 个月里,我一直在做 C#。我不确定这是否可能。
    • 检查我的答案的更新,它应该可以工作。最后的解决方法是调用所有图像构造函数,然后在所有Item 对象都具有loaded==true 时启动动画。
    猜你喜欢
    • 2012-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多