Search code examples
javascripthtmlcanvasflashing

Javascript Canvas Flashing When Drawing Frames


Been having issues with this for a couple days, not sure why the text I'm rendering on the canvas is flashing so much. I'm using the requestAnimationFrame() function, but its still flickering.

What I want to have happen is for the text to move smoothly and they remove themselves from the array when they move completely off screen.

var canvas = document.getElementById("myCanvas");

var c = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var w = canvas.width;
var h = canvas.height;

var texts = [];

window.addEventListener("load", init);

function init() {
    draw();
    mainLoop();
}


function mainLoop() {
    texts.push(createText("wow", "blue"));
    texts.push(createText("wow", "green"));
    texts.push(createText("wow", "red"));
    setTimeout(function() { mainLoop(); }, 100);
}

function Text(x, y, vx, vy, varText, theColor){
    this.x = x;
    this.y = y;
    this.vx = vx;
    this.vy = vy;
    this.color = theColor;
    this.draw = function() {
        drawStroked(varText, this.x, this.y, this.color);
    }
}

function drawStroked(text, x, y, color) {
    c.font = "30px bold Comic Sans MS";
    c.strokeStyle = 'black';
    c.lineWidth = 8;
    c.strokeText(text, x, y);
    c.fillStyle = color;
    c.fillText(text, x, y);
}

function createText(varText, color) {
    var x = (Math.random() * w / 2 ) + w/4;
    var y = (Math.random() * h / 2) + h/2;
    var vx = (Math.random() * .5) - .25
    var vy = -(Math.random() * 3) - 1

    return new Text(x, y, vx, vy, varText, color);
}

function draw() {
    c.clearRect(0, 0, c.canvas.width, c.canvas.height);
    for(var i = 0;i < texts.length; i++) {
        var currentText = texts[i];
        currentText.x += currentText.vx;
        currentText.y += currentText.vy;
        currentText.draw();

        if(currentText.x>w||currentText.x<0||currentText.y<10){
            texts.splice(i, 1);
        }
    }

    requestAnimationFrame(draw);
}
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}
<!DOCTYPE html>
<html>
<head>
  <title>Game Screen</title>
</head>
<body>

<canvas id="myCanvas"></canvas>

</body>
</html>


Solution

  • The flickering you are seeing results from your looping code, where you skip elements of the array when deleting elements (Element 3 needs to be deleted? You call splice(3, 1) and then continue with the loop at index 4. Since the array shifts when you call splice, you should process element 3 again). The imho easiest way to fix this is to iterate backwards over the array. Please note that iterating backwards is less CPU cache efficient (because every array access leads to a cache miss), so another fix would be

    if(currentText.x>w||currentText.x<0||currentText.y<10){
                texts.splice(i--, 1); // decrement i after accessing and deleting
    }
    

    var canvas = document.getElementById("myCanvas");
    
    var c = canvas.getContext('2d');
    
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    var w = canvas.width;
    var h = canvas.height;
    
    var texts = [];
    
    window.addEventListener("load", init);
    
    function init() {
        draw();
        mainLoop();
    }
    
    
    function mainLoop() {
        texts.push(createText("wow", "blue"));
        texts.push(createText("wow", "green"));
        texts.push(createText("wow", "red"));
        setTimeout(function() { mainLoop(); }, 100);
    }
    
    function Text(x, y, vx, vy, varText, theColor){
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.color = theColor;
        this.draw = function() {
            drawStroked(varText, this.x, this.y, this.color);
        }
    }
    
    function drawStroked(text, x, y, color) {
        c.font = "30px bold Comic Sans MS";
        c.strokeStyle = 'black';
        c.lineWidth = 8;
        c.strokeText(text, x, y);
        c.fillStyle = color;
        c.fillText(text, x, y);
    }
    
    function createText(varText, color) {
        var x = (Math.random() * w / 2 ) + w/4;
        var y = (Math.random() * h / 2) + h/2;
        var vx = (Math.random() * .5) - .25
        var vy = -(Math.random() * 3) - 1
    
        return new Text(x, y, vx, vy, varText, color);
    }
    
    function draw() {
        c.clearRect(0, 0, c.canvas.width, c.canvas.height);
        for(var i = texts.length - 1;i >= 0; i--) {
            var currentText = texts[i];
            currentText.x += currentText.vx;
            currentText.y += currentText.vy;
            currentText.draw();
    
            if(currentText.x>w||currentText.x<0||currentText.y<10){
                texts.splice(i, 1);
            }
        }
    
        requestAnimationFrame(draw);
    }
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
    <!DOCTYPE html>
    <html>
    <head>
      <title>Game Screen</title>
    </head>
    <body>
    
    <canvas id="myCanvas"></canvas>
    
    </body>
    </html>