Source description for demo by Ilan Bar-Magen.
// js1k 2010 entry by Ilan Bar-Magen d=document; M=Math; R=M.round; W=800; H=400; // get the canvas e=d.body.children.c; c=e.getContext('2d'); e.width=W;e.height=H; c.font = '16px sans'; x=W/2;y=H/2;vx=0;vy=0; ra = 10; //Radius of player circle sa = 1; //Radius of player circle cl= 15; //Cannon length ps = 2; //player speed sh = 4; //shooting speed shoots = new Array(); mx=0;my=0; function inside(x,y) {return !(x<0||y<0||x>W||y>H);} //move circle d.onkeydown = function(ev){n=ev.keyCode-38; if(n>-2&&n<3){vx=n%2?n*ps:vx;vy=!(n%2)?(n-1)*ps:vy;}} d.onkeyup = function(ev){if(ev.keyCode%2) vx=0; else vy=0;} d.onmousemove = function(ev) { if (ev.layerX || ev.layerX == 0) { // Firefox mx = ev.layerX; my = ev.layerY; } else if (ev.offsetX || ev.offsetX == 0) { // Opera mx = ev.offsetX; my = ev.offsetY; } //mx = window.event.clientX; //my = window.event.clientY; } i=0; setInterval(function(){ c.clearRect(0,0,W,H); c.beginPath(); //draw circle: if(inside(x+vx,y+vy)){x = x+vx;y = y+vy;} //move circle c.arc(x,y, ra, 0, M.PI*2, true); c.fill(); c.moveTo(x,y); //draw cannon pita = M.sqrt(M.pow(mx-x,2)+M.pow(my-y,2)); dx = (mx-x)/pita; dy = (my-y)/pita; c.lineTo(x+cl*dx,y+cl*dy); c.stroke(); if (!(i++%5)){shoots.push({sx:x+cl*dx,sy:y+cl*dy,sdx:dx,sdy:dy});} //Create new shooting // draw shootings te = shoots.length; while(te--){ t = shoots.shift(); t.sx += t.sdx*sh; t.sy += t.sdy*sh; c.beginPath(); c.arc(t.sx,t.sy, sa, 0, M.PI*2, true); c.fill(); c.closePath(); if(inside(t.sx,t.sy)){shoots.push(t)}; } }, 30);