diff options
-rw-r--r-- | snek.js | 159 | ||||
-rw-r--r-- | w | 456 |
2 files changed, 587 insertions, 28 deletions
@@ -10,28 +10,38 @@ let context; let mice; let explosions; -let drawInterval=20/1000; +const drawInterval=20/1000; let micePerSecond=0.3; +const chargeDepletionRate=200; let normalMouseSpeed=3; let normalMouseSize=1; -let maxNumberOfExplosionParticles=20; -let minNumberOfExplosionParticles=5; -let maxParticleSize=50; -let maxExplosionAge=100; +const maxNumberOfExplosionParticles=20; +const minNumberOfExplosionParticles=5; +const maxParticleSize=50; +const maxExplosionAge=100; + let lastTimeStamp; let snake = { 'x':window.innerWidth/2, - 'y':window.innerHeight/2 + 'y':window.innerHeight/2, + 'discharging': false, + 'direction' : 0 + }; let health=10; +let score=0; let frameId; +let snakeLaserId; + +let charge=0; +const chargeTipoffPoint=10; function draw(timeStamp) { @@ -46,15 +56,27 @@ function draw(timeStamp) canvas.width = window.innerWidth; canvas.height = window.innerHeight; + /*the only clear thing here is that I am very bad at geometry*/ context.clearRect(0, 0, canvas.width, canvas.height); + drawExplosions(timeElapsed); drawMice(timeElapsed); drawSnake(timeElapsed); + drawHealth(); frameId=window.requestAnimationFrame(draw); } +function drawHealth() +{ + context.save(); + context.font='48px serif'; + context.fillText(`Health: ${health}`,10,70); + context.font='48px serif'; + context.fillText(`Score: ${score}/30`,window.innerWidth-48*10,70); + context.restore(); +} function createMouse(x,y,direction,speed,size) { return { 'x':x, 'y':y, 'direction':direction, 'speed':speed,'size':size ,'tailLag':0, 'animation':0, 'animationCounter':0, 'hitbox':size*90 }; @@ -68,11 +90,13 @@ function main() setInterval(spawnMouse,1000/micePerSecond); setInterval(cleanUpMice,100); setInterval(cleanUpBlood,maxExplosionAge); + + setInterval(depleteCharge,chargeDepletionRate); } function spawnMouse() { - mice.push(createMouse(5+window.innerWidth*Math.random()*0.9,window.innerHeight+normalMouseSize*90,-Math.PI/2,normalMouseSpeed,normalMouseSize)); + mice.push(createMouse(5+window.innerWidth*Math.random()*0.9,window.innerHeight+normalMouseSize*90,-Math.PI/2,(normalMouseSpeed*(Math.random()+1)),normalMouseSize*(Math.random()+1))); } function initialise() @@ -86,7 +110,6 @@ function initialise() mice.push(createMouse(200,100,1,normalMouseSpeed,normalMouseSize)); explosions=[]; - } function cleanUpMice() { @@ -100,11 +123,20 @@ function cleanUpMice() if(health==0) { window.cancelAnimationFrame(frameId); - alert("Too many of the filthy rats escaped! Your snake died of despair."); + alert(`Too many of the filthy rats escaped! Your snake has died of despair. Your score is ${score}`); } } else if(mice[i].x-mice[i].hitbox<snake.x && mice[i].x+mice[i].hitbox>snake.x && mice[i].y+mice[i].hitbox>snake.y && mice[i].y-mice[i].hitbox<snake.y) + { + explosions.push( makeExplosion(mice.splice(i,1)[0])); + checkScore(); + } + else if(snake.discharging && mouseColidesWithLaserBeam(mice[i])) + { explosions.push( makeExplosion(mice.splice(i,1)[0])); + checkScore(); + } + } } function cleanUpBlood() @@ -116,22 +148,48 @@ function cleanUpBlood() explosions.splice(i,1); } } -/*it is clear that I am bad at geometry :P*/ function drawSnake(timeElapsed) { let distance; + let distance2; let vx; let vy; let wx; let wy; - distance=Math.sqrt(Math.pow(window.innerWidth/2-snake.x,2) + Math.pow(window.innerHeight/2-snake.y,2)); + distance2=Math.sqrt(Math.pow(window.innerWidth/2-snake.x,2) + Math.pow(window.innerHeight/2-snake.y,2))+0.1; + wx=((window.innerWidth/2)-snake.x)/distance2; + + gravitate(snake,cursor,true,10000*(timeElapsed/drawInterval),100); + + distance=Math.sqrt(Math.pow(window.innerWidth/2-snake.x,2) + Math.pow(window.innerHeight/2-snake.y,2))+0.1; vx=(window.innerWidth/2-snake.x)/distance; vy=(window.innerHeight/2-snake.y)/distance; - gravitate(snake,cursor,true,10000*(timeElapsed/drawInterval),100); + + if(charge>chargeTipoffPoint && snake.discharging==false) + { + snake.discharging=true; + snakeLaserId=setInterval(cleanUpMice,drawInterval); + }else if(snake.discharging==true && charge<=0) + { + snake.discharging=false; + clearInterval(snakeLaserId); + } + if(snake.discharging==true) + { + gravitate(snake,{'x':Math.random()*window.innerWidth,'y':Math.random()*window.innerHeight/4},false,10000*(timeElapsed/drawInterval),1); + charge+=Math.abs(Math.asin(wx)-Math.asin(vx))*0.5; + }else + { + charge+=Math.abs(Math.asin(wx)-Math.asin(vx)); + } + + context.save(); + context.shadowBlur=charge; + context.shadowColor="yellow"; /*body*/ context.beginPath(); context.strokeStyle="#00FF00"; @@ -148,27 +206,34 @@ function drawSnake(timeElapsed) context.stroke(); context.closePath(); - - /*head*/ - distance=Math.sqrt(Math.pow(vx*300,2) + Math.pow(vy*100,2)); - wx=(vx*300)/distance; - wy=(vy*100)/distance; - - context.save(); - - context.translate(snake.x,snake.y); + snake.direction=Math.atan2(vy,vx); + context.rotate(Math.PI/2+snake.direction); + /* if(wx>0) { - context.rotate(Math.PI-Math.acos(wy)); + snake.direction=Math.acos(wy); + context.rotate(Math.PI-snake.direction); }else { - context.rotate(Math.PI+Math.acos(wy)); + snake.direction=Math.acos(wy); + context.rotate(Math.PI+snake.direction); + } + */ + + if(snake.discharging==true) + { + context.beginPath(); + context.fillStyle="#FF0000"; + context.rect(-15,0,30,10000); + context.fill(); + context.closePath(); } + context.strokeStyle="#00FF00"; context.beginPath(); - context.ellipse(0,50,30,70,0,0,3*Math.PI); context.fillStyle = "#00FF00"; + context.ellipse(0,50,30,70,0,0,3*Math.PI); context.fill(); context.stroke(); context.closePath(); @@ -244,10 +309,10 @@ function drawMouse(mouse,timeElapsed) mouse.y+=mouse.speed*(timeElapsed/drawInterval)*Math.sin(mouse.direction); mouse.animation+=0.4*(timeElapsed/drawInterval); - /* - mouse.direction+=0.1; - if(mouse.direction>1) mouse.direction-=1; - */ + if(score>=0) + { + gravitate(mouse,snake,false,(timeElapsed/drawInterval)*500,10); + } context.save(); @@ -355,6 +420,7 @@ function makeExplosion(mouse) let numberOfParticles=Math.floor(Math.random()*(maxNumberOfExplosionParticles-minNumberOfExplosionParticles))+minNumberOfExplosionParticles; let i=0; + ++score; for(i;i<numberOfParticles;++i) { ret.particles.push({ 'x':mouse.x , 'y':mouse.y, 'direction':Math.random()*2*Math.PI, 'size':Math.random() }); @@ -362,3 +428,40 @@ function makeExplosion(mouse) return ret; } +function depleteCharge() +{ + charge=Math.max(0,charge-1); +} +function possiblyDischarge() +{ + +} +function mouseColidesWithLaserBeam(mouse) +{ + let vx=(mouse.x-snake.x); + let vy=(mouse.y-snake.y); + let direction=Math.atan2(vy,vx); + + if(direction<0) + direction=Math.PI*2+direction; + + if(Math.abs(direction-Math.PI-snake.direction)<0.1) + return true; + else + return false; +} +function checkScore() +{ + if(score==20 || score==10 || score==5) + { + normalMouseSpeed*=2; + normalMouseSize*=0.7; + setInterval(spawnMouse,1000/micePerSecond); + } + + if(score>=30) + { + window.cancelAnimationFrame(frameId); + alert("You are winner!"); + } +} @@ -0,0 +1,456 @@ + +let cursor = { + 'x' : 0, + 'y' : 0 +}; + +let canvas; +let context; + +let mice; +let explosions; + +const drawInterval=20/1000; + +let micePerSecond=0.3; +const chargeDepletionRate=200; + +const normalMouseSpeed=3; +const normalMouseSize=1; + +const maxNumberOfExplosionParticles=20; +const minNumberOfExplosionParticles=5; +const maxParticleSize=50; +const maxExplosionAge=100; + + +let lastTimeStamp; + +let snake = { + 'x':window.innerWidth/2, + 'y':window.innerHeight/2, + 'discharging': false, + 'direction' : 0 + +}; + +let health=10; +let score=0; + +let frameId; +let snakeLaserId; + +let charge=0; +const chargeTipoffPoint=10; + +function draw(timeStamp) +{ + let timeElapsed; + + if(lastTimeStamp==undefined) + lastTimeStamp=timeStamp; + + timeElapsed=Math.min((timeStamp-lastTimeStamp)/1000,0.1); + lastTimeStamp=timeStamp; + + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + /*the only clear thing here is that I am very bad at geometry*/ + context.clearRect(0, 0, canvas.width, canvas.height); + + + drawExplosions(timeElapsed); + drawMice(timeElapsed); + drawSnake(timeElapsed); + drawHealth(); + + frameId=window.requestAnimationFrame(draw); +} +function drawHealth() +{ + context.save(); + context.font='48px serif'; + context.fillText(`Health: ${health}`,10,70); + + context.font='48px serif'; + context.fillText(`Score: ${score}/30`,window.innerWidth-48*10,70); + context.restore(); +} +function createMouse(x,y,direction,speed,size) +{ + return { 'x':x, 'y':y, 'direction':direction, 'speed':speed,'size':size ,'tailLag':0, 'animation':0, 'animationCounter':0, 'hitbox':size*90 }; +} + + +function main() +{ + initialise(); + frameId=window.requestAnimationFrame(draw); + setInterval(spawnMouse,1000/micePerSecond); + setInterval(cleanUpMice,100); + setInterval(cleanUpBlood,maxExplosionAge); + + setInterval(depleteCharge,chargeDepletionRate); +} + +function spawnMouse() +{ + mice.push(createMouse(5+window.innerWidth*Math.random()*0.9,window.innerHeight+normalMouseSize*90,-Math.PI/2,(normalMouseSpeed*(Math.random()+1)),normalMouseSize*(Math.random()+1))); +} + +function initialise() +{ + + canvas=document.getElementById("canvas1"); + context=canvas.getContext("2d"); + + canvas.addEventListener('mousemove', e => { cursor.x=e.offsetX; cursor.y=e.offsetY; }); + mice=[]; + mice.push(createMouse(200,100,1,normalMouseSpeed,normalMouseSize)); + + explosions=[]; +} +function cleanUpMice() +{ + let i=0; + for(i;i<mice.length;++i) + { + if(mice[i].y<-200 || mice[i].y>window.innerHeight+300 || mice[i].x<-100 || mice[i].x>window.innerWidth+300) + { + mice.splice(i,1); + --health; + } + else if(mice[i].x-mice[i].hitbox<snake.x && mice[i].x+mice[i].hitbox>snake.x && mice[i].y+mice[i].hitbox>snake.y && mice[i].y-mice[i].hitbox<snake.y) + { + explosions.push( makeExplosion(mice.splice(i,1)[0])); + } + else if(snake.discharging && mouseColidesWithLaserBeam(mice[i])) + { + explosions.push( makeExplosion(mice.splice(i,1)[0])); + } + + if(health==0) + { + window.cancelAnimationFrame(frameId); + alert(`Too many of the filthy rats escaped! Your snake has died of despair. Your score is ${score}`); + } + if(score==20); + if(score>=30) + { + window.cancelAnimationFrame(frameId); + alert("You are winner!"); + } + } +} +function cleanUpBlood() +{ + let i=0; + for(i;i<explosions.length;++i) + { + if(explosions[i].animation>maxExplosionAge) + explosions.splice(i,1); + } +} +function drawSnake(timeElapsed) +{ + let distance; + let distance2; + let vx; + let vy; + let wx; + let wy; + + distance2=Math.sqrt(Math.pow(window.innerWidth/2-snake.x,2) + Math.pow(window.innerHeight/2-snake.y,2))+0.1; + wx=((window.innerWidth/2)-snake.x)/distance2; + + gravitate(snake,cursor,true,10000*(timeElapsed/drawInterval),100); + + distance=Math.sqrt(Math.pow(window.innerWidth/2-snake.x,2) + Math.pow(window.innerHeight/2-snake.y,2))+0.1; + vx=(window.innerWidth/2-snake.x)/distance; + vy=(window.innerHeight/2-snake.y)/distance; + + + if(charge>chargeTipoffPoint && snake.discharging==false) + { + snake.discharging=true; + snakeLaserId=setInterval(cleanUpMice,drawInterval); + }else if(snake.discharging==true && charge<=0) + { + snake.discharging=false; + clearInterval(snakeLaserId); + } + + if(snake.discharging==true) + { + gravitate(snake,{'x':Math.random()*window.innerWidth,'y':Math.random()*window.innerHeight/4},false,10000*(timeElapsed/drawInterval),1); + charge+=Math.abs(Math.asin(wx)-Math.asin(vx))*0.5; + }else + { + charge+=Math.abs(Math.asin(wx)-Math.asin(vx)); + } + + context.save(); + + context.shadowBlur=charge; + context.shadowColor="yellow"; + /*body*/ + context.beginPath(); + context.strokeStyle="#00FF00"; + context.moveTo(window.innerWidth/2,-10); + context.bezierCurveTo( + window.innerWidth/2, + window.innerHeight/4, + snake.x+vx*300, + snake.y+vy*100, + snake.x, + snake.y + ); + context.lineWidth=40; + context.stroke(); + context.closePath(); + + context.translate(snake.x,snake.y); + snake.direction=Math.atan2(vy,vx); + context.rotate(Math.PI/2+snake.direction); + /* + if(wx>0) + { + snake.direction=Math.acos(wy); + context.rotate(Math.PI-snake.direction); + }else + { + snake.direction=Math.acos(wy); + context.rotate(Math.PI+snake.direction); + } + */ + + if(snake.discharging==true) + { + context.beginPath(); + context.fillStyle="#FF0000"; + context.rect(-15,0,30,10000); + context.fill(); + context.closePath(); + } + + context.strokeStyle="#00FF00"; + context.beginPath(); + context.fillStyle = "#00FF00"; + context.ellipse(0,50,30,70,0,0,3*Math.PI); + context.fill(); + context.stroke(); + context.closePath(); + + /*right eye*/ + context.beginPath(); + context.fillStyle="#FF0000" + context.moveTo(20,80); + context.lineTo(30,80); + context.lineTo(15,100); + context.fill(); + context.closePath(); + + /*right eye*/ + context.beginPath(); + context.fillStyle="#FF0000" + context.moveTo(-20,80); + context.lineTo(-30,80); + context.lineTo(-15,100); + context.fill(); + context.closePath(); + + + context.restore(); + +} + +function drawExplosions(timeElapsed) +{ + let i=0; + for(i;i<explosions.length;++i) + { + drawExplosion(explosions[i],timeElapsed); + } +} +function drawExplosion(explosion,timeElapsed) +{ + let i=0; + explosion.animation+=timeElapsed/drawInterval; + for(i;i<explosion.particles.length;++i) + { + explosion.particles[i].x+=(1000/explosion.animation)*0.1*Math.cos(explosion.particles[i].direction); + explosion.particles[i].y+=(1000/explosion.animation)*0.1*Math.sin(explosion.particles[i].direction); + + + context.fillStyle=`rgb( + 255, + ${Math.floor(255*(explosion.animation/(maxExplosionAge+30)))}, + ${Math.floor(255*(explosion.animation/(maxExplosionAge+30)))} + + )`; + context.rect( + explosion.particles[i].x, + explosion.particles[i].y, + maxParticleSize*explosion.particles[i].size, + maxParticleSize*explosion.particles[i].size, + ); + context.fill(); + } +} +function drawMice(timeElapsed) +{ + let i=0; + for(i;i<mice.length;++i) + { + drawMouse(mice[i],timeElapsed); + } +} +function drawMouse(mouse,timeElapsed) +{ + mouse.animationCounter+=drawInterval; + mouse.x+=mouse.speed*(timeElapsed/drawInterval)*Math.cos(mouse.direction); + mouse.y+=mouse.speed*(timeElapsed/drawInterval)*Math.sin(mouse.direction); + mouse.animation+=0.4*(timeElapsed/drawInterval); + + /* + mouse.direction+=0.1; + if(mouse.direction>1) mouse.direction-=1; + */ + + context.save(); + + context.translate(mouse.x, mouse.y); + context.rotate(mouse.direction); + context.scale(mouse.size,mouse.size); + + /*body*/ + context.beginPath(); + context.ellipse(0,0,90,40,0,0,2*Math.PI); + context.fillStyle = "#8f8f8f"; + context.fill(); + context.stroke(); + context.closePath(); + /*right ear*/ + context.beginPath(); + context.arc(50, 20, 20, 0, Math.PI*1.5, false); + context.fillStyle = "#8f8f8f"; + context.fill(); + context.stroke(); + context.closePath(); + /*left ear*/ + context.beginPath(); + context.arc(50, -22, 20, 0,- Math.PI*1.5, true); + context.fillStyle = "#8f8f8f"; + context.fill(); + context.stroke(); + context.closePath(); + /*left eye*/ + context.beginPath(); + context.ellipse(80,7,5,3,-1/2,0,2*Math.PI); + context.fillStyle = "#000000"; + context.fill(); + context.closePath(); + /*right eye*/ + context.beginPath(); + context.ellipse(80,-7,5,3,1/2,0,2*Math.PI); + context.fillStyle = "#000000"; + context.fill(); + context.closePath(); + /*right wiskers*/ + context.beginPath(); + context.moveTo(89,0); + context.lineTo(95,20); + context.stroke(); + context.closePath(); + context.beginPath(); + context.moveTo(89,0); + context.lineTo(90,20); + context.stroke(); + context.closePath(); + /*left wiskers*/ + context.beginPath(); + context.moveTo(89,0); + context.lineTo(95,-20); + context.stroke(); + context.closePath(); + context.beginPath(); + context.moveTo(89,0); + context.lineTo(90,-20); + context.stroke(); + context.closePath(); + + /*tail*/ + context.beginPath(); + context.moveTo(-90,0); + context.bezierCurveTo(-100,0,-150,Math.cos(mouse.animation)*30,-200,Math.sin(mouse.animation)*10); + context.lineWidth+=2; + context.stroke(); + context.closePath(); + + context.restore(); +} + +function gravitate(subject,gravitas,doesItPull,pullStrength,nearDistance) +{ + let distance=Math.sqrt( (subject.x-gravitas.x)*(subject.x-gravitas.x) + (subject.y-gravitas.y)*(subject.y-gravitas.y)); + + if(distance==0) + { + return ; + } + + if(doesItPull==false) + { + subject.x+=(((subject.x-gravitas.x)*pullStrength)/(distance*distance)); + subject.y+=(((subject.y-gravitas.y)*pullStrength)/(distance*distance)); + }else + { + if(distance<=nearDistance) + { + subject.x=gravitas.x; + subject.y=gravitas.y; + }else + { + subject.x-=(((subject.x-gravitas.x)*pullStrength)/(distance*distance)); + subject.y-=(((subject.y-gravitas.y)*pullStrength)/(distance*distance)); + } + + } +} +function makeExplosion(mouse) +{ + let ret={ 'mouse': mouse, 'animation':0, 'particles':[] }; + let numberOfParticles=Math.floor(Math.random()*(maxNumberOfExplosionParticles-minNumberOfExplosionParticles))+minNumberOfExplosionParticles; + let i=0; + + ++score; + for(i;i<numberOfParticles;++i) + { + ret.particles.push({ 'x':mouse.x , 'y':mouse.y, 'direction':Math.random()*2*Math.PI, 'size':Math.random() }); + } + + return ret; +} +function depleteCharge() +{ + charge=Math.max(0,charge-1); +} +function possiblyDischarge() +{ + +} +function mouseColidesWithLaserBeam(mouse) +{ + let vx=(mouse.x-snake.x); + let vy=(mouse.y-snake.y); + let direction=Math.atan2(vy,vx); + + if(direction<0) + direction=Math.PI*2+direction; + + if(Math.abs(direction-Math.PI-snake.direction)<0.1) + return true; + else + return false; +} |