xxxxxxxxxx
992
//Game Variables
let gameState = "START"; // initial state
let startButton;
let startButtonX, startButtonY, startButtonW, startButtonH;
let restartButton;
let restartButtonX, restartButtonY, restartButtonW, restartButtonH;
let isAudioOn = 1;
let camX = 0;
let speed = 5;
//Particle animation variables
let particles = []; //array to store particles
let noiseScale = 0.001; //for controlling size of noise changes in different contexts
let timeMove = 0; //for changing positions
let timeC = 0; //for changing color
let timeIncrementMove = 0.005; //control values for increments in both time variables
let timeIncrementColor = 0.008;
let currSpeed = 3; //controls movement speed of animation
//Project coordinates
const ART_START = 1700; //x coordinate where e art start in the background
const ART_LENGTH = 400;
const PARTICLE_START = 2900; //x coordinate where particles start in the background
const PARTICLE_LENGTH = 300;
const DATA_START = 4400;
const DATA_LENGTH = 1000;
const FACE_START = 600;
const FACE_LENGTH = 400;
//for art spirals
let shapes = []; //center spiral
let maxSize = 35; // changing sizes of circles/squares in the center spiral
let minSize = 10;
let distance = 0.4; //vairables to change shape, structure and speed of spiral
let increment = 0.133;
let spawn = 6;
let offset = 100; //offsets for colors and distance from center for center spiral
let offsetr = 100;
let offsetg = 200;
let offsetb = 0;
let redVal;
let greenVal;
let blueVal;
//data variables
let cityTable, weatherTable;
let delhiX, delhiY; // Variables to store Delhi's x and y coordinates
let temperatures = [];
let windDirections = [];
let windSpeeds = [];
let particlesD = [];
let index = 0;
const ROW_TIME = 120;
const JUMP_FORWARD = 24;
let dateInput;
let jumpButton;
//cat variables
let catSpriteSheet;
let walkFrames = [];
let sitFrames = [];
let currentFrame = 0;
let catWidth;
let catHeight;
let isWalking = true;
let isSitting = false;
let lastCamX;
let wasMoving = false; // Keeps track of previous movement state
let direction = -1; // Assuming the default direction is to the right
let catY;
let gravity = 0.8;
let velocity = 0;
let jumpForce = -15;
const baseSpeed = 5; // or whatever your current speed is
const boostSpeed = baseSpeed + 3; // 2 units faster, adjust to your liking
//Obstacles
let obstacles = [];
let obstacleWidth = 10;
let obstacleHeight;
let groundHeight;
let obstacleImages = [];
let lastobs = 0;
function preload() {
cityTable = loadTable("updated_cities.csv", "csv", "header");
weatherTable = loadTable("updated_testset.csv", "csv", "header");
catSpriteSheet = loadImage("cat.png");
for (let i = 1; i <= 3; i++) {
let img = loadImage(`obstacle${i}.png`);
obstacleImages.push(img);
}
myFont = loadFont("font.otf");
startSound = loadSound("Digital Lemonade-[AudioTrimmer.com] (1).mp3");
playingSound = loadSound("Voxel Revolution (1).mp3");
gameOverSound = loadSound("sad.mp3");
clickSound = loadSound("Swoosh.mp3");
bounceSound = loadSound("bounce.mp3");
collideSound = loadSound("mixkit-falling-game-over-1942.wav");
}
//mouse clicked function
function mouseClicked() {
if (currSpeed == 1 || currSpeed == 2) currSpeed += 1;
else currSpeed += 2;
if (currSpeed >= 8) currSpeed = 1;
index = (index + JUMP_FORWARD) % temperatures.length;
}
function setup() {
frameRate(24);
textFont(myFont);
startButtonW = 200; // width of the button
startButtonH = 60; // height of the button
startButtonX = width / 2; // center the button horizontally
startButtonY = height / 2 + 360; // position below the instructions
restartButtonW = 250; // width of the button
restartButtonH = 60; // height of the button
restartButtonX = width / 2; // center the button horizontally
restartButtonY = height / 2 + 260; // position slightly below the "Game Over" text
createCanvas(800, 500);
noStroke();
background(0);
//initializing the cat
catWidth = catSpriteSheet.width / 2;
catHeight = catSpriteSheet.height / 12;
catY = (4 * height) / 5 - catHeight / 2;
// Extracting the walk frames from the sprite sheet
for (let i = 0; i < 12; i++) {
let img = catSpriteSheet.get(0, i * catHeight, catWidth, catHeight);
walkFrames.push(img);
}
// Extracting the sit frames from the sprite sheet
for (let i = 0; i < 7; i++) {
let img = catSpriteSheet.get(catWidth, i * catHeight, catWidth, catHeight);
sitFrames.push(img);
}
//putting in the obstacles
groundHeight = (4 * height) / 5;
//initializing the particle animation
for (
let x = PARTICLE_START;
x < PARTICLE_START + PARTICLE_LENGTH + width;
x += 30
) {
//range is slightly beyond canvas size for smoother animation
for (let y = -20; y < height + 20; y += 30) {
particles.push(new Particle(x, y));
}
}
//initializing the data animation
for (let row of weatherTable.rows) {
let temp = row.getNum(" _tempm");
temperatures.push(isNaN(temp) ? 25 : temp); // Use 25 if temperature is NaN
let windDir = row.getString(" _wdire");
windDirections.push(windDir === "" ? "East" : windDir); // Use "East" if windDir is empty
let windSpd = row.getNum(" _wspdm");
windSpeeds.push(isNaN(windSpd) ? 0 : windSpd); // Use 0 if wind speed is NaN
}
for (let x = DATA_START + 300; x < DATA_START + DATA_LENGTH + 300; x += 30) {
for (let y = -50; y < height + 50; y += 30) {
particlesD.push(new ParticleData(x, y));
}
}
let toggleButton = createButton("Toggle Audio");
toggleButton.position(width - 100, 10); // top-right corner
toggleButton.mousePressed(toggleAudio);
}
function toggleAudio() {
// turning audio on/off
isAudioOn = !isAudioOn;
if (isAudioOn) {
getAudioForState(gameState).play();
} else {
startSound.stop();
playingSound.stop();
gameOverSound.stop();
}
}
function getAudioForState(state) {
//finding right audio to play
switch (state) {
case "START":
return startSound;
case "PLAYING":
return playingSound;
case "GAME_OVER":
return gameOverSound;
default:
return null;
}
}
function draw() {
if (gameState === "START") {
if (!startSound.isPlaying() && isAudioOn) {
playingSound.stop();
gameOverSound.stop();
startSound.loop();
}
background(0);
fill(255);
textAlign(CENTER, CENTER);
textSize(40);
text("A Dreamlike Journey", width / 2, height / 2 - 200);
// Display the instructions
textSize(30);
let instructions = [
"1. Move the cat with your left and right arrow keys.",
"2. Use the spacebar to jump and avoid obstacles.",
"3. Stop to admire the artworks at any point",
"This will prevent any new obstacles from spawning!",
"4. Press 1 to click a screenshot and save it!",
"5. Press 2 to restart!",
"WARNING: DO NOT RUN AWAY FROM YOUR PROBLEMS",
];
let y = height / 2 - 130;
for (let i = 0; i < instructions.length; i++) {
if (i == instructions.length - 1) {
y += 20;
textSize(35);
}
text(instructions[i], width / 2, y);
y += 40; // This spaces out each line of instructions
}
fill(255);
stroke(220);
strokeWeight(2);
rectMode(CENTER);
rect(
width / 2,
startButtonY + startButtonH / 2,
startButtonW,
startButtonH,
20
); // 20 is for rounded corners
// Draw "start" text inside the button
noStroke();
fill(0);
textSize(28);
text("START", width / 2, startButtonY + startButtonH / 2 - 5); // 10 is to adjust the text vertical alignment
} else if (gameState === "PLAYING") {
if (!playingSound.isPlaying() && isAudioOn) {
playingSound.loop();
gameOverSound.stop();
startSound.stop();
}
background(0, 70);
noStroke();
// Handle camera movement based on keys being held down
if (keyIsDown(LEFT_ARROW)) {
camX -= speed;
}
if (keyIsDown(RIGHT_ARROW)) {
camX += speed;
}
if (camX <= -150) camX = -150;
else if (camX >= 6500) camX = 6500;
// Check direction of camera movement to adjust cat's direction
if (camX > lastCamX) {
direction = -1;
} else if (camX < lastCamX) {
direction = 1;
}
// If camera is not moving and the cat was walking previously
if (camX == lastCamX && wasMoving) {
wasMoving = false;
isWalking = false;
isSitting = true;
sitFrames.reverse();
currentFrame = 0;
}
// If camera starts moving and the cat was sitting previously
if (camX != lastCamX && !wasMoving) {
wasMoving = true;
isSitting = false;
isWalking = true;
sitFrames.reverse();
currentFrame = 0;
}
// Set the "camera" position
translate(-camX, 0);
fill(255);
textAlign(LEFT);
textSize(48);
text("A Dreamlike Journey", 50, 75);
text("Through Intro to IM", 50, 130);
textSize(32);
text("- Sneheel Sarangi", width / 2 + 100, 250);
textSize(48);
if (camX >= 0 && camX < FACE_START + FACE_LENGTH + 500) {
viewFace();
}
if (camX >= ART_START - 500 && camX < ART_START + ART_LENGTH + 300) {
viewArt();
}
if (
camX >= PARTICLE_START - 750 &&
camX < PARTICLE_START + PARTICLE_LENGTH + 800
)
viewParticles();
if (camX >= DATA_START - 750 && camX < DATA_START + DATA_LENGTH + 800) {
viewData();
}
if (frameCount % 100 == 0 && isWalking) {
// adjust this for obstacle frequency
spawnObstacle();
}
updateObstacles();
drawObstacles();
// Check for collisions
for (i = 0; i < obstacles.length; i++) {
if (checkCollision(obstacles[i])) {
obs = i;
collideSound.play();
gameOver(); // triggers the game over state
}
}
catY += velocity;
velocity += gravity;
if (catY > groundHeight - catHeight / 2) {
catY = groundHeight - catHeight / 2;
velocity = 0;
speed = baseSpeed;
}
catY = constrain(catY, 0, groundHeight - catHeight / 2);
// Draw the cat
let frameToDraw;
if (isWalking) {
frameToDraw = walkFrames[currentFrame % 12];
if (frameCount % 2 == 0)
//making the animation slower
currentFrame = (currentFrame + 1) % 12;
} else if (isSitting) {
frameToDraw = sitFrames[currentFrame];
if (frameCount % 2 == 0 && currentFrame < 6) {
currentFrame++;
}
}
push();
translate(camX + width / 2, catY + 80); // Adjusted line for cat's position
scale(direction * 0.6, 0.6); //scaling forturning the cat in the right direction and changing its size
image(frameToDraw, -catWidth / 2, -catHeight / 2, catWidth, catHeight);
pop();
lastCamX = camX;
// Draw a thick white line at the absolute x-coordinate -150 taking the camera's position into account
strokeWeight(5); // Set the thickness of the line
stroke(255); // Set the color to white
line(-50 - camX, 0, -50 - camX, height); // start line
line(7300, 0, 7300, height); // end
noStroke();
fill(255);
textSize(48);
textAlign(CENTER);
text("You. Yes, YOU", 6870, height / 2 - 200);
textSize(30);
text("CONGRATULATIONS!!!", 6870, height / 2 - 100);
text("You finished the first half with flying colors!!", 6870, height / 2);
text("You've earned yourself a break. Have fun!!", 6870, height / 2 + 50);
text("To restart, press 2", 6750, height / 2 + 150);
} else if (gameState === "GAME_OVER") {
if (!gameOverSound.isPlaying() && isAudioOn) {
playingSound.stop();
gameOverSound.loop();
startSound.stop();
}
background(0);
fill(255);
textAlign(CENTER, CENTER);
textSize(48);
text("Game Over!", width / 2, height / 2 - 70);
textSize(32);
text("Your score was: The amount of fun you had", width / 2, height / 2);
// Draw custom restart button
fill(255);
stroke(220);
strokeWeight(2);
rectMode(CENTER);
rect(
width / 2,
restartButtonY + restartButtonH / 2,
restartButtonW,
restartButtonH,
20
); // 20 is for rounded corners
// Draw "restart" text inside the button
noStroke();
fill(0);
textSize(28);
text("RESTART", width / 2, restartButtonY + restartButtonH / 2 - 5); // 10 is to adjust the text vertical alignment
}
}
function jump() {
if (catY >= groundHeight - catHeight / 2) {
velocity += jumpForce;
speed = boostSpeed; // boost the speed during the jump
bounceSound.play();
}
} //jump function
function keyPressed() {
if (keyCode === 32) {
// space key for jump
jump();
}
if (keyCode === 49)
//when 1 is pressed
save("myart.png");
if (keyCode === 50)
//when 1 is pressed
restartGame();
} //jump trigger when spacebar pressed
function spawnObstacle() {
obstacleWidth = random(20, 40);
obstacleHeight = random(60, 110);
let yPos = groundHeight - obstacleHeight + 30;
let xPos = camX + width;
let randomImage = random(obstacleImages); // p5.js' random function
let newObstacle = {
x: xPos,
y: yPos,
width: obstacleWidth,
height: obstacleHeight,
img: randomImage,
};
obstacles.push(newObstacle);
}
function updateObstacles() {
for (let i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].x -= speed;
if (obstacles[i].x < camX - obstacleWidth) {
obstacles.splice(i, 1);
}
}
}
function drawObstacles() {
fill(255, 0, 0);
for (let obs of obstacles) {
image(obs.img, obs.x, obs.y, obs.width, obs.height);
}
}
function startGame() {
gameState = "PLAYING";
clickSound.play();
}
function gameOver() {
gameState = "GAME_OVER";
}
function restartGame() {
clickSound.play();
particles = [];
particlesD = [];
shapes = [];
obstacles = [];
camX = 0;
lastobs = 0; //to store the last obstacle passed
//initializing the particle animation
for (
let x = PARTICLE_START;
x < PARTICLE_START + PARTICLE_LENGTH + width;
x += 20
) {
//range is slightly beyond canvas size for smoother animation
for (let y = -20; y < height + 20; y += 20) {
particles.push(new Particle(x, y));
}
}
//initializing the data animation
for (let x = DATA_START + 300; x < DATA_START + DATA_LENGTH + 300; x += 30) {
for (let y = -50; y < height + 50; y += 30) {
particlesD.push(new ParticleData(x, y));
}
}
gameState = "START";
loop();
}
function checkCollision(obs) {
// print(camX + width / 2 + catWidth / 2 * 0.6 - obs.x +"+");
// print( camX + width / 2 - catWidth / 2 * 0.6 - obs.x + obs.width +"-")
// print(catY + (catHeight / 2) * 0.6 - obs.y +"+")
// print(catY - (catHeight / 2) * 0.6 - obs.y +"-")
//for debugging collisions
if (isWalking)
return (
camX + width / 2 + (catWidth / 2) * 0.6 - 50 > obs.x &&
camX + width / 2 - (catWidth / 2) * 0.6 + 40 < obs.x + obs.width &&
catY + catHeight * 0.6 + 20 > obs.y &&
catY - catHeight * 0.6 < obs.y + obs.height
);
else
return (
camX + width / 2 + (catWidth / 2) * 0.6 - 50 > obs.x &&
camX + width / 2 - (catWidth / 2) * 0.6 + 80 < obs.x + obs.width &&
catY + catHeight * 0.6 + 20 > obs.y &&
catY - catHeight * 0.6 < obs.y + obs.height
);
}
function mousePressed() {
if (gameState === "START") {
// Check if mouse is inside the custom start button
if (
mouseX > width / 2 - startButtonW / 2 &&
mouseX < width / 2 + startButtonW / 2 &&
mouseY > startButtonY &&
mouseY < startButtonY + startButtonH
) {
startGame();
}
} else if (gameState === "GAME_OVER") {
// Check if mouse is inside the custom restart button
if (
mouseX > width / 2 - restartButtonW / 2 &&
mouseX < width / 2 + restartButtonW / 2 &&
mouseY > restartButtonY &&
mouseY < restartButtonY + restartButtonH
) {
restartGame();
}
}
}
function viewParticles() {
background(0, 25); // for subtle fade effect
text("Week 3", PARTICLE_START + PARTICLE_LENGTH - 100, 100);
text(
"Click to toggle particle speed",
PARTICLE_START + PARTICLE_LENGTH - 100,
150
);
timeMove += timeIncrementMove;
timeC += timeIncrementColor;
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.repulse(createVector(mouseX, mouseY)); // Add repulsion based on mouse position
if (p.isFarFromOrigin()) {
let oldPos = p.originalPos.copy(); // Store the original position before deleting
particles.splice(i, 1); // remove particle from the list
particles.push(new Particle(oldPos.x, oldPos.y)); // Add a new particle at the stored position
} else {
p.update();
p.show();
}
}
}
class Particle {
constructor(x, y) {
this.pos = createVector(x, y);
this.originalPos = this.pos.copy(); //make a copy of initial position to reload new particle at this location
this.size = random(5, 25);
this.angle = 0;
}
isFarFromOrigin() {
return p5.Vector.dist(this.pos, this.originalPos) > random(100, 250);
}
update() {
let r =
noise(this.pos.x * noiseScale, this.pos.y * noiseScale, timeC) * 255;
let g =
noise(
this.pos.x * noiseScale + 100,
this.pos.y * noiseScale + 100,
timeC
) * 255;
let b =
noise(
this.pos.x * noiseScale + 200,
this.pos.y * noiseScale + 200,
timeC
) * 255;
let alpha =
noise(
this.pos.x * noiseScale + 300,
this.pos.y * noiseScale + 300,
timeC
) *
150 +
105;
this.color = color(r, g, b, alpha);
this.angle = noise(this.pos.x * 0.01, this.pos.y * 0.01, timeMove) * TWO_PI; //random orientation
let move = p5.Vector.fromAngle(this.angle); //Create a vector at a random angle
move.mult(currSpeed);
this.pos.add(move); //add to current vector
let sizeNoise = noise(
this.pos.x * noiseScale,
this.pos.y * noiseScale,
timeMove * 2
);
this.size = sizeNoise * 25; // Change these values to adjust the range of size based on noise
}
show() {
push();
translate(this.pos.x, this.pos.y);
rotate(this.angle);
fill(this.color);
rect(0, 0, this.size, this.size * 0.3); // making the rectangle elongated like a bristle
pop();
}
repulse(point) {
let dir = p5.Vector.sub(this.pos, point);
let dist = dir.mag();
if (dist < 100) {
// Only push away if within 100 pixels
dir.normalize();
dir.mult(currSpeed + 2); // Adjust for stronger or weaker repulsion
this.pos.add(dir);
}
}
}
function viewArt() {
fill(255);
push();
translate(ART_START + ART_LENGTH, height / 2);
text("Week 2", -width / 2 + 100, -height / 2 + 100);
text(
"Why don't we wait here for a bit?",
-width / 2 + 100,
-height / 2 + 150
);
// Spawn a new shape at the center every 'spawn' frames
if (frameCount % spawn == 0) {
offsetr += 0.1; //color offsets
offsetg += 0.1;
offsetb += 0.1;
let newShape = {
theta: 0, //to control movement in direction of circle
r: 0, //to control distance from center
size: random(minSize, maxSize),
isCircle: random() < 0.5, //choosing if circle or square
redval: noise(offsetr) * 255,
greenval: 255 - noise(offsetg) * 255,
blueval: noise(offsetb) * 255,
};
shapes.push(newShape);
}
for (let i = 0; i < shapes.length; i++) {
let shape = shapes[i];
offset += 0.1;
let x = shape.r * cos(shape.theta);
let y = shape.r * sin(shape.theta);
fill(shape.redval, shape.greenval, shape.blueval);
if (shape.isCircle) {
ellipse(x, y, shape.size);
} else {
rect(x, y, shape.size, shape.size);
}
// Update position
shape.theta += increment;
shape.r += distance;
shape.r += noise(offset) * 0.1;
}
// Remove shapes that go beyond the canvas boundary
for (let i = shapes.length - 1; i >= 0; i--) {
if (shapes[i].r > width) {
shapes.splice(i, 1);
}
}
pop();
}
function viewData() {
text("Week 4", DATA_START - 100, 100);
text("Part 1: The Major Cities", DATA_START - 100, 150);
text("In India", DATA_START + 50, 200);
text(
"Part 2: Temperature and Wind in Delhi",
DATA_START + DATA_LENGTH / 2 + 300,
150
);
text(
"Click to go ahead by 24 hours",
DATA_START + DATA_LENGTH / 2 + 450,
200
);
for (let row of cityTable.rows) {
let city = row.getString("city");
let lat = row.getNum("lat");
let lng = row.getNum("lng");
// Convert latitude and longitude to x and y
let x = map(lng, 65, 100, DATA_START, DATA_START + width);
let y = map(lat, 5, 35, height, 0);
if (city === "Delhi") {
fill(255, 255, 255); // Color for Delhi
delhiX = x;
delhiY = y;
ellipse(x, y, 20, 20);
} else {
fill(255, 0, 0, 150); // Color for other cities
}
ellipse(x, y, 10, 10);
}
push();
translate(500, 0);
if (frameCount % ROW_TIME == 0) index = (index + 1) % temperatures.length;
for (let i = particlesD.length - 1; i >= 0; i--) {
let p = particlesD[i];
if (p.isFarFromOrigin()) {
let oldPos = p.originalPos.copy(); // Store the original position before deleting
particlesD.splice(i, 1); // remove particle from the list
particlesD.push(new ParticleData(oldPos.x, oldPos.y)); // Add a new particle at the stored position
} else {
p.update();
p.show();
}
}
let dateTime = weatherTable.getString(index, "datetime_utc");
let windDir = weatherTable.getString(index, " _wdire");
let windSpd = weatherTable.getString(index, " _wspdm");
let temp = weatherTable.getString(index, " _tempm");
// Display date and time, wind direction, wind speed, and temperature inside the rectangle
fill(255); // White text
textSize(14);
textAlign(LEFT, TOP);
text(
"Date & Time: " + dateTime,
DATA_START + DATA_LENGTH / 2 + 500,
height - 30
);
text(
"Wind Direction: " + windDir,
DATA_START + DATA_LENGTH / 2 + 500,
height - 50
);
text(
"Wind Speed: " + windSpd + " km/h",
DATA_START + DATA_LENGTH / 2 + 500,
height - 70
);
text(
"Temperature: " + temp + " C",
DATA_START + DATA_LENGTH / 2 + 500,
height - 90
);
pop();
textAlign(CENTER);
}
class ParticleData {
constructor(x, y) {
this.pos = createVector(x, y);
this.originalPos = this.pos.copy();
this.size = random(1, 20);
this.angle = 0;
}
//checks the distance moved from starting point
isFarFromOrigin() {
return p5.Vector.dist(this.pos, this.originalPos) > random(100, 250);
}
update() {
// Convert wind direction to angle
this.angle = this.directionToAngle(windDirections[index]);
// Create a vector for wind direction
let windVec = p5.Vector.fromAngle(this.angle);
windVec.mult(windSpeeds[index] * 0.2);
// Adding Perlin noise for adding randomness to make it feel more natural
let noiseVal = noise(
this.pos.x * 0.01,
this.pos.y * 0.01,
millis() * 0.0005
);
let dir = windDirections[index];
if (windSpeeds[index] == 0) {
if (dir == "North" || dir == "NW" || dir == "NE") noiseVal *= -1;
else if (dir == "NNW" || dir == "NNE") noiseVal *= -0.6;
else if (dir == "ENE" || dir == "WNW") noiseVal *= -0.3;
else if (dir == "East" || dir == "West") noiseVal *= 0.1;
else if (dir == "ESE" || dir == "WSW") noiseVal *= 0.3;
else if (dir == "SSE" || dir == "SSW") noiseVal *= 0.6;
}
let noiseVec = p5.Vector.fromAngle(noiseVal * TWO_PI * 0.7); // Adjust multiplier as needed
// Combine wind vector with noise vector
let combinedVec = p5.Vector.add(windVec, noiseVec);
this.pos.add(combinedVec);
// Map temperature to color
let col = lerpColor(
color(0, 0, 255),
color(255, 0, 0),
map(temperatures[index], 0, 40, 0, 1)
);
fill(col);
}
show() {
push();
translate(this.pos.x, this.pos.y);
rotate(this.angle);
rect(0, 0, this.size, this.size * 0.3);
pop();
}
directionToAngle(direction) {
switch (direction) {
case "North":
return -PI / 2; // Upward on the canvas
case "NE":
return -PI / 4;
case "East":
return 0; // Rightward on the canvas
case "SE":
return PI / 4;
case "South":
return PI / 2; // Downward on the canvas
case "SW":
return (3 * PI) / 4;
case "West":
return PI; // Leftward on the canvas
case "NW":
return (-3 * PI) / 4;
case "WSW":
return (7 * PI) / 8;
case "WNW":
return (-7 * PI) / 8;
case "ENE":
return -PI / 8;
case "ESE":
return PI / 8;
case "SSW":
return (5 * PI) / 8;
case "SSE":
return (3 * PI) / 8;
case "NNE":
return (-3 * PI) / 8;
case "NNW":
return (-5 * PI) / 8;
default:
return 0;
}
}
}
function viewFace() {
text("Week 1", FACE_START + FACE_LENGTH - 100, 100);
text("I can do better", FACE_START + FACE_LENGTH + 300, 150);
text("I swear.", FACE_START + FACE_LENGTH + 300, 200);
push();
rectMode(CORNER);
translate(FACE_START + FACE_LENGTH, 0);
// Hair
fill(0);
stroke(255);
beginShape();
vertex(107, 212);
vertex(87, 131);
vertex(117, 90);
vertex(203, 85);
vertex(235, 113);
vertex(228, 198);
vertex(196, 138);
vertex(113, 160);
endShape(CLOSE);
//Neck
fill(215, 156, 121);
strokeWeight(0.25);
beginShape();
vertex(128, 262);
vertex(131, 296);
vertex(153, 328);
vertex(212, 325);
vertex(223, 280);
vertex(219, 236);
vertex(167, 280);
endShape(CLOSE);
// Face
fill(215, 156, 121);
beginShape();
vertex(107, 212);
vertex(121, 252);
vertex(135, 268);
vertex(167, 280);
vertex(196, 270);
vertex(215, 249);
vertex(228, 198);
vertex(196, 138);
vertex(113, 160);
endShape(CLOSE);
// Ears
fill(215, 156, 121);
ellipse(103, 207, 20, 35);
ellipse(103, 207, 15, 30);
ellipse(231, 200, 20, 35);
ellipse(231, 200, 15, 30);
// Eyes
fill(255);
ellipse(136, 192, 20, 10);
ellipse(189, 186, 20, 10);
fill(0);
ellipse(136, 192, 6.5, 6.5);
ellipse(189, 186, 6.5, 6.5);
// Eyebrows
noFill();
stroke(0);
strokeWeight(3);
arc(136, 186, 30, 20, PI + PI / 9, TWO_PI - PI / 6);
arc(189, 180, 30, 20, PI + PI / 6, TWO_PI - PI / 8);
//Nose
fill(215, 156, 121);
strokeWeight(0.25);
beginShape();
vertex(155, 188);
vertex(167, 188);
vertex(167, 204);
vertex(174, 214);
vertex(163, 219);
vertex(148, 215);
vertex(157, 204);
endShape(CLOSE);
// Mouth
fill(222, 144, 137);
arc(163, 240, 40, 18, 0, PI);
fill(222, 144, 137);
arc(163, 237, 40, 10, PI, TWO_PI);
fill(255);
rect(148, 237, 30, 3);
fill(224, 255, 255);
strokeWeight(0);
triangle(38, 328, 127, 289, 160, 340);
triangle(220, 280, 210, 330, 330, 330);
rect(27, 328, 310, 600, 20);
strokeWeight(0.2);
triangle(28, 334, -70, 540, 30, 540);
triangle(336, 334, 336, 540, 420, 540);
fill(10);
rect(147, 328, 70, 215);
pop();
rectMode(CENTER);
}