After talking things through with Wendy yesterday, I moved on from KeyBoardScalingCircleGrid to KeyboardSnake. Wendy pointed out the multicoloured background wasn’t necessary for this version – so I could concentrate on making the interaction work with a single colour for the snake. I decided to change the name to the slightly more friendly KeyboardWorm.
I began by creating a WormSegment object:
function WormSegment(aColour,aRadius){ //WormSegment object this.radius = aRadius; this.position = createVector(0.5,0.5); //start in centre of screen this.colour = aColour; this.display = function(){ var translatedX = this.position.x * windowWidth; var translatedY = this.position.y * windowHeight; fill(this.colour); ellipse(translatedX, translatedY, this.radius, this.radius); } }
Then created an array of these segments to make up a worm:
var worm = []; //array of WormSegment objects var wormLength = 30; //number of segments of the worm
and
function setup() { createCanvas(windowWidth,windowHeight); //make a fullscreen canvas, thanks to: http://codepen.io/grayfuse/pen/wKqLGL noStroke(); //no outlines, just filled shapes colorMode(HSB, 100);// Use HSB with scale of 0-100, see https://p5js.org/reference/#/p5/color var segmentColourMaxBrightness = 100; var segmentColourMinBrightness = 80; var segmentColourBrightnessRatio = (segmentColourMaxBrightness-segmentColourMinBrightness)/wormLength; var segmentColour = color(random(100),50,segmentColourMaxBrightness, 100); //random hue, saturation 50%, brightness 100%, alpha 100% var segmentMaxRadius = 100; var segmentMinRadius = 70; var segmentRadiusRatio = (segmentMaxRadius-segmentMinRadius)/wormLength; var segmentRadius = segmentMaxRadius; for (var i=0; i < wormLength; i++) { worm.push(new WormSegment(segmentColour, segmentRadius)); segmentRadius -= segmentRadiusRatio; segmentColour = color(hue(segmentColour), saturation(segmentColour), brightness(segmentColour)-segmentColourBrightnessRatio, alpha(segmentColour)); } console.log("The length of the worm is " + worm.length); }
I changed my draw() function to the following:
function draw() { background(255); //white background updateWorm(); drawWorm(); }
Drawing the worm was pretty straight forward, after I realised that I had to draw the segments in reverse order so that the “head” of the worm drew last:
function drawWorm(){ //draw the first segment of the worm last so that the shading looks correct for (var i = (worm.length-1); i > 0; i--) { worm[i].display(); } }
Most challenging was updating the worm:
function updateWorm(){ seekWormTowardsKey(key); //starting at back of the worm, copy the previous worm segments position onto the current segments position for (var i = (worm.length-1); i > 0; i--) { worm[i].position.x = worm[i-1].position.x; worm[i].position.y = worm[i-1].position.y; //had to copy both values - not the reference, worm[i].position = worm[i-1].position doesn't work } }
As I noted in the comments – just setting the position as a reference didn’t work – I had to set each position x and y value manually – this was a nasty bug to track down, after two hours of drawing and redrawing my segment shifting code I finally realised my error.
Seeking the worm towards the key was a matter of checking to make sure that the key was valid, then easing towards the virtual key position – code that I had already written for the KeyboardScalingCircleGrid Reactickle.
function seekWormTowardsKey(aKey){ var lowerCaseKey = key.toLowerCase(); //key is a system variable via https://p5js.org/reference/#/p5/key, toLowerCase via http://www.w3schools.com/jsref/jsref_tolowercase.asp if(allTheKeys.includes(lowerCaseKey)){ //if the key is a valid one, then seek the worm towards it seekWormTowardsPosition(getCanvasPositionFromKey(lowerCaseKey)); } } function seekWormTowardsPosition(relativeSeekPosition){ var easing = 0.05; //move the head of the worm a bit closer... via https://processing.org/examples/easing.html var dx = relativeSeekPosition.x - worm[0].position.x; worm[0].position.x += dx * easing; var dy = relativeSeekPosition.y - worm[0].position.y; worm[0].position.y += dy * easing; }
You can try the KeyboardWorm online, as well as a MouseWorm version that I made as a bonus, which also works on Android or iOS mobile devices.