Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML 5 Canvas elements not animating correctly in a .setInterval method

The code will render the animation with one of the "boxes" , but acts very strangely when two of the "boxes" are drawn within the setInterval method. I suspect this may have something to do with ctx.clearRect.

JS Fiddle

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
var raf;
var switchDirection = [true, true];

function alien() {

  if (canvas.getContext) {

    function Spaceships(x) {
      this.x = x;
      this.y = 100;
      this.color = 'rgb(192, 192, 192)';

      this.draw = function() {
        ctx.beginPath();
        ctx.rect(this.x, this.y, 100, 100);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();
      };
    };

    var alienOne = new Spaceships(100);
    var alienTwo = new Spaceships(500);

    alienOne.draw();
    alienTwo.draw();

    setInterval(function redraw() {

      if (alienOne.x == 200) {
        switchDirection[0] = false;
      } else if (alienOne.x == 100) {
        switchDirection[0] = true;
      }

      if (switchDirection[0] == true) {
        ctx.clearRect(0, 0, 0, 0);
        alienOne.draw();
        alienOne.x += 10;
      } else if (switchDirection[0] == false) {
        ctx.clearRect(0, 0, 0, 0);
        alienOne.draw();
        alienOne.x -= 10;
      }

      if (alienTwo.x == 600) {
        switchDirection[1] = false;
      } else if (alienTwo.x == 500) {
        switchDirection[1] = true;
      }

      if (switchDirection[1] == true) {
        ctx.beginPath();
        ctx.clearRect(0, 0, 0, 0);
        alienTwo.draw();
        alienTwo.x += 10;
      } else if (switchDirection[1] == false) {
        ctx.beginPath();
        ctx.clearRect(0, 0, 0, 0);
        alienTwo.draw();
        alienTwo.x -= 10;
      }

    }, 250);

  } else {
    alert('you need a better browser to play this game')
  }
};
alien();

I have tried placing the second box in its own .setInterval. The animation renders incorrectly by not properly adjusting its width.

Any help would be greatly appreciated.

like image 812
Michael Avatar asked Jul 19 '26 02:07

Michael


1 Answers

I fixed your problem, and refactored some of your code:

  • The main problem was the clearing of the canvas with the clearRect method. You didn't specify the right parameter values.
  • Some of the code is very repetitive. For now this isn't really a problem since you're only using 2 aliens, however this could become a problem once you have more than two. Imagine writing almost identical code for 40 aliens. This is solved with arrays and for-loops. Also, you use a boolean variable to determine when to add/substract from the alienX. This too can become quite a hassle. Now, we check when the spaceships exceed/go below the tolerated x-value, and change the sign of your velocity accordingly.
  • As mentioned by @Kaiido in the comments above, you can use requestAnimationFrame for your animations, which is better for this project than setInterval. To maintain the choppy animation effect, I used a really basic counter, with the % operator to only execute the code every 4x in a second (usually, reqAnimFrame callbacks 60x per second, so 60/15 = 4, equal to 250ms in your example) (see below).

The code:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var aliens = [];
var counter = 0;

function alien() {

  if (canvas.getContext) {

    function Spaceships(x) {
      this.baseX = x; // added a baseX to remember where the spaceship started off
      this.x = x;
      this.y = 100;
      this.velocityX = 10;
      this.color = "rgb(192, 192, 192)";

      this.draw = function() {
        ctx.beginPath();
        ctx.rect(this.x, this.y, 100, 100);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();
      }
    }

    aliens.push(new Spaceships(100), new Spaceships(500));
    drawAllAliens();

    function redraw() {

      requestAnimationFrame(redraw);

      var maxXDiff = 100; //choose how far or near your aliens/squares can go
      counter ++;

      // remainder/modulo operator: 
      // reduce animation to every 4x per sec for that "choppy" animation
      if(counter%15 === 0){
        for (var i = 0; i < aliens.length; i ++) {
          if ( ( (aliens[i].baseX + maxXDiff) < aliens[i].x ) || (aliens[i].baseX > aliens[i].x) ) {
            aliens[i].velocityX = -aliens[i].velocityX; // switches the sign
          }
          aliens[i].x += aliens[i].velocityX;
        }
      }

      drawAllAliens();
    }

    redraw();

    function drawAllAliens() {
      ctx.clearRect(0,0,canvas.width,canvas.height);

      for (var i = 0; i < aliens.length; i++) {
        aliens[i].draw();
      }
    }

  } else {
    alert("you need a better browser to play this game");
  }
}

alien();
like image 123
Sven Avatar answered Jul 20 '26 15:07

Sven



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!