xxxxxxxxxx
508
let capture;
let fruits = [];
let bombs = [];
let mango, pine, watermelon;
let bmb;
let images = [];
let hands = [];
let readyToGo = false;
let sliceLines = [];
let handpose;
let previousPositions = {};
let cnv;
let score = 0;
let trails = {};
let flashBangActive = false;
let flashBangDuration = 120;
let flashBangIntensity = 255;
let lives =3 ;
let music;
let x=0,y=200 ,x2=0, y2=200;
function preload() {
mango = loadImage("images/Mango.png");
pine = loadImage("images/Pineapple.png");
watermelon = loadImage("images/Watermelon.png");
bmb = loadImage("images/bomb.png");
music = loadSound("bg.mp3");
}
function setup() {
music.loop();
frameRate(60);
images.push(mango);
images.push(pine);
images.push(watermelon);
cnv = createCanvas(640, 480);
cnv.position((windowWidth - width) / 2, (windowHeight - height) / 2);
//start video capture
capture = createCapture(VIDEO);
capture.size(width, height);
handpose = ml5.handpose(capture, modelReady);
handpose.on("predict", function(results) {
hands = results;
});
capture.hide();
}
function modelReady() {
console.log("Handpose Model Ready!");
readyToGo = true;
}
function keyPressed() {
if (key == " ") {
setUpSerial();
}
}
function draw() {
if (!serialActive) {
fill(255);
textSize(25);
text("Press Space Bar to select Serial Port", 60, 60);
} else {
text("Connected", 20, 30);
}
if (readyToGo && serialActive) {
translate(capture.width, 0);
scale(-1, 1);
image(capture, 0, 0, width, height);
push();
fill(255);
textSize(25);
scale(-1, 1);
text("Score: " + score, -width+80, 40);
pop();
let indx = floor(random(images.length))
//generate fruits and bombs over time
if (frameCount % 10 == 0) {
fruits.push(new Fruit(indx));
}
if (frameCount % 50 == 0) {
fruits.push(new Fruit(indx));
bombs.push(new Bomb());
}
//keep updating the location of fruits and bombs and check if the user sliced
if(lives>0){
for (let i = fruits.length - 1; i >= 0; i--) {
fruits[i].update();
fruits[i].show();
if (fruits[i].isOffScreen()) {
fruits.splice(i, 1);
}
}
for (let i = bombs.length - 1; i >= 0; i--) {
bombs[i].update();
bombs[i].show();
if (bombs[i].isOffScreen()) {
bombs.splice(i, 1);
}
}
}
//create a slicing line effect
for (let i = sliceLines.length - 1; i >= 0; i--) {
let slice = sliceLines[i];
push();
translate(slice.x, slice.y);
rotate(slice.angle);
stroke(255, 0, 0, map(slice.lifespan, 60, 0, 255, 0));
strokeWeight(2);
line(-25, 0, 25, 0);
pop();
slice.lifespan -= 1;
if (slice.lifespan <= 0) {
sliceLines.splice(i, 1);
}
}
//check hands
if(hands.length>0){
didCollide();
checkBombCollisions();
}
//have flashbang effect if bomb is sliced
if (flashBangActive) {
fill(255, flashBangIntensity);
rect(0, 0, width, height);
push();
translate(width, 0);
scale(-1, 1);
textSize(32);
fill(0, flashBangIntensity);
textAlign(CENTER, CENTER);
text( lives + " lives left", width / 2, height / 2);
pop();
flashBangIntensity -= 255 / flashBangDuration;
if (flashBangIntensity < 0) {
flashBangActive = false;
flashBangIntensity = 0;
}
}
updatePreviousPositions(hands);
ellipse(x,y,15,15)
} else {
textSize(50);
textAlign(CENTER);
fill(255);
text("Model Loading", width / 2, height / 2);
}
if (lives <= 0) {
// noLoop();
push();
translate(width, 0);
scale(-1, 1);
background(0);
fill(255);
textSize(50);
textAlign(CENTER, CENTER);
text("Game Over", width / 2, height / 2 - 50);
textSize(32);
text("Score: " + score, width / 2, height / 2);
textSize(25);
text("Press 'R' to Restart", width / 2, height / 2 + 50);
pop();
if (keyIsPressed && key === 'r') {
loop()
flashBangIntensity = 255;
flashBangActive = false;
score = 0;
lives = 3;
fruits = [];
bombs = [];
sliceLines = [];
previousPositions = {};
hands =[];
}
}
}
class Fruit {
constructor(index) {
this.x = random(width);
this.y = height - 10;
this.size = 100;
this.index = index;
this.type = 'fruit';
this.speed = random(10, 15);
let angleRange = random([true, false]) ? [PI / 3, 2 * PI / 3] : [4 * PI / 3, 5 * PI / 3];
this.angle = random(angleRange[0], angleRange[1]);
this.vx = this.speed * cos(this.angle);
this.vy = (this.speed) * sin(this.angle);
this.rotation = 0;
this.rotationSpeed = random(-0.1, 0.1);
this.sliced = false;
this.half1 = null;
this.half2 = null;
}
update() {
if (!this.sliced) {
this.vy += 0.2;
this.x += this.vx;
this.y += this.vy;
this.rotation += this.rotationSpeed;
} else {
this.updateHalf(this.half1);
this.updateHalf(this.half2);
}
}
isOffScreen() {
return (this.y > height || this.x < 0 || this.x > width);
}
show() {
push();
if (!this.sliced) {
translate(this.x + this.size / 2, this.y + this.size / 2);
rotate(this.rotation);
imageMode(CENTER);
image(images[this.index], 0, 0, this.size, this.size);
} else {
this.showHalf(this.half1, 'left');
this.showHalf(this.half2, 'right');
}
pop();
}
//half the fruit when sliced
showHalf(half, direction) {
push();
translate(half.x, half.y);
rotate(half.rotation);
imageMode(CENTER);
let img = images[this.index];
let imgWidth = img.width;
let imgHeight = img.height;
let sx = direction === 'left' ? 0 : imgWidth / 2;
let sy = 0;
let swidth = imgWidth / 2;
let sheight = imgHeight;
copy(img, sx, sy, swidth, sheight, -this.size / 4, -this.size / 2, this.size / 2, this.size);
pop();
}
slice(angle) {
this.sliced = true;
let sliceSpeed = 5;
let angle1 = angle + PI / 4;
let angle2 = angle - PI / 4;
this.half1 = {
x: this.x,
y: this.y,
vx: sliceSpeed * cos(angle1),
vy: sliceSpeed * sin(angle1),
rotation: this.rotation
};
this.half2 = {
x: this.x,
y: this.y,
vx: sliceSpeed * cos(angle2),
vy: sliceSpeed * sin(angle2),
rotation: this.rotation
};
}
updateHalf(half) {
half.vx *= 0.99;
half.vy += 0.5;
half.rotation += this.rotationSpeed;
half.x += half.vx;
half.y += half.vy;
}
}
//get previous position of user's hand to compare it with its currrent position to check for slicing
function updatePreviousPositions(hands) {
for (let i = 0; i < hands.length; i++) {
let hand = hands[i];
let sumX = 0, sumY = 0; // Variables to store the sum of x and y coordinates
let count = 0; // Counter for the number of landmarks
// Calculate the sum of all landmark positions
for (let j = 0; j < hand.landmarks.length; j++) {
let landmark = hand.landmarks[j];
sumX += landmark[0];
sumY += landmark[1];
count++;
}
if (count > 0) {
let avgX = sumX / count; // Calculate average X
let avgY = sumY / count; // Calculate average Y
if (!previousPositions['average']) {
previousPositions['average'] = [];
}
previousPositions['average'].unshift({ x: avgX, y: avgY });
if (previousPositions['average'].length > 20) {
previousPositions['average'].pop();
}
// Now update the x2, y2 to the second most recent position if available
x2 = previousPositions['average'].length > 1 ? previousPositions['average'][1].x : avgX;
y2 = previousPositions['average'].length > 1 ? previousPositions['average'][1].y : avgY;
fill(255, 0, 0);
noStroke();
x=avgX;
}
}
}
function slicingMotionDetected(currentX, currentY, previousX, previousY, fruit) {
if (previousX == null || previousY == null) return false;
let distance = dist(currentX, currentY, previousX, previousY);
let fruitDistance = dist(currentX, currentY, fruit.x, fruit.y);
return distance > 20 && fruitDistance < (fruit.size / 2);
}
function didCollide() {
for (let i = fruits.length - 1; i >= 0; i--) {
let fruit = fruits[i];
if (!fruit.sliced && slicingMotionDetected(x, y,x2,y2, fruit)) {
let angle = atan2(y - y2, x - x2); // Compute slice angle
sliceLines.push({ x: fruit.x, y: fruit.y, angle: angle, lifespan: 60 });
fruit.slice(angle);
score++;
break; // Break if collision is detected
}
}
}
class Bomb {
constructor() {
this.x = random(width);
this.y = height - 10;
this.size = 50;
this.type = 'bomb';
this.speed = random(15, 20);
let angleRange = random([true, false]) ? [PI / 3, 2 * PI / 3] : [4 * PI / 3, 5 * PI / 3];
this.angle = random(angleRange[0], angleRange[1]);
this.vx = this.speed * cos(this.angle);
this.vy = (this.speed) * sin(this.angle);
this.rotation = 0;
this.rotationSpeed = random(-0.1, 0.1);
this.sliced = false;
this.half1 = null;
this.half2 = null;
}
update() {
if (!this.sliced) {
this.vy += 0.2;
this.x += this.vx;
this.y += this.vy;
this.rotation += this.rotationSpeed;
} else {
this.updateHalf(this.half1);
this.updateHalf(this.half2);
}
}
isOffScreen() {
return (this.y > height || this.x < 0 || this.x > width);
}
show() {
push();
if (!this.sliced) {
translate(this.x + this.size / 2, this.y + this.size / 2);
rotate(this.rotation);
imageMode(CENTER);
image(bmb, 0, 0, this.size, this.size);
} else {
}
pop();
}
}
function checkBombCollisions() {
for (let i = bombs.length - 1; i >= 0; i--) {
let bomb = bombs[i];
if (slicingMotionDetected(x, y,x2,y2, bomb)) {
bombs.splice(i, 1);
flashBangActive = true;
flashBangIntensity = 255;
lives--;
break; // Break if collision is detected
}
}
}
function readSerial(data) {
////////////////////////////////////
//READ FROM ARDUINO HERE
////////////////////////////////////
if (data != null) {
let fromArduino = split(trim(data), ",");
// if the right length, then proceed
if (fromArduino.length == 2) {
y = map(int(fromArduino[1]), -60, 60, -60, height+60);
}
}
}