xxxxxxxxxx
755
let aVal = 0;
let bVal = 0;
let cVal = 0;
let dVal = 0;
const space = 80;
var state = "setup";
//Piano Variables
var rSide = [];
var black = [];
var mid = [];
var lSide = [];
var osc = [];
var envo = [];
var stringValue = "";
var prevValue = "";
var rKee = ["A", null, null, "D", null, null, null, "H", null, null];
var blKee = ["W", "E", null, "T", "Y", "U", null, "O", "P", null, null];
var midKee = [null, "B", null, null, "E", "F", null, null, "I", null];
var lKee = [null, null, "C", null, null, null, "G", null, null, "J"];
//
//Rocket Variables
var player1;
var gameState;
//
//Snake Variables
let numSegments = 10;
let direction = "right";
const xStart = 0; //starting x coordinate for snake
const yStart = 250; //starting y coordinate for snake
const diff = 10;
let xCor = [];
let yCor = [];
let xFruit = 0;
let yFruit = 0;
let scoreElem;
let snakeMove = false;
function preload(){
initial = loadImage("intro.png");
tutorialImage = loadImage("tutorial.png")
}
function setup() {
createCanvas(space * 10, 600);
player1 = new Player(200, 200);
gameState = 0;
scoreElem = createDiv("Score = 0");
scoreElem.position(400, 20);
scoreElem.id = "score";
scoreElem.style("color", "white");
for (var j = 0; j < 17; j++) {
envo.push(new p5.Env()); //p5.Envelope, controls the output volume of oscillator.
envo[j].setADSR(0.01, 0.05, 1, 0.1);
envo[j].setRange(1, 0);
osc.push(new p5.Oscillator());
osc[j].amp(envo[j]);
}
for (var i = 0; i < 10; i++) {
rSide.push(new rSideKey(i, space, rKee[i]));
black.push(new BlackKey(i + 0.667, space, blKee[i]));
mid.push(new MidKey(i, space, midKee[i]));
lSide.push(new lSideKey(i, space, lKee[i]));
}
for (var g = 0; g < 30; g++) {
var xC = random(800);
var yC = random(600);
star = new Star(xC, yC);
stars[g] = star;
}
updateFruitCoordinates();
for (let i = 0; i < numSegments; i++) {
xCor.push(xStart + i * diff);
yCor.push(yStart);
}
}
function draw() {
background(255, 255, 255);
frameRate(60);
if (!serialActive) {
text("Press Space Bar to select Serial Port", 20, 30);
} else {
background(255, 255, 255);
rectMode(CORNER);
frameRate(60);
if (state == "intro") {
scoreElem.html("");
drawIntro();
} else if (state == "piano") {
scoreElem.html("");
drawPiano();
if (frameCount % 60 == 0) {
for (var i = 0; i < 10; i++) {
rSide[i].white();
black[i].white();
mid[i].white();
lSide[i].white();
}
}
} else if (state == "rocket") {
rectMode(CENTER);
scoreElem.html("");
drawRocket();
} else if (state == "disco") {
scoreElem.html("");
drawDisco();
} else if (state == "snake") {
frameRate(15);
stroke(255);
strokeWeight(10);
drawSnake();
}else if(state == "tutorial"){
stroke(255);
scoreElem.html("");
drawTutorial();
}
textFont("Arial");
textSize(20);
fill(0, 100, 200);
stroke(200)
strokeWeight(1);
text("Glove:", 20, 30);
// Print the current values (DEBUG)
text("Index = " + str(aVal), 20, 50);
text("Middle = " + str(bVal), 20, 70);
text("Ring = " + str(cVal), 20, 90);
text("Pinky = " + str(dVal), 20, 110);
}
}
function keyPressed() {
if (key == " ") {
// important to have in order to start the serial connection!!
setUpSerial();
}
if (keyCode === ESCAPE) {
state = "intro";
}
}
function drawPiano() {
background(255);
strokeWeight(1);
stroke(0);
for (var i = 0; i < rSide.length; i++) {
if (i === 0 || i === 3 || i === 7) {
rSide[i].display();
}
if (i !== 2 && i !== 6 && i !== 9 && i !== 10) {
black[i].display();
}
if (i === 1 || i === 4 || i === 5 || i === 8) {
mid[i].display();
}
if (i === 2 || i === 6 || i === 9) {
lSide[i].display();
}
}
}
var stars = [];
class Star {
constructor(x, y) {
this.x = x;
this.y = y;
}
drawStar(weight) {
fill(255);
stroke(255);
strokeWeight(weight);
point(this.x, this.y);
strokeWeight(1);
}
}
function drawTutorial(){
image(tutorialImage, 0, 0);
}
function drawRocket() {
background(0);
noStroke();
fill("black");
textSize(20);
text("Total fuel left:", 10, 20);
for (var j = 0; j < stars.length; j++) {
stars[j].drawStar(random(1, 3));
}
push();
rectMode(CORNER);
fill("red");
//this controls my "fuel gauge" at the top of the screen
if (player1.fuel > 0) {
rect(300, 20, player1.fuel, 20);
}
pop();
if (gameState == 0) {
fill(255);
textSize(30);
noStroke();
text("PRESS 'PINKY' TO START GAME", 200, 200);
textSize(20);
text("Hold MIDDLE to keep the rocket afloat", 250, 300);
text("Keep it in space as long as you can", 270, 330);
} else if (gameState == 1) {
player1.move();
player1.display();
//game over conditional
if (player1.fuel == 0 || player1.y > 500) {
gameState = 2;
}
} else if (gameState == 2) {
fill(255, 0, 0);
textSize(30);
text("GAME OVER, HIT 'PINKY' to reset", space * 3, 200);
}
}
function drawDisco() {
background(0);
noStroke();
if (aVal == 1) {
for (var x = 0; x <= width; x += 50) {
for (var y = 0; y <= height; y += 50) {
fill(random(0, 75), 0, random(0, 75));
ellipse(x, y, 25, 25);
}
}
} else if (bVal == 1) {
for (var x = 0; x <= width; x += 50) {
for (var y = 0; y <= height; y += 50) {
fill(random(0, 150), random(0, 75), random(75, 150));
ellipse(x, y, 25, 25);
}
}
} else if (cVal == 1) {
for (var x = 0; x <= width; x += 50) {
for (var y = 0; y <= height; y += 50) {
fill(random(0, 200), random(150), random(0, 200));
ellipse(x, y, 25, 25);
}
}
} else if (dVal == 1) {
for (var x = 0; x <= width; x += 50) {
for (var y = 0; y <= height; y += 50) {
fill(random(0, 255), random(255), random(0, 255));
ellipse(x, y, 25, 25);
}
}
} else {
for (var x = 0; x <= width; x += 50) {
for (var y = 0; y <= height; y += 50) {
fill(0);
ellipse(x, y, 25, 25);
}
}
}
}
// This function will be called by the web-serial library
// with each new *line* of data. The serial library reads
// the data until the newline and then gives it to us through
// this callback function
function readSerial(data) {
////////////////////////////////////
//READ FROM ARDUINO HERE
////////////////////////////////////
if (data != null) {
// make sure there is actually a message
// split the message
let fromArduino = split(trim(data), ",");
// if the right length, then proceed
if (fromArduino.length == 4) {
aVal = int(fromArduino[0]);
bVal = int(fromArduino[1]);
cVal = int(fromArduino[2]);
dVal = int(fromArduino[3]);
}
stringValue = str(aVal) + str(bVal) + str(cVal) + str(dVal);
//PIANO
//
//
if ((state == "piano") & (frameCount % 6 == 0)) {
var root = 60;
if (stringValue === "1000") {
rSide[0].red();
osc[0].start();
osc[0].freq(midiToFreq(root));
envo[0].play();
} else if (keyCode === 87) {
black[0].red();
osc[1].start();
osc[1].freq(midiToFreq(root + 1));
envo[1].play();
} else if (stringValue === "0100") {
mid[1].red();
osc[2].start();
osc[2].freq(midiToFreq(root + 2));
envo[2].play();
} else if (keyCode === 69) {
black[1].red();
osc[3].start();
osc[3].freq(midiToFreq(root + 3));
envo[3].play();
} else if (stringValue === "0010") {
lSide[2].red();
osc[4].start();
osc[4].freq(midiToFreq(root + 4));
envo[4].play();
} else if (stringValue === "0001") {
rSide[3].red();
osc[5].start();
osc[5].freq(midiToFreq(root + 5));
envo[5].play();
} else if (keyCode === 84) {
black[3].red();
osc[6].start();
osc[6].freq(midiToFreq(root + 6));
envo[6].play();
} else if (stringValue === "1100") {
mid[4].red();
osc[7].start();
osc[7].freq(midiToFreq(root + 7));
envo[7].play();
} else if (keyCode === 89) {
black[4].red();
osc[8].start();
osc[8].freq(midiToFreq(root + 8));
envo[8].play();
} else if (stringValue === "1010") {
mid[5].red();
osc[9].start();
osc[9].freq(midiToFreq(root + 9));
envo[9].play();
} else if (keyCode === 85) {
black[5].red();
osc[10].start();
osc[10].freq(midiToFreq(root + 10));
envo[10].play();
} else if (stringValue === "1001") {
lSide[6].red();
osc[11].start();
osc[11].freq(midiToFreq(root + 11));
envo[11].play();
} else if (stringValue === "1110") {
rSide[7].red();
osc[12].start();
osc[12].freq(midiToFreq(root + 12));
envo[12].play();
} else if (keyCode === 79) {
black[7].red();
osc[13].start();
osc[13].freq(midiToFreq(root + 13));
envo[13].play();
} else if (stringValue === "0111") {
mid[8].red();
osc[14].start();
osc[14].freq(midiToFreq(root + 14));
envo[14].play();
} else if (keyCode === 80) {
black[8].red();
osc[15].start();
osc[15].freq(midiToFreq(root + 15));
envo[15].play();
} else if (stringValue === "1111") {
lSide[9].red();
osc[16].start();
osc[16].freq(midiToFreq(root + 16));
envo[16].play();
}
}
//ROCKET
//
//
//
if (dVal == 1 && state == "rocket") {
if (gameState == 0) {
gameState = 1;
} else if (gameState == 2) {
gameState = 0;
player1.fuel = 200;
player1.x = 200;
player1.y = 200;
}
}
//Snake
if (state == "snake") {
if (aVal == 1) {
if (direction !== "right") {
direction = "left";
}
} else if (bVal == 1) {
if (direction !== "left") {
direction = "right";
}
} else if (cVal == 1) {
if (direction !== "down") {
direction = "up";
}
} else if (dVal == 1) {
if (direction !== "up") {
direction = "down";
}
}
}
//////////////////////////////////
//SEND TO ARDUINO HERE (handshake)
//////////////////////////////////
let sendToArduino = "\n";
writeSerial(sendToArduino);
}
}
function rSideKey(start, space, kee) {
this.x = start * space;
this.keyWidth = space;
this.col = color(255);
this.kee = kee;
this.size = space / 3;
this.display = function () {
fill(this.col);
beginShape();
vertex(this.x, 0);
vertex(this.x, height);
vertex(this.x + this.keyWidth, height);
vertex(this.x + this.keyWidth, height * 0.6);
vertex(this.x + this.keyWidth * 0.667, height * 0.6);
vertex(this.x + this.keyWidth * 0.667, 0);
endShape();
fill(0);
textSize(this.size);
textFont("Helvetica");
text(this.kee, this.x + this.keyWidth * 0.4, height - this.size);
};
this.red = function () {
this.col = color(255, 0, 0);
};
this.white = function () {
this.col = color(255);
};
}
function BlackKey(start, space, kee) {
this.x = start * space;
this.keyWidth = space;
this.col = color(0);
this.kee = kee;
this.size = space / 3;
this.display = function () {
fill(this.col);
rect(this.x, 0, this.keyWidth * 0.667, height * 0.6);
fill(255);
textSize(this.size);
textFont("Helvetica");
text(this.kee, this.x + this.keyWidth * 0.2, height * 0.6 - this.size);
};
this.red = function () {
this.col = color(255, 0, 0);
};
this.white = function () {
this.col = color(0);
};
}
function MidKey(start, space, kee) {
this.x = start * space;
this.keyWidth = space;
this.col = color(255);
this.kee = kee;
this.size = space / 3;
this.display = function () {
fill(this.col);
beginShape();
vertex(this.x + this.keyWidth * 0.333, 0);
vertex(this.x + this.keyWidth * 0.333, height * 0.6);
vertex(this.x, height * 0.6);
vertex(this.x, height);
vertex(this.x + this.keyWidth, height);
vertex(this.x + this.keyWidth, height * 0.6);
vertex(this.x + this.keyWidth * 0.667, height * 0.6);
vertex(this.x + this.keyWidth * 0.667, 0);
endShape();
fill(0);
textSize(this.size);
textFont("Helvetica");
text(this.kee, this.x + this.keyWidth * 0.4, height - this.size);
};
this.red = function () {
this.col = color(255, 0, 0);
};
this.white = function () {
this.col = color(255);
};
}
function lSideKey(start, space, kee) {
this.x = start * space;
this.keyWidth = space;
this.col = color(255);
this.kee = kee;
this.size = space / 3;
this.display = function () {
fill(this.col);
beginShape();
vertex(this.x + this.keyWidth * 0.333, 0);
vertex(this.x + this.keyWidth * 0.333, height * 0.6);
vertex(this.x, height * 0.6);
vertex(this.x, height);
vertex(this.x + this.keyWidth, height);
vertex(this.x + this.keyWidth, 0);
endShape();
fill(0);
textSize(this.size);
textFont("Helvetica");
text(this.kee, this.x + this.keyWidth * 0.4, height - this.size);
};
this.red = function () {
this.col = color(255, 0, 0);
};
this.white = function () {
this.col = color(255);
};
}
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.speed = 5;
this.color = "green";
this.fuel = 200;
}
move() {
if (aVal == 1) {
this.x -= this.speed;
} else if (cVal == 1) {
this.x += this.speed;
} else if (bVal == 1) {
this.y -= this.speed;
//this is the flame for the rocket ship
noStroke();
fill("red");
rect(this.x, this.y + 50, 10, 50);
fill("orange");
rect(this.x, this.y + 30, 5, 30);
fill("yellow");
rect(this.x, this.y + 20, 2, 20);
this.fuel -= 1;
}
//gravity
if (this.y < 600) {
this.y += 1;
}
}
display() {
stroke(1);
fill(this.color);
triangle(
this.x - 10,
this.y - 25,
this.x + 10,
this.y - 25,
this.x,
this.y - 50
);
rect(this.x, this.y, 20, 50);
fill("black");
ellipse(this.x, this.y - 10, 10, 10);
}
}
function drawSnake() {
background(0);
for (let i = 0; i < numSegments - 1; i++) {
line(xCor[i], yCor[i], xCor[i + 1], yCor[i + 1]);
}
if (snakeMove == false) {
updateSnakeCoordinates();
checkForFruit();
checkGameStatus();
}else{
}
}
/*
The segments are updated based on the direction of the snake.
All segments from 0 to n-1 are just copied over to 1 till n, i.e. segment 0
gets the value of segment 1, segment 1 gets the value of segment 2, and so on,
and this results in the movement of the snake.
The last segment is added based on the direction in which the snake is going,
if it's going left or right, the last segment's x coordinate is increased by a
predefined value 'diff' than its second to last segment. And if it's going up
or down, the segment's y coordinate is affected.
*/
function updateSnakeCoordinates() {
for (let i = 0; i < numSegments - 1; i++) {
xCor[i] = xCor[i + 1];
yCor[i] = yCor[i + 1];
}
switch (direction) {
case "right":
xCor[numSegments - 1] = xCor[numSegments - 2] + diff;
yCor[numSegments - 1] = yCor[numSegments - 2];
break;
case "up":
xCor[numSegments - 1] = xCor[numSegments - 2];
yCor[numSegments - 1] = yCor[numSegments - 2] - diff;
break;
case "left":
xCor[numSegments - 1] = xCor[numSegments - 2] - diff;
yCor[numSegments - 1] = yCor[numSegments - 2];
break;
case "down":
xCor[numSegments - 1] = xCor[numSegments - 2];
yCor[numSegments - 1] = yCor[numSegments - 2] + diff;
break;
}
}
/*
I always check the snake's head position xCor[xCor.length - 1] and
yCor[yCor.length - 1] to see if it touches the game's boundaries
or if the snake hits itself.
*/
function checkGameStatus() {
if (
xCor[xCor.length - 1] > width ||
xCor[xCor.length - 1] < 0 ||
yCor[yCor.length - 1] > height ||
yCor[yCor.length - 1] < 0 ||
checkSnakeCollision()
) {
const scoreVal = parseInt(scoreElem.html().substring(8));
scoreElem.html("Game ended! Your score was : " + scoreVal);
setTimeout(goBack, 3000);
}
}
function goBack() {
state = "intro";
}
/*
If the snake hits itself, that means the snake head's (x,y) coordinate
has to be the same as one of its own segment's (x,y) coordinate.
*/
function checkSnakeCollision() {
const snakeHeadX = xCor[xCor.length - 1];
const snakeHeadY = yCor[yCor.length - 1];
for (let i = 0; i < xCor.length - 1; i++) {
if (xCor[i] === snakeHeadX && yCor[i] === snakeHeadY) {
return true;
}
}
}
/*
Whenever the snake consumes a fruit, I increment the number of segments,
and just insert the tail segment again at the start of the array (basically
I add the last segment again at the tail, thereby extending the tail)
*/
function checkForFruit() {
point(xFruit, yFruit);
if (xCor[xCor.length - 1] === xFruit && yCor[yCor.length - 1] === yFruit) {
const prevScore = parseInt(scoreElem.html().substring(8));
xCor.unshift(xCor[0]);
yCor.unshift(yCor[0]);
numSegments++;
updateFruitCoordinates();
}
}
function updateFruitCoordinates() {
/*
The complex math logic is because I wanted the point to lie
in between 100 and width-100, and be rounded off to the nearest
number divisible by 10, since I move the snake in multiples of 10.
*/
xFruit = floor(random(10, (width - 100) / 10)) * 10;
yFruit = floor(random(10, (height - 100) / 10)) * 10;
}
function mouseClicked() {
if(state == "setup"){
state = "tutorial";
}
else if (state == "tutorial") {
state = "intro";
}
else if (state == "intro") {
if (mouseX < width / 2 && mouseY< height / 2) {
state = "piano";
} else if (mouseX > width / 2 && mouseY < height / 2) {
state = "rocket";
}else if (mouseX < width / 2 && mouseY > height / 2) {
state = "disco";
}
else{
updateFruitCoordinates();
xCor = [];
yCor = [];
for (let i = 0; i < numSegments; i++) {
xCor.push(xStart + i * diff);
yCor.push(yStart);
}
state = "snake";
}
}
}
function drawIntro() {
image(initial, 0, 0);
}