diff --git a/.DS_Store b/.DS_Store index 112f065..306cbd0 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/background/cloud.js b/background/cloud.js new file mode 100644 index 0000000..f14c432 --- /dev/null +++ b/background/cloud.js @@ -0,0 +1,68 @@ +class Cloud { + constructor(cloudGif) { + this.cloudSpeed = 5; + this.x = random(10, windowWidth); + this.y = random(10, windowHeight/2); + this.scalefactor = random(0.07, 0.17); + this.cloudGif = cloudGif; + } + + collidesWith(otherCloud) { + return ( + this.x < otherCloud.x + otherCloud.cloudGif.width && + this.x + this.cloudGif.width > otherCloud.x && + this.y < otherCloud.y + otherCloud.cloudGif.height && + this.y + this.cloudGif.height > otherCloud.y + ); + } + + move(direction) { + if (direction < 0) { + this.x += this.cloudSpeed; + } else { + this.x -= this.cloudSpeed; + } + + if (this.x > width) this.x = 0; + if (this.x < 0) this.x = width; + } + + render() { + push(); + imageMode(CENTER); + image(this.cloudGif, this.x, this.y, this.cloudGif.width * this.scalefactor, this.cloudGif.height * this.scalefactor); + pop(); + // if (cloudGif) { + + // } + } +} + +function updateAndRenderClouds(clouds, moving, direction) { + for (let cloud of clouds) { + if (moving) { + cloud.move(direction); + } + cloud.render(); + } +} + + +function createCloud(clouds, cloudGif) { + let newCloud; + let attempts = 0; + const maxAttempts = 100; // Prevent infinite loop + + while (attempts < maxAttempts) { + newCloud = new Cloud(cloudGif); + attempts++; + + // Check collision with existing clouds + let collided = clouds.some(cloud => newCloud.collidesWith(cloud)); + + if (!collided || attempts >= maxAttempts) { + clouds.push(newCloud); + break; + } + } +} \ No newline at end of file diff --git a/background/grass.js b/background/grass.js new file mode 100644 index 0000000..d106faa --- /dev/null +++ b/background/grass.js @@ -0,0 +1,49 @@ +class GrassPoke { + constructor(index) { + this.x = map(index, 0, 100 - 1, 0, width) + this.y = random(130, 150); + this.controlPointY = random(10, 30); + this.speed = 5 + } +} + +function drawGrass(direction, grassPokes) { + push(); + + let grassTipColor = color('#9EB287'); + let grassBaseColor = color('#66816D'); + + // Move grass pokes + for (let poke of grassPokes) { + poke.x -= direction * poke.speed; + if (poke.x < 0) poke.x += width; + if (poke.x > width) poke.x -= width; + } + + // Sort pokes by x + grassPokes.sort((a, b) => a.x - b.x); + + // Draw grass pokes + noStroke(); + beginShape(); + + // Start at the bottom-left corner + vertex(0, height); + + // Draw each poke + for (let poke of grassPokes) { + let gradient = drawingContext.createLinearGradient(poke.x, height, poke.x, height - poke.y); + gradient.addColorStop(0, grassBaseColor.toString()); + gradient.addColorStop(1, grassTipColor.toString()); + drawingContext.fillStyle = gradient; + + // Draw the poke + curveVertex(poke.x, height - poke.y); + } + + // End at the bottom-right corner + vertex(width, height); + + endShape(CLOSE); + + } diff --git a/rain.js b/background/rain.js similarity index 55% rename from rain.js rename to background/rain.js index f763099..ba61dc3 100644 --- a/rain.js +++ b/background/rain.js @@ -2,9 +2,10 @@ class Rain { constructor() { this.isRaining = false; this.timeBetweenRain = random(200, 500); - this.rainSpeed = 5; // Adjust this for faster/slower rain movement - this.x = windowWidth + 300; // Start off-screen to the right + this.rainSpeed = 5; + this.x = windowWidth + 300; this.y = 300; + this.rainGif; } move(moving, direction) { @@ -17,19 +18,15 @@ class Rain { this.timeBetweenRain--; } } else { - // Move rain based on character's direction this.x -= this.rainSpeed * direction; - // Stop raining when rain moves off screen on either side if (this.x < -300 || this.x > windowWidth + 300) { this.isRaining = false; this.timeBetweenRain = random(200, 500); } } } else { - // If character stops, gradually slow down the rain if (this.isRaining) { - this.x -= this.rainSpeed * 0.5; // Slow movement if (this.x < -300) { this.isRaining = false; this.timeBetweenRain = random(200, 500); @@ -39,6 +36,7 @@ class Rain { } render(rainGif) { + rain.rainGif = rainGif if (this.isRaining && rainGif) { push(); imageMode(CENTER); @@ -51,4 +49,34 @@ class Rain { function updateAndRenderRain(rain, moving, direction, rainGif) { rain.move(moving, direction); rain.render(rainGif); +} + +let lastScoreDecrease = 0 +scoreDecreaseInterval = 1000 + +function updateScoreRain(rain, moving, charX, charWidth, showUmbrella, score, currentTime) { + // If it is raining in frame + if (rain.isRaining && !showUmbrella && currentTime - lastScoreDecrease >= scoreDecreaseInterval) { + // Entering Rain + if (charX + charWidth / 2 > rain.x && charX < rain.x + rain.rainGif.width * 0.3){ + lastScoreDecrease = currentTime + return score - 1 + } + // Inside Rain + else if (rain.x < charX && rain.x + rain.rainGif.width * 0.3 > charX + charWidth / 2){ + lastScoreDecrease = currentTime + return score - 1 + } + // Exiting Rain + else if (rain.x + rain.rainGif.width * 0.3 > charX && charX > rain.x) { + lastScoreDecrease = currentTime + return score - 1 + } + else { + return score + } + } + else { + return score + } } \ No newline at end of file diff --git a/star.js b/background/star.js similarity index 84% rename from star.js rename to background/star.js index b098717..d08b31a 100644 --- a/star.js +++ b/background/star.js @@ -1,20 +1,18 @@ class Star { constructor() { - this.x = random(10, width); - this.y = random(10, height); + this.x = random(10, windowWidth); + this.y = random(10, windowHeight/2); this.size = random(30, 50); this.speed = random(1, 3); } move(direction) { - // Move stars in the opposite direction of character movement if (direction > 0) { this.x += this.speed; } else { this.x -= this.speed; } - - // Wrap around the screen + if (this.x > width) this.x = 0; if (this.x < 0) this.x = width; } diff --git a/index.html b/index.html index aedee0d..4388800 100644 --- a/index.html +++ b/index.html @@ -10,8 +10,10 @@
- - + + + + diff --git a/sketch.js b/sketch.js index 7fc697c..ffae576 100644 --- a/sketch.js +++ b/sketch.js @@ -1,46 +1,101 @@ -let stillFrame, runningGif, rainGif; +let stillFrame, runningGif, rainGif, grainImage, umbrellaImage;; let speed = 5; let direction = 0; // -1 for left, 0 for still, 1 for right -let curPos; +let charX; +let charY; // Star Background let stars = []; -const numStars = 100; +const numStars = 40; let starImages; +// Cloud Background +let clouds = []; +const numClouds = 6; + +// Grass Background +let grassPokes = [] +let numGrassPokes = 100; + +// Umbrella +let showUmbrella = false; + +// Score System +let score = 10; + function preload() { stillFrame = loadImage('./static/stillFrame.png'); runningGif = loadImage("./static/runFrame.gif"); yellowStarImage = loadImage('./static/yellow_star.png'); pinkStarImage = loadImage('./static/pink_star.png'); - - rainGif = loadImage("./static/rainFrame.gif"); + rainGif = loadImage("./static/rain.gif"); + cloudGif = loadImage("./static/cloud.gif"); + grainImage = loadImage('./static/grainAttempt2.jpeg'); + umbrellaGif = loadImage('./static/umbrella.gif'); } function setup() { - //canvas = createCanvas(900, 600); canvas = createCanvas(windowWidth, windowHeight); - centerCanvas(); imageMode(CENTER); - curPos = width / 2; + charX = width / 2; + charY = height - 250; // Create stars for background + starImages = [pinkStarImage, yellowStarImage]; for (let i = 0; i < numStars; i++) { stars.push(new Star()); } - starImages = [pinkStarImage, yellowStarImage]; + + // Create rain cloud rain = new Rain(); -} -function centerCanvas() { - let x = (windowWidth - width) / 2; - let y = (windowHeight - height) / 2; - canvas.position(x, y); + // Create clouds for background + for (let i = 0; i < numClouds; i++) { + createCloud(clouds, cloudGif); + } + + // Create grass pokes + for (let i = 0; i < numGrassPokes; i++) { + grassPokes.push(new GrassPoke(i)); + } } function draw() { - background('#030b07'); + // background + + // Perplexity.AI helped with creating gradient background + let c1 = color('#432749'); // purple + let c2 = color('#E17E84'); // pink + let c3 = color('#EEE790'); // yellow + for (let y = 0; y < height; y++) { + let inter1 = map(y, 0, height/2, 0, 1); + let inter2 = map(y, height/2, height, 0, 1); + let c; + + if (y < height/2) { + c = lerpColor(c1, c2, inter1); + } else { + c = lerpColor(c2, c3, inter2); + } + + stroke(c); + line(0, y, width, y); + } + + // Draw grass + drawGrass(direction, grassPokes); + + // Apply grain + push(); + blendMode(OVERLAY); + tint(255, 80); + image(grainImage, 0, 0, width , height); + image(grainImage, width, height, width , height); + image(grainImage, 0, height, width , height); + image(grainImage, width, 0, width , height); + pop(); + // Check for key presses if (keyIsDown(RIGHT_ARROW)) { direction = 1; @@ -50,25 +105,64 @@ function draw() { direction = 0; } - // Move and display stars + if (keyIsDown(UP_ARROW)) { + showUmbrella = true; + } else { + showUmbrella = false; + } + + // Update and display stars updateAndRenderStars(stars, direction !== 0, -direction, starImages); // Update and display rain updateAndRenderRain(rain, direction !== 0, direction, rainGif) - - // Calculate y position to place the bottom of the image at the bottom of the canvas - let yPos = height - (stillFrame.height * 0.4/ 2); - + + // Update and display clouds + updateAndRenderClouds(clouds, direction !== 0, direction) + + // Update and display Score + displayScore() + score = updateScoreRain(rain, direction !== 0, charX, runningGif.width, showUmbrella, score, millis()) + // Display character push(); if (direction !== 0) { // Running - translate(curPos, yPos); + translate(charX, charY); scale(direction, 1); // Flip horizontally if moving left image(runningGif, 0, 0, runningGif.width * 0.3, runningGif.height * 0.3); + if (showUmbrella) { + image(umbrellaGif, 15, -250, umbrellaGif.width * 0.25, umbrellaGif.height * 0.25); + } } else { // Standing still - image(stillFrame, curPos, yPos, stillFrame.width * 0.3, stillFrame.height * 0.3); + image(stillFrame, charX, charY, stillFrame.width * 0.3, stillFrame.height * 0.3); } pop(); -} \ No newline at end of file + + // Check if gameover + checkDeath() +} + +function displayScore() { + push(); + fill(255); + textSize(24); + textAlign(LEFT, TOP); + text(score, 10, 10); + pop(); +} + +function checkDeath() { + if (score < 0) { + noLoop(); // Stop the game + push(); + fill(255); + textSize(48); + textAlign(CENTER, CENTER); + text("Game Over", width/2, height/2); + pop(); + } +} + + diff --git a/static/cloud.gif b/static/cloud.gif index ddf2283..9a16ba5 100644 Binary files a/static/cloud.gif and b/static/cloud.gif differ diff --git a/static/grainAttempt1.jpeg b/static/grainAttempt1.jpeg new file mode 100644 index 0000000..69ee979 Binary files /dev/null and b/static/grainAttempt1.jpeg differ diff --git a/static/grainAttempt2.jpeg b/static/grainAttempt2.jpeg new file mode 100644 index 0000000..4e316d2 Binary files /dev/null and b/static/grainAttempt2.jpeg differ diff --git a/static/rain.gif b/static/rain.gif new file mode 100644 index 0000000..3393e42 Binary files /dev/null and b/static/rain.gif differ diff --git a/static/rainFrame.gif b/static/rainFrame.gif deleted file mode 100644 index b742537..0000000 Binary files a/static/rainFrame.gif and /dev/null differ diff --git a/static/umbrella.gif b/static/umbrella.gif new file mode 100644 index 0000000..d8d5c99 Binary files /dev/null and b/static/umbrella.gif differ