Solution 1 :

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>Howling at the Moon</title>
</head>

<body onload="init();">

  <canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
  <script type="text/javascript">
    var canvas, ctx;

    function init() {
      var canvas = document.getElementById('myCanvas');
      var ctx = canvas.getContext('2d');
      window.addEventListener('keydown', handleKeydown, false);
      window.addEventListener('keyup', handleKeyup, false);
      drawMonster(260, 260);
      drawMoon(100, 100);
      drawCloud(150, 175);

      function handleKeydown(evt) {
        if (evt.keyCode === 37) {
          //left key 
          incrementX = -1;
        } else if (evt.keyCode === 39) {
          // right key
          incrementX = 1;
        }
      }

      function drawMonster(x, y) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(740, 750, 175, 0, Math.PI / .5);
        ctx.fillStyle = "lightgrey";
        ctx.fill();
        ctx.lineWidth = 3;
        ctx.stroke();
        //mouth1
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 350, y + 550, 200, 20);
        //mouth2
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 375, y + 540, 150, 20);
        //mouth3
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 375, y + 560, 150, 20);
        ctx.restore();
        //eyes
        addShadows2();
        ctx.fillStyle = 'lightslategrey'
        ctx.fillRect(x + 350, y + 400, 40, 40);
        ctx.fillRect(x + 450, y + 400, 40, 40);
        //pupil
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 350, y + 400, 20, 20);
        ctx.fillRect(x + 450, y + 400, 20, 20);
      }
      
      function animateMoon()
      {
        ctx.clearArc(0,0,canvas.width,canvas.height);
        drawMoon(x,y);
        requestId = requestAnimationFrame(animateMoon);
      }
      
      //moon
      function drawMoon(x, y) {
        ctx.beginPath();
        ctx.arc(100, 75, 150, 0, Math.PI / .5);
        ctx.fillStyle = "lightgrey";
        addShadows();
        ctx.fill();
        ctx.lineWidth = 3;
        ctx.stroke();
      }
      //cloud
      function drawCloud(x, y) {
        ctx.beginPath();
        ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
        ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
        ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
        ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
        ctx.moveTo(x + 200, y + 60);
        ctx.lineTo(x, y + 60);
        ctx.strokeStyle = "#797874";
        ctx.stroke();
        ctx.fillStyle = "lightslategrey";
        ctx.fill();
      }

      function addShadows() {
        ctx.shadowColor = "beige"; // color
        ctx.shadowBlur = 160; // blur level
        ctx.shadowOffsetX = 15; // horizontal offset
        ctx.shadowOffsetY = 15; // vertical offset
      }

      function addShadows2() {
        ctx.shadowColor = "black";
        ctx.shadowBlur = 40;
        ctx.shadowOffsetX = 15;
        ctx.shadowOffsetY = 10;
      }

      function addShadows3() {
        ctx.shadowColor = "beige";
        ctx.shadowBlur = 160;
        ctx.shadowOffsetX = 10;
        ctx.shadowOffsetY = 10;
      }

      function start() {
        // Start the animation loop, targets 60 frames/s
        requestId = requestAnimationFrame(animationLoop);
      }

      function stop() {
        if (requestId) {
          cancelAnimationFrame(requestId);
        }
      }
  </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>Howling at the Moon</title>
</head>

<body onload="init();">

  <canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
  <script type="text/javascript">
    var canvas, ctx;

    function init() {
      var canvas = document.getElementById('myCanvas');
      var ctx = canvas.getContext('2d');
      window.addEventListener('keydown', handleKeydown, false);
      window.addEventListener('keyup', handleKeyup, false);
      drawMonster(260, 260);
      drawMoon(100, 100);
      drawCloud(150, 175);

      function handleKeydown(evt) {
        if (evt.keyCode === 37) {
          //left key 
          incrementX = -1;
        } else if (evt.keyCode === 39) {
          // right key
          incrementX = 1;
        }
      }

      function drawMonster(x, y) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(740, 750, 175, 0, Math.PI / .5);
        ctx.fillStyle = "lightgrey";
        ctx.fill();
        ctx.lineWidth = 3;
        ctx.stroke();
        //mouth1
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 350, y + 550, 200, 20);
        //mouth2
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 375, y + 540, 150, 20);
        //mouth3
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 375, y + 560, 150, 20);
        ctx.restore();
        //eyes
        addShadows2();
        ctx.fillStyle = 'lightslategrey'
        ctx.fillRect(x + 350, y + 400, 40, 40);
        ctx.fillRect(x + 450, y + 400, 40, 40);
        //pupil
        ctx.fillStyle = 'black'
        ctx.fillRect(x + 350, y + 400, 20, 20);
        ctx.fillRect(x + 450, y + 400, 20, 20);
      }

      function animateMoon() {
        ctx.clearArc(0, 0, canvas.width, canvas.height);
        drawMoon(x, y);
        requestId = requestAnimationFrame(animateMoon);
      }

      //moon
      function drawMoon(x, y) {
        ctx.beginPath();
        ctx.arc(100, 75, 150, 0, Math.PI / .5);
        ctx.fillStyle = "lightgrey";
        addShadows();
        ctx.fill();
        ctx.lineWidth = 3;
        ctx.stroke();
      }
      //cloud
      function drawCloud(x, y) {
        ctx.beginPath();
        ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
        ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
        ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
        ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
        ctx.moveTo(x + 200, y + 60);
        ctx.lineTo(x, y + 60);
        ctx.strokeStyle = "#797874";
        ctx.stroke();
        ctx.fillStyle = "lightslategrey";
        ctx.fill();
      }

      function addShadows() {
        ctx.shadowColor = "beige"; // color
        ctx.shadowBlur = 160; // blur level
        ctx.shadowOffsetX = 15; // horizontal offset
        ctx.shadowOffsetY = 15; // vertical offset
      }

      function addShadows2() {
        ctx.shadowColor = "black";
        ctx.shadowBlur = 40;
        ctx.shadowOffsetX = 15;
        ctx.shadowOffsetY = 10;
      }

      function addShadows3() {
        ctx.shadowColor = "beige";
        ctx.shadowBlur = 160;
        ctx.shadowOffsetX = 10;
        ctx.shadowOffsetY = 10;
      }

      function start() {
        // Start the animation loop, targets 60 frames/s
        requestId = requestAnimationFrame(animationLoop);
      }

      function stop() {
        if (requestId) {
          cancelAnimationFrame(requestId);
        }
      }
  </script>
</body>

</html>

Solution 2 :

There were several issues in your code and I’ll share the changes I made to get the animation to work.

Errors

In your animationLoop, you referenced a variable named context which I believe you meant to reference ctx instead.

  context.globalCompositeOperation = 'destination-out'

I can’t say I’ve used this property of the CanvasRenderingContext2D, but I didn’t notice any positive effects it produced for your code and the resulting animation. I first changed it to ctx.globalCompositeOperation and eventually removed it.

Another error was that you were declaring ctx and canvas in your init function even though you had variables declared outside the function. I opted to remove the declaration and just make it an assignment instead:

  canvas = document.getElementById("myCanvas");
  ctx = canvas.getContext("2d");

With these changes, the initial errors were resolved.

Issues

In init the shapes are drawn on the canvas and we have two identical lines using requestAnimationFrame:

  requestId = requestAnimationFrame(animationLoop);
  drawMoon(moonx, moony, moonAngle, "green", "yellow");
  moonx += incrementX;
  requestId = requestAnimationFrame(animationLoop);

I removed the first one (also removing the requestId assignment as it didn’t seem necessary). Then, in order for the animationLoop to continue to animate, we need to call requestAnimationFrame(animationLoop) inside of the animationLoop function.

function animationLoop() {
  // ...
  requestAnimationFrame(animationLoop);
}

Then, in order to actually draw the shapes in each call of animationLoop, I moved the draw<shape> function calls inside of animationLoop. Also, we want to clear the canvas each time we draw on it to properly animate our shapes, so we’ll need to use .clearRect. Now the animationLoop looks like this:

  function animationLoop() {
    moonx += incrementX;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawMonster(260, 260);
    drawCloud(150, 175);
    drawMoon(moonx, moony, moonAngle, "green", "yellow");
    requestAnimationFrame(animationLoop);
  }

But the final reason the moon won’t move when we press the left or right arrows is that we’re not actually using the moonx and moony variables when drawing the moon. So, in drawMoon, instead of

ctx.arc(100, 75, 150, 0, Math.PI / .5);

this should be changed to the following

ctx.arc(moonx, moony, 150, 0, Math.PI / 0.5);

I believe I covered all of the major issues with your code to be able to draw all the shapes and move the moon with the left and right arrows. See the full code example below.

var canvas, ctx;
var moonx = 0;
var moony = 0;
var moonAngle = 0;
var incrementX = 0;

function init() {
  canvas = document.getElementById("myCanvas");
  ctx = canvas.getContext("2d");
  window.addEventListener("keydown", handleKeydown, false);
  window.addEventListener("keyup", handleKeyup, false);
  requestAnimationFrame(animationLoop);

  function handleKeydown(evt) {
    if (evt.keyCode === 37) {
      incrementX = -1;
    } else if (evt.keyCode === 39) {
      incrementX = 1;
    }
  }

  function handleKeyup(evt) {
    incrementX = 0;
  }

  function animationLoop() {
    moonx += incrementX;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawMonster(260, 260);
    drawCloud(150, 175);
    drawMoon(moonx, moony, moonAngle, "green", "yellow");
    requestAnimationFrame(animationLoop);
  }
}

function drawMonster(x, y) {
  ctx.save();
  ctx.beginPath();
  ctx.arc(740, 750, 175, 0, Math.PI / 0.5);
  ctx.fillStyle = "lightgrey";
  ctx.fill();
  ctx.lineWidth = 3;
  ctx.stroke();
  //mouth1
  ctx.fillStyle = "black";
  ctx.fillRect(x + 350, y + 550, 200, 20);
  //mouth2
  ctx.fillStyle = "black";
  ctx.fillRect(x + 375, y + 540, 150, 20);
  //mouth3
  ctx.fillStyle = "black";
  ctx.fillRect(x + 375, y + 560, 150, 20);
  ctx.restore();
  //eyes
  addShadows2();
  ctx.fillStyle = "lightslategrey";
  ctx.fillRect(x + 350, y + 400, 40, 40);
  ctx.fillRect(x + 450, y + 400, 40, 40);
  //pupil
  ctx.fillStyle = "black";
  ctx.fillRect(x + 350, y + 400, 20, 20);
  ctx.fillRect(x + 450, y + 400, 20, 20);
}
//moon
function drawMoon(moonx, moony) {
  ctx.beginPath();
  ctx.arc(moonx, moony, 150, 0, Math.PI / 0.5);
  ctx.fillStyle = "lightgrey";
  addShadows();
  ctx.fill();
  ctx.lineWidth = 3;
  ctx.stroke();
}
//cloud
function drawCloud(x, y) {
  ctx.beginPath();
  ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
  ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
  ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
  ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
  ctx.moveTo(x + 200, y + 60);
  ctx.lineTo(x, y + 60);
  ctx.strokeStyle = "#797874";
  ctx.stroke();
  ctx.fillStyle = "lightslategrey";
  ctx.fill();
}

function addShadows() {
  ctx.shadowColor = "beige"; // color
  ctx.shadowBlur = 160; // blur level
  ctx.shadowOffsetX = 15; // horizontal offset
  ctx.shadowOffsetY = 15; // vertical offset
}

function addShadows2() {
  ctx.shadowColor = "black";
  ctx.shadowBlur = 40;
  ctx.shadowOffsetX = 15;
  ctx.shadowOffsetY = 10;
}

function addShadows3() {
  ctx.shadowColor = "beige";
  ctx.shadowBlur = 160;
  ctx.shadowOffsetX = 10;
  ctx.shadowOffsetY = 10;
}
init();
<canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>

Problem :

I’m trying to create simple animation to take the moon that I have drawn behind the clouds and allow users to move it across the x axis in the canvas. I have seen where others have done this with rectangles, and I have seen where their code seems basic enough for my inexperience to follow… but I’m struggling a bit with my code.

Every time I put code in that I think will work, it wipes out the canvas… which means I have placement and structural issues… but I’m having trouble figuring out where and how.

Can someone help me figure out how to animate my drawMoon so that it will move across the x axis when the left and right arrow keys are used?

NOTE I have tried using event listeners for keydown and keyup, but I’m sure I’m doing it wrong.

Attaching code that has nothing included so that you all have the base code without the animation attempt.

Any help is appreciated.

UPDATE I think I broke it more….. thoughts?

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>Howling at the Moon</title>
</head>

<body onload="init();">

  <canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
  <script type="text/javascript">
    
    var canvas, ctx;
    var moonx = 0;
    var moony = 0;
    var moonAngle = 0;
    var incrementX = 0;

    function init() {
      var canvas = document.getElementById("myCanvas");
      var ctx = canvas.getContext("2d");
      window.addEventListener("keydown", handleKeydown, false);
      window.addEventListener("keyup", handleKeyup, false);
      drawMonster(260, 260);
      drawMoon(100, 100);
      drawCloud(150, 175);
      requestId = requestAnimationFrame(animationLoop);

      function handleKeydown(evt) {
        if (evt.keyCode === 37) {
          incrementX = -1;
        } else if (evt.keyCode === 39) {
          incrementX = 1;
        }
      }

      function handleKeyup(evt) {
        incrementX = 0;
      }

      function animationLoop() {
        context.globalCompositeOperation = 'destination-out'
      }
      drawMoon(moonx, moony, moonAngle, "green", "yellow");
      moonx += incrementX;
      requestId = requestAnimationFrame(animationLoop);
    }

    function drawMonster(x, y) {
      ctx.save();
      ctx.beginPath();
      ctx.arc(740, 750, 175, 0, Math.PI / 0.5);
      ctx.fillStyle = "lightgrey";
      ctx.fill();
      ctx.lineWidth = 3;
      ctx.stroke();
      //mouth1
      ctx.fillStyle = "black";
      ctx.fillRect(x + 350, y + 550, 200, 20);
      //mouth2
      ctx.fillStyle = "black";
      ctx.fillRect(x + 375, y + 540, 150, 20);
      //mouth3
      ctx.fillStyle = "black";
      ctx.fillRect(x + 375, y + 560, 150, 20);
      ctx.restore();
      //eyes
      addShadows2();
      ctx.fillStyle = "lightslategrey";
      ctx.fillRect(x + 350, y + 400, 40, 40);
      ctx.fillRect(x + 450, y + 400, 40, 40);
      //pupil
      ctx.fillStyle = "black";
      ctx.fillRect(x + 350, y + 400, 20, 20);
      ctx.fillRect(x + 450, y + 400, 20, 20);
    }
    //moon
    function drawMoon(moonx, moony) {
      ctx.beginPath();
      ctx.arc(100, 75, 150, 0, Math.PI / 0.5);
      ctx.fillStyle = "lightgrey";
      addShadows();
      ctx.fill();
      ctx.lineWidth = 3;
      ctx.stroke();
    }
    //cloud
    function drawCloud(x, y) {
      ctx.beginPath();
      ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
      ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
      ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
      ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
      ctx.moveTo(x + 200, y + 60);
      ctx.lineTo(x, y + 60);
      ctx.strokeStyle = "#797874";
      ctx.stroke();
      ctx.fillStyle = "lightslategrey";
      ctx.fill();
    }

    function addShadows() {
      ctx.shadowColor = "beige"; // color
      ctx.shadowBlur = 160; // blur level
      ctx.shadowOffsetX = 15; // horizontal offset
      ctx.shadowOffsetY = 15; // vertical offset
    }

    function addShadows2() {
      ctx.shadowColor = "black";
      ctx.shadowBlur = 40;
      ctx.shadowOffsetX = 15;
      ctx.shadowOffsetY = 10;
    }

    function addShadows3() {
      ctx.shadowColor = "beige";
      ctx.shadowBlur = 160;
      ctx.shadowOffsetX = 10;
      ctx.shadowOffsetY = 10;
    }
  </script>
</body>

</html>

Comments

Comment posted by phentnil

Your code currently works at drawing the shapes. Can you share your animation attempt? At least enough to be able to reproduce the problem.

Comment posted by epauze

Sure…. see new code added.

Comment posted by edit

Your answer could be improved with additional supporting information. Please

Comment posted by phentnil

It would be best to

Comment posted by epauze

Excellent. I will try. Ty Phentnil

Comment posted by epauze

Updated OP with added code…. but I still cant seem to get it right…. frustrating.

Comment posted by epauze

Thanks again for your wonderful feedback and guidance. I really do appreciate your efforts to help me understand and the excellent write up @phentnil

By