xxxxxxxxxx
430
let fruits = [];
let basketY;
let lives = 3;
let score = 0;
let highScore = 0;
let fruitSpeed = 2;
let spawnInterval = 1500;
let basketColor = "";
let bgImage;
let basketImage;
let titleImage;
let gameState = "title"; // Possible states: title, instructions, play
let playButton, instructionsButton;
let myFont;
let fruitImages = {};
let lastSpawnTime = 0; // tracks time for spawning fruits
let spawnDelay = 15000; // initial delay between spawns
// Oscillator for notes
let oscillator;
let frequencies = {
"Cm": 261.63, // C4
"G#": 415.30, // G#4
"D#": 311.13, // D#4
"D": 293.66 // D4
};
let chordSequence = ["Cm", "G#", "D#", "D"];
let currentChordIndex = 0;
function preload() {
bgImage = loadImage('images/bg.png');
basketImage = loadImage('images/basket.png');
titleImage = loadImage('images/title.png'); // Load full-screen title image
myFont = loadFont('fonts/etna.otf');
// load fruit images
fruitImages.green = loadImage('images/1.png');
fruitImages.yellow = loadImage('images/2.png');
fruitImages.blue = loadImage('images/3.png');
fruitImages.red = loadImage('images/4.png');
}
function setup() {
createCanvas(windowWidth, windowHeight);
basketY = height - 50;
// set the font
textFont(myFont);
textSize(50);
fill(0);
// Buttons for title screen
playButton = createButton('Play Game');
playButton.position(width / 2 - 170, height / 2 - 20);
playButton.style('font-size','32px');
playButton.style('background-color','#4CAF50');
playButton.style('color','black');
//playButton.style('border', 'none');
playButton.mousePressed(() => {
gameState = "play";
playButton.hide();
instructionsButton.hide();
startGame();
});
instructionsButton = createButton('Instructions');
instructionsButton.position(width / 2 + 20, height / 2 - 20);
instructionsButton.style('font-size','32px');
instructionsButton.style('background-color','#4CAF50');
instructionsButton.style('color','black');
//instructionsButton.style('border', 'none');
instructionsButton.mousePressed(() => {
gameState = "instructions";
playButton.hide();
instructionsButton.hide();
});
// creates the oscillator
oscillator = new p5.Oscillator();
oscillator.setType('sine'); // use sine wave
oscillator.amp(0); // set initial amplitude to 0
oscillator.start();
// Shuffle chords initially
shuffleArray(chordSequence);
//Spawn fruits periodically
setInterval(spawnFruit,spawnInterval);
}
function draw() {
if (gameState === "title") {
displayTitleScreen();
} else if (gameState === "instructions") {
displayInstructions();
} else if (gameState === "play") {
playGame();
}
}
function displayTitleScreen() {
background(0);
image(titleImage, 0, 0, width, height); // Full-screen title image
textFont(myFont);
textSize(50);
fill(0);
textAlign(LEFT,CENTER);
text("Catch That Note!", width/2 - 170, height/4);
}
function displayInstructions() {
background(0);
image(titleImage, 0, 0, width, height); // Full-screen title image
textAlign(CENTER, CENTER);
fill('black');
textSize(30);
text("Instructions", width / 2, height / 4);
textSize(20);
text("Fruits are falling. Press the arcade button matching the fruit color.", width / 2, height / 2 - 120);
text("Colors:", width / 2, height / 2 - 90);
text("Blue: Blueberries | Red: Strawberries | Green: Green Pear | Yellow: Banana", width / 2, height / 2 - 70);
text("If you press the wrong color or let the fruit fall, you lose a life.", width / 2, height / 2 - 40);
text("Press 'M' to return to the Main Menu.", width / 2, height / 2 - 10);
}
function playGame() {
background(bgImage);
image(basketImage, width / 2 - 50, basketY, 250, 150);
// spawnFruit();
// update and draw fruits
for (let i = fruits.length - 1; i >= 0; i--) {
let fruit = fruits[i];
fruit.update();
fruit.display();
// check if fruit is our of bounds
if (fruit.isOutOfBounds()) {
console.log("Fruit went out of bounds"); // Debugging info
lives--;
fruits.splice(i, 1);
}
}
// Debugging info to track the fruits array
console.log(`Current fruits on screen: ${fruits.length}`);
// display score and lives
fill(0);
textSize(20);
text(`Score: ${score}`, 10, 30);
if (score > highScore) {
highScore = score;
}
text(`High Score: ${highScore}`, 10, 60);
text(`Lives: ${lives}`, 10, 90);
// end game
if (lives <= 0) {
textSize(40);
text("Game Over", width / 2, height / 2);
textSize(20);
text("Press 'T' to Restart", width / 2, height / 2 + 50);
noLoop();
}
}
function startGame() {
score = 0;
lives = 3;
fruits = [];
fruitSpeed = 2;
spawnDelay = 15000;
currentChordIndex = 0;
lastSpawnTime = 0;
shuffleArray(chordSequence);
}
class Fruit {
constructor(x, y, color, chord) {
this.x = x;
this.y = y;
this.color = color;
this.chord = chord;
// this.radius = 40;
this.velocity = fruitSpeed;
}
display() {
/* let colorMap = {
blue: color(0,0,255),
red: color(255,0,0),
green: color(0,255,0),
yellow: color(255,255,0),
};
fill(colorMap[this.color]);
noStroke();
ellipse(this.x,this.y,this.radius *2);
// overlay the image
let colorToImage = {
blue: fruitImages.blue,
red: fruitImages.red,
green: fruitImages.green,
yellow: fruitImages.yellow,
};
let img = colorToImage[this.color];
if(img){
imageMode(CENTER);
image(img, this.x, this.y, this.radius * 2, this.radius * 2);
}
}
update() {
this.y += this.velocity;
}
isOutOfBounds() {
return this.y > height;
}
*/
if (fruitImages[this.color]) {
image(fruitImages[this.color], this.x - 15, this.y - 15, 80, 80); // Draw the fruit image
} else {
fill(255); // Fallback in case the image is missing
ellipse(this.x, this.y, 70, 70);
}
}
update() {
this.y += this.velocity;
}
isOutOfBounds() {
return this.y > height;
}
}
function spawnFruit() {
/*
// check if enough time has passed to spawn a new one
if(millis() - lastSpawnTime > spawnDelay && fruits.length < 1){
// Reset and shuffle the chord sequence if the index exceeds its length
if(currentChordIndex >= chordSequence.length){
currentChordIndex = 0;
shuffleArray(chordSequence);
}
}
let currentChord = chordSequence[currentChordIndex];
let chordToColor = {
"Cm": "red",
"G#": "green",
"D#": "yellow",
"D": "blue",
};
//let currentChord = chordSequence[currentChordIndex];
let color = chordToColor[currentChord];
if(!color){
console.error(`Invalid chord or color mapping: ${currentChord}`);
return; // Skip this iteration if there's an invalid mapping
}
let x = random(50, width - 50);
fruits.push(new Fruit(x, 0, color, currentChord));
console.log(`Spawned fruit: ${color}`); // Debugging info
// increment the chord index
currentChordIndex++;
lastSpawnTime = millis(); // update spawn time
// gradually increase spped
if (fruitSpeed < 10){
fruitSpeed += 0.1;
}
// reduce spawn delay gradually
if(spawnDelay > 500){
spawnInterval -= 20;
} */
if (currentChordIndex >= chordSequence.length) {
currentChordIndex = 0; // Restart the chord sequence
shuffleArray(chordSequence); // Shuffle the sequence each loop
}
let chordToColor = {
"Cm": "red",
"G#": "green",
"D#": "yellow",
"D": "blue",
};
let currentChord = chordSequence[currentChordIndex];
let color = chordToColor[currentChord];
// Spawn the fruit
let x = random(50, width - 50);
fruits.push(new Fruit(x, 0, color, currentChord));
// Move to the next chord in the sequence
currentChordIndex++;
// Gradually increase the speed
if (fruitSpeed < 20) {
fruitSpeed += 0.5;
}
if (spawnInterval > 300) {
spawnInterval -= 20;
}
}
function keyPressed() {
if(key === " "){
setUpSerial();
}
// Ensure audio context is resumed
let audioContext = getAudioContext();
if (audioContext.state !== 'running') {
audioContext.resume();
}
if (gameState === "instructions" && key.toLowerCase() === "m") {
gameState = "title";
playButton.show();
instructionsButton.show();
return;
}
if ( key.toLowerCase() === "m") {
gameState = "title";
playButton.show();
instructionsButton.show();
return;
}
if (key === "t" && gameState === "play") {
score = 0;
lives = 3;
fruits = [];
currentChordIndex = 0;
fruitSpeed = 2; // Reset the falling speed
spawnInterval = 1500; // Reset the spawn interval
shuffleArray(chordSequence); // Shuffle the chords
loop();
return;
}
if (gameState === "play") {
let keyToColor = {
b: "blue",
r: "red",
g: "green",
y: "yellow",
};
if (fruits.length > 0) {
let firstFruit = fruits[0];
let matchedColor = keyToColor[key.toLowerCase()];
if (firstFruit.color === matchedColor) {
score++;
playNote(firstFruit.chord);
fruits.splice(0, 1);
} else {
lives--;
fruits.splice(0, 1);
}
}
}
}
function playNote(chord) {
let freq = frequencies[chord];
if (freq) {
oscillator.freq(freq);
oscillator.amp(0.5, 0.1); // Increase amplitude to hear the note
setTimeout(() => {
oscillator.amp(0, 0.5); // Fade out after a short time
}, 500);
}
}
// Utility function to shuffle an array
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(random(0, i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function readSerial(data) {
// Process incoming serial data from the Arduino
let input = data.trim(); // Remove any whitespace or newline characters
// Map serial input to colors
let serialToColor = {
b: "blue",
r: "red", // Replace w with r
g: "green",
y: "yellow",
};
if (fruits.length > 0) {
let firstFruit = fruits[0];
if (serialToColor[input] === firstFruit.color) {
score++;
playNote(firstFruit.chord); // Play the corresponding note
fruits.splice(0, 1); // Remove the matched fruit
} else {
lives--; // Lose a life for incorrect button press
fruits.splice(0, 1); // Remove the mismatched fruit
}
}
}