// create a hand recognizer to keep track of hand movements in the camera view const face = new FaceRecognizer(); let mouthTop, mouthBottom, mouthLeft, mouthRight; let foodPos; let foodType; let foodImages = []; let food1, food2, food3, food4, food5, food6; let score = 0; //const foodSpeed = 5; const foodVel = {x: 0, y: 5}; function preload() { food1 = loadImage("./assets/apple-1.png"); food2 = loadImage("./assets/corn.png"); food3 = loadImage("./assets/cupcake.png"); food4 = loadImage("./assets/drumstick.png"); food5 = loadImage("./assets/pie.png"); food6 = loadImage("./assets/pumpkin.png"); } function setup() { // create canvas with specified size, camera will resize automatically createCanvas(480, 360); // set target framerate frameRate(30); foodImages = [food1, food2, food3, food4, food5, food6]; spawnNewFood(); // show video with 50% opacity over canvas face.showVideo(30); imageMode(CENTER); food1.resize(50, 0); food2.resize(50, 0); food3.resize(50, 0); food4.resize(50, 0); food5.resize(50, 0); food6.resize(50, 0); } function draw() { clear(); background("#9F5D3480"); // predict gestures with the camera face.predict(); face.drawLandmarks(false); // Drop a new food when the old one is fully offscreen if (foodIsOffScreen()) { score--; spawnNewFood(); } // Update food position //foodPos.y += foodSpeed; foodPos.y += foodVel.y; renderFood(); // Check if this food got eaten mouthTop = face.getLandmark(Landmarks.Middle_Upper_Lip); mouthBottom = face.getLandmark(Landmarks.Middle_Lower_Lip); mouthLeft = face.getLandmark(Landmarks.Left_Lip_Corner); mouthRight = face.getLandmark(Landmarks.Right_Lip_Corner); //if (detectEat()) { if (foodIsInMouth() && mouthIsOpen(20)) { score++; spawnNewFood(); } renderScore(score, 255, 32, RIGHT, width-20, 40); } function foodIsInMouth() { return (foodPos.x > mouthLeft.x && foodPos.x < mouthRight.x && foodPos.y > mouthTop.y && foodPos.y < mouthBottom.y); } function mouthIsOpen(distance) { return (dist(mouthTop.x, mouthTop.y, mouthBottom.x, mouthBottom.y) > distance); } ////////////////////////////////////////////////////////// // // // Helper functions defined below with explanations // // // ////////////////////////////////////////////////////////// /** * Resets food-related variables to preset values. * Position is reset to the top edge of the canvas. * Image is set to a random selection */ function spawnNewFood() { foodPos = {x: random(width), y: 0}; foodType = random([0, 1, 2, 3, 4, 5]); } /** * Checks if the food has fallen offscreen by checking its y-coordinate. * @return {Boolean} Whether the food has fallen below the bottom edge of the screen. */ function foodIsOffScreen() { return foodPos.y > height + foodImages[foodType].height / 2; } /** * Checks if the upper lip is touching the food and the mouth is open. TODO: remove if we're committing to having the student write these checks, this is currently unused * Treats food as roughly circular. * @return {Boolean} Whether the open mouth has made contact with the food. */ function detectEat() { //let bladeTip = getTip(); let mouthTop = face.getLandmark(Landmarks.Middle_Upper_Lip); let mouthBottom = face.getLandmark(Landmarks.Middle_Lower_Lip); let mouthLeft = face.getLandmark(Landmarks.Left_Lip_Corner); let mouthRight = face.getLandmark(Landmarks.Right_Lip_Corner); //let foodRadius = foodSprites[foodType].width / 2; //if (dist(mouthTop.x, mouthTop.y, mouthBottom.x, mouthBottom.y) > 30 && dist(mouthTop.x, mouthTop.y, foodPos.x, foodPos.y) < foodRadius) { if (dist(mouthTop.x, mouthTop.y, mouthBottom.x, mouthBottom.y) > 30 && foodPos.x > mouthLeft.x && foodPos.x < mouthRight.x && foodPos.y > mouthTop.y && foodPos.y < mouthBottom.y) { return true; } return false; } /** * Renders the current food according to its current position/s, color, size, and shrink factor. */ function renderFood() { imageMode(CENTER); let foodImage = foodImages[foodType]; image(foodImage, foodPos.x, foodPos.y, foodImage.width, foodImage.height); } /** * Renders the player's score. * @param {number} score The player's score. * @param {array} color The color of the text as an [R, G, B] array. * @param {number} fontSize The size of the text. * @param {LEFT|CENTER|RIGHT} alignment The horizontal alignment of the text. * @param {number} x The x-coordinate of the text. * @param {number} y The y-coordinate of the text. */ function renderScore(score, color, fontSize, alignment, x, y) { noStroke(); fill(color); textSize(fontSize); textAlign(alignment); text("Score: " + score, x, y); }