javascripthtmlcanvasdrawingxor

Drawing in JavaScript / HTML5 using XOR to remove old sprite


I'm building the engine for a tiny game, and right now I have just got a red circle with two little eyes as a main character. I have keyPress functions to detect movement, and that works, but I wanted to use something I used a long time ago in QBASIC to remove the character and redraw at a new location: XOR

Basically, on keypress this happens:

if (code == 39) {
    mainChar.drawChar();
    mainChar.x += 1;
    mainChar.leftEye.x += 1;
    mainChar.rightEye.x += 1;
    mainChar.drawChar();
}

I thought drawing the character on the same space, then adjusting the positions and drawing again would remove the first instance and draw a new one. Here is a snippet of my drawChar method:

  context.beginPath();
  context.arc(mainChar.x, mainChar.y, mainChar.radius, 0, 2 * Math.PI, false);
  context.closePath();
  context.fillStyle = 'red';
  context.fill();
  context.globalCompositeOperation = "xor";

It's 'sort-of' working, and by 'sort-of' I mean it's not completely erasing the first drawing. Nothing has shifted yet for the first call (and the character has been called on load) so I thought XOR would completely erase the image since their coordinates and everything are identical?

Am I way off base, implementing something slightly wrong, or is there just a much better way to do this?


Solution

  • Have you noticed that the un-erased part of your circle is very jaggy?

    That's because canvas originally drew your circle with anti-aliasing to visually smooth out the roundness of your circle.

    When you XOR the same circle, canvas does not erase the anti-aliasing pixels it originally created.

    The same will happen for slanted lines.

    Bottom line...XOR will not work until browsers let us turn off anti-aliasing. This option has been proposed to the powers-that-be.

    Until then you might change your drawChar so that you can "erase" a slightly larger circle than you originally drew.

    drawChar(50,"red");
    drawChar(51,"white");
    
    function drawChar(r,fill){
      ctx.beginPath();
      ctx.arc(100,100,r, 0, 2 * Math.PI, false);
      ctx.closePath();
      ctx.fillStyle = fill;
      ctx.fill();
    }