5

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?

armadadrive
  • 963
  • 2
  • 11
  • 42

1 Answers1

7

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();
}
markE
  • 102,905
  • 11
  • 164
  • 176
  • Thanks. That would explain why the image is so... fuzzy. Erasing the character with a white circle would mean having to redraw any background or objects he was in front of. – armadadrive May 24 '13 at 17:39
  • I find it kind of funny that XOR worked so well in my QBASIC stick fighting game, but that there are issues with DRAWING AND ERASING A CIRCLE twelve years later... – armadadrive May 24 '13 at 17:40
  • 2
    Yes, I remember XOR-ing with GDI a long while back--it was simple and effective. I guess that's "progress"! Canvas is a different animal. You will probably find that erasing/redrawing your entire scene is best for all but the most performance intensive projects. For ultimate performance you can redraw portions of the canvas or use a second hidden "buffer" canvas which holds your next frame. Then just draw your buffer to the display canvas and start the whole process over again by drawing on the buffer. – markE May 24 '13 at 17:47
  • 2
    BTW, you can have 2 overlapping canvas's. Your background canvas will be under your "animation" canvas. That way, you can erase the circle on the animation canvas without having to redraw any background. – markE May 24 '13 at 17:49
  • Great suggestion. If the rest of the objects are on the upper layer that sounds much less intensive. RE: drawing a 'buffer' canvas, do you know of any sites with instructions on such a technique? – armadadrive May 24 '13 at 17:54
  • 1
    Here's a fairly good article: http://blog.bob.sh/2012/12/double-buffering-with-html-5-canvas.html One update to that article: Canvas will *automatically* "buffer" your drawings starting with "beginPath" and ending with the first fill or stroke. If you can do all your draws for the next frame before calling fill/stroke...you're being automatically buffered! – markE May 24 '13 at 18:20
  • Thanks so much for taking some time to help me with this, @markE ! – armadadrive May 27 '13 at 12:35
  • 2
    I too was astounded that XOR doesn't work as well as it did in 1980! But on the other hand, drawing is so fast now, probably people figured it wasn't needed. – Mike Sokolov Nov 23 '13 at 01:53