Skip to content

Instantly share code, notes, and snippets.

@markrockcity
Last active April 18, 2017 00:34
Show Gist options
  • Select an option

  • Save markrockcity/12b066b0b00b592bc31e2d79a74742e7 to your computer and use it in GitHub Desktop.

Select an option

Save markrockcity/12b066b0b00b592bc31e2d79a74742e7 to your computer and use it in GitHub Desktop.
"Worms"
<button id='playpause' title='play/pause'>&#10074;&#10074;</button>
<button id='clear' title='clear'>X</button>
<br/>
<canvas id="canvas"></canvas>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var playPauseButton = document.getElementById("playpause");
var clearButton = document.getElementById("clear");
canvas.height = window.innerHeight * 0.94;
canvas.width = window.innerWidth * 0.95;
var ww = 100; //grid width
var hh = 100; //grid height
var w = (canvas.width / ww); //grid square width
var h = (canvas.height / hh); //grid square height
/////////////////////////////////////
var text = "X";
//when clicking on canvas:
canvas.addEventListener("click", event =>
{
if (t)
return;
//the last worm in the list:
   var cworms = worms[worms.length-1];
cworms[0].x = (event.pageX-canvas.offsetLeft) / w;
cworms[0].y = (event.pageY-canvas.offsetTop) / h;
cworms[0].color.a = 1;
cworms[0].color.r = 255;
cworms[0].color.g=0;
cworms[0].color.b=0;
cworms[0].vx = 0;
cworms[0].vy = 0;
   cworms[0].width = w*2;
},
false);
//middle
var mh = hh/2, mw = ww/2;
//W[orm]()
function W(x,y,r,g,b)
{
var a = [];
//segment protoype
var w = {
x:x,
y:y,
color:{r:r, g:g, b:b, a:0.01},
vx: 0,
vy:0,
width: 10
};
//worm segments
for(var i=0;i<randi(3,15);i++)
{
a.push
({
x:w.x,
y:w.y,
color: i==0 ? {r:150,g:150,b:150,a:1} //head
: {r:w.color.r, g:w.color.g, b:w.color.b, a:0.8},
vx: 0,
vy:0,
width: w.width
});
}
return a;
}
//"worm"
var worms = [];
//= [W(0,0,255,0,0),
// W(mw,mh,0,255,0),
// W(75,75,0,0,255)];
//initial worms
var initialWormCount = 15;
for(var i=0; i < initialWormCount; i++)
{
worms.push(W
(
rand(0,ww), //x
rand(0,hh), //y
randi(0,100), // R
randi(0,100), // G
randi(0,100) // B
));
}
//random-integer()
function randi(min,max)
{
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//random-float()
function rand(min,max)
{
return Math.random() * (max - min ) + min;
}
function clamp255(x)
{
return Math.max(0,Math.min(255,x));
}
function color(x)
{
var r = clamp255(randi(x-5,x+5)),
g = clamp255(randi(x-5,x+5)),
b = clamp255(randi(x-5,x+5));
return "rgb("+r+","+g+","+b+")";
}
//t = paused
var t = false;
//when clicking on playPauseButton
playPauseButton.onclick = function toggleBetweenPlayAndPause()
{
t = !t;
if (!t)
{
playPauseButton.innerHTML = "&#10074;&#10074;";
main();
}
else
playPauseButton.innerHTML = "&#9654;";
}
//CLEAR BUTTON
clearButton.onclick = () =>
{
worms = [];
};
/////////////////////////////////////
var lastRate = 0;
var avgRate = 0;
var rateColor = "black";
var textColor = "black";
var bgAlpha = {v:0.125, min: 0.125, max: 0.25, co1: 1, co2: 0.00125};
// UPDATE
function update(framerate)
{
if (t)
{
text ="paused";
return;
}
var targetRate = 35;
//bgAlpha (for controlling motion blur and removing artifacts)
if (bgAlpha.v <= bgAlpha.min)
bgAlpha.co1 = 1; //1 = increase alpha
if (bgAlpha.v >= bgAlpha.max)
bgAlpha.co1 = -1; //-1 = decrease alpha
bgAlpha.v = bgAlpha.v + bgAlpha.co1 * bgAlpha.co2;
//removes worm segments and worms if framerate is too low
if (framerate < targetRate && worms.length > 2)
{
var w = worms[0];
var choppedHead = w.shift();
var newHead = worms[0];
if (w.length < 2)
worms.shift();
else
{
newHead.width = choppedHead.width * 1.1;
newHead.color = {r:200,g:200,b:200,a:1};
}
if (w.length == 2)
{
newHead.width *= 1.5;
}
textColor = rateColor = "red";
}
//adds worm if framerate is too high or nor worms are left
else if (framerate > targetRate+30 || worms.length == 0)
{
worms.push(W
(
rand(0,ww), rand(0,hh), //position (x,y)
randi(0,255), randi(0,255), randi(0,255) //color (rgb)
));
textColor = rateColor = "green";
}
else
{
//rateColor = "black";
textColor = "grey";
}
//for each worm...
for(var i=0; i < worms.length; ++i)
{
//worms[i].push (worms[i].shift());
var w = worms[i]; //actual worm
var head = w[0];
//if (w.length > 2)
// head.color = {r:0,g:0,b:0,a:1};
//for each worm segment...
for(var j=0; j < w.length; ++j)
{
var worm = w[j]; //worm segment
var prev = w[j>0?j-1:j]; //previous segment
if (rand(0,3)<1)
{
var dx = Math.abs(worm.x-prev.x);
var dy = Math.abs(worm.y-prev.y);
var rx = rand(-0.5,0.5)/10;
var ry = rand(-0.5,0.5)/10;
var arx = Math.abs(rx) * Math.max(1,dx);
var ary = Math.abs(ry) * Math.max(1,dy);
if (j ==0) //head
{
worm.vx += rx * 1.1;
worm.vy += ry * 1.1;
}
else //tail segment
{
//x
if (worm.x > prev.x)
worm.vx -= arx;
if (worm.x < prev.x)
worm.vx += arx;
if (Math.abs(worm.x - head.x-head.width)==0)
worm.vx = 0;
if (dx > 1)
{
worm.vx /= 2;
prev.vx /= 2;
head.vx *= 1.05;
}
//y
if (worm.y > prev.y)
worm.vy -= ary;
if (worm.y < prev.y)
worm.vy += ary;
if (Math.abs(worm.y - head.y-head.width)==0)
worm.vy = 0;
if (dy > 1)
{
worm.vy /= 2;
prev.vy /= 2;
head.vy *= 1.05;
}
}
//[c]olor(e[x]istingColor, a, b))
function _c (x,a,b)
{
return Math.min
(
255,
Math.max(0,(x+randi(a,b)))
);
}
//color cycling
if (rand(0,10)<1)
{
var c = worm.color;
//...
var threshold = 10;
var limit = 0;
if ( c.r < threshold && c.g==limit && c.b==limit
|| c.r== limit && c.g < threshold && c.b==limit
|| c.r==limit && c.g==limit && c.b < threshold)
{
let min = 0;
let max = 25;
c.r = _c(c.r,min,max);
c.g = _c(c.g,min,max);
c.b = _c(c.b,min,max);
}
let min = -2;
let max = +1;
c.r = _c(c.r,min,max);
c.g = _c(c.g,min,max);
c.b = _c(c.b,min,max);
}
}
//move horizontal + vertical wall bounce
worm.x = Math.min(Math.max(0,worm.x+worm.vx),ww-1);
if (worm.x == 0 || worm.x == ww-1)
worm.vx = -worm.vx/2;
//move vertical + horizontal wall bounce
worm.y = Math.min(Math.max(0,worm.y+worm.vy),hh-1);
if (worm.y == 0 || worm.y == hh-1)
worm.vy = -worm.vy/2;
}
}
//text for framerate
avgRate = (framerate + lastRate)/2;
lastRate = framerate;
if (Math.abs(avgRate-framerate)>10)
{
text = Math.round(avgRate);
}
}
// RENDER()
function render()
{
//this clears the canvas between frames:
//ctx.clearRect(0, 0, canvas.width,canvas.height);
//render bg
   /*
   for(var i=0; i < ww; ++i)
for(var j=0; j < hh; ++j)
{
var alt = i % 2 == 0 && j % 2 > 0 || i % 2 > 0 && j % 2 == 0;
//ctx.fillStyle = color(parseInt((i+j)*1.5));
//ctx.fillStyle = alt ? "#eee" : "#fff";
ctx.fillStyle = alt ? "rgb(220,190,91)" : "rgb(255,220,190)";
//ctx.fillStyle = "rgb(50,10,1)"
ctx.fillRect(w * i , h * j, w+1, h+1);
  }*/
var bgColor = `rgba(30,20,15,${bgAlpha.v})`;
ctx.fillStyle = bgColor;
ctx.fillRect(0,0,canvas.width,canvas.height);
 
//render worms
   for(var i=0; i < worms.length; ++i)
  {
var worm = worms[i];
//render segments (including head, j=0)
for(var j=0; j < worm.length; ++j)
{
var cs = worm[j]; //current segment
//ctx.strokeStyle = "#000";
ctx.lineWidth = rand(4,5);
ctx.fillStyle = "rgba("+ cs.color.r+","+ cs.color.g+","+ cs.color.b+","+ cs.color.a+")";
var prev = worm[j>0 ? j-1 : j];
//renders line between segments
var renderLines = true;
if (renderLines && worm.indexOf(cs) > 0)
{
/*
text = cs == prev;
ctx.font = "bold 20px sans-serif";
ctx.clearRect(0, 0, 70, 45);
//ctx.fillStyle = 'black';
ctx.fillText(text,1, 20);
*/
ctx.strokeStyle = `rgba(${ cs.color.r},${ cs.color.g},${cs.color.b},${ cs.color.a})`;
ctx.lineWidth = cs.width*2;
ctx.beginPath();
ctx.moveTo(w*prev.x, h*prev.y);
ctx.lineTo(w* cs.x, h* cs.y);
//ctx.closePath();
ctx.stroke();
}
/*
ctx.fillRect
(
w*prev.x,
h*prev.y,
w*(cworm.x - prev.x),
h*(cworm.y - prev.y)
);*/
//circle
//if(j==0 || j==worm.length-1)
{
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(w*cs.x,h*cs.y, cs.width, 0, Math.PI * 2, false);
ctx.closePath();
//ctx.stroke();
//let gradient = ctx.createRadialGradient(w*cs.x,h*cs.y,cs.width,w*cs.x,h*cs.y,0);
//gradient.addColorStop(0,bgColor);
// gradient.addColorStop(1,"white");
// ctx.fillStyle = gradient;
ctx.fill();
}
}//j (segments)
}
//text
ctx.font = "bold 20px sans-serif";
var wormCountText = worms.length.toString();
var textWidth = Math.max(ctx.measureText(text).width,
ctx.measureText(wormCountText).width);
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, textWidth+4, 45);
//ctx.textAlign = "right";
ctx.fillStyle = rateColor;
ctx.fillText(text,1, 20);
ctx.fillStyle = textColor;
ctx.fillText(wormCountText,1,40);
//dot
ctx.fillStyle="red";
ctx.fillRect(canvas.width-3,canvas.height-3,2,2);
}
var then = Date.now();
function main()
{
// Request to do this again ASAP
if (!t)
requestAnimationFrame(main);
var now = Date.now();
var delta = now - then;
update(1/(delta/1000));
render();
then = now;
};
main();
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
button
{
font-family: Arial;
margin-bottom: 2px;
height: 2em;
}
#clear
{
position: relative;
top: -1px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment