1

I have a pong game that I made 6 months ago when I was much worse at programming. The only thing is it flickers like CRAZY, which ruins it for me.

Here is some code which is involved in the drawing and clearing of the canvas, so may be behind the flickering:

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 );

Do you see anything that can be done to this to reduce flicker? Thanks.

EDIT

Check out how i was redrawing each image every interval by creating a NEW image in its draw method:

//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;
        }
    };
};

EDIT So i did this:

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);  
    };

Which makes it draw all items nicely except the paddles and ball which do not draw at all

user2602079
  • 1,283
  • 5
  • 20
  • 39

1 Answers1

1

It is hard to say where exactly it flickers without looking at the whole solution, but I would blame setInterval(). The way to go is to use requestAnimationFrame technique described here: http://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/ I was able to achieve very smooth animations by using this code template:

 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();

In general, setInterval() is fairly bad, use setTimeout() after each re-draw, since interval might come at the worst timing possible.

Note, depending on required browser versions support, you might want to drop setTimeout alltogether, as requestAnimationFrame is universally supported by now.

Update A simple fix for the image loading without using extra tools within the code would be this, although it might run some animation cycles until all images will be loaded:

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);  
    };
Alex Pakka
  • 9,466
  • 3
  • 45
  • 69
  • Yes this seems very much a better way of doing it thank you. I have also made an edit which is a new discovery probably causing the problem. – user2602079 Dec 12 '13 at 02:45
  • 1
    The problem is that you try to load every image on every draw. Most probably there is a trip to a server involved, but at the very least some disc I/O. You need to pre-cache images before your animation starts. If you use jQuery, there is a way to do it with observer pattern: http://stackoverflow.com/questions/476679/preloading-images-with-jquery/10999147#10999147 otherwise it might be worth a separate question. – Alex Pakka Dec 12 '13 at 03:03
  • Thanks. I find it easier to understand creating the image once upon object creation using a constructor. But I couldn't do this in JavaScript. I have been doing C# for the last 6 months. I'm not sure it's even possible. – user2602079 Dec 12 '13 at 03:13
  • Check the update to my answer, it should work. The final fix would be to call all image constructors and then start animation once all `Item ` objects have `loaded==true`. – Alex Pakka Dec 12 '13 at 03:15