function draw() {
if (currentLevel === 9) {
background(0);
} else {
background(220);
}
textAlign(LEFT, TOP);
textSize(32);
fill(0);
noStroke();
text(`Level: ${currentLevel}`, 10, 10);
if (currentLevel === 8) {
text(`Fish Caught: ${fishCaughtCount}`, 10, 40);
}
if (currentLevel !== 8) {
translate(camX, camY);
}
if (!panning && currentLevel === 9 && !diamondFound && !gameCompleted) {
camX += driftVelocityX;
camY += driftVelocityY;
driftVelocityX *= 0.95;
driftVelocityY *= 0.95;
if (abs(driftVelocityX) < 0.1) driftVelocityX = 0;
if (abs(driftVelocityY) < 0.1) driftVelocityY = 0;
camX = constrain(camX, -(TOWN_WIDTH - width), 0);
}
checkAndGenerateNewBlocks();
if (currentLevel === 9) {
for (let nebula of nebulae) {
fill(nebula.color);
noStroke();
ellipse(nebula.x, nebula.y, nebula.size, nebula.size);
}
for (let asteroid of asteroids) {
fill(asteroid.color);
stroke(asteroid.color.levels[0] + 50);
strokeWeight(1);
ellipse(asteroid.x, asteroid.y, asteroid.size, asteroid.size);
asteroid.x += asteroid.speedX;
asteroid.y += asteroid.speedY;
if (asteroid.x > TOWN_WIDTH) asteroid.x = -asteroid.size;
if (asteroid.x < -asteroid.size) asteroid.x = TOWN_WIDTH;
let screenTop = -camY;
let screenBottom = -camY + height;
if (asteroid.y > screenBottom + height) asteroid.y = screenTop - height;
if (asteroid.y < screenTop - height) asteroid.y = screenBottom + height;
}
} else if (currentLevel !== 8) {
let visibleStartX = -camX;
let visibleStartY = -camY;
let visibleEndX = visibleStartX + width;
let visibleEndY = visibleStartY + height;
let buffer = BLOCK_SIZE * 2;
visibleStartX -= buffer;
visibleStartY -= buffer;
visibleEndX += buffer;
visibleEndY += buffer;
let startDrawBlockX = floor(visibleStartX / BLOCK_SIZE);
let startDrawBlockY = floor(visibleStartY / BLOCK_SIZE);
let endDrawBlockX = ceil(visibleEndX / BLOCK_SIZE);
let endDrawBlockY = ceil(visibleEndY / BLOCK_SIZE);
stroke(100);
strokeWeight(2);
for (let bx = startDrawBlockX; bx < endDrawBlockX; bx++) {
for (let by = startDrawBlockY; by < endDrawBlockY; by++) {
if (bx >= 0 && bx < TOWN_WIDTH / BLOCK_SIZE) {
let blockData = generatedBlocks.get(`${bx},${by}`);
if (blockData) {
let x = bx * BLOCK_SIZE;
let y = by * BLOCK_SIZE;
line(x, y, x + BLOCK_SIZE, y);
line(x + BLOCK_SIZE, y, x + BLOCK_SIZE, y + BLOCK_SIZE);
line(x, y + BLOCK_SIZE, x + BLOCK_SIZE, y + BLOCK_SIZE);
line(x, y, x, y + BLOCK_SIZE);
}
}
}
}
noStroke();
for (let bx = startDrawBlockX; bx < endDrawBlockX; bx++) {
for (let by = startDrawBlockY; by < endDrawBlockY; by++) {
if (bx >= 0 && bx < TOWN_WIDTH / BLOCK_SIZE) {
let blockData = generatedBlocks.get(`${bx},${by}`);
if (blockData) {
for (let person of blockData.people) {
fill(person.color);
rect(person.x, person.y, person.bodyW, person.bodyH);
ellipse(person.x + person.bodyW / 2, person.y - person.headSize / 2, person.headSize, person.headSize);
}
}
}
}
}
for (let bx = startDrawBlockX; bx < endDrawBlockX; bx++) {
for (let by = startDrawBlockY; by < endDrawBlockY; by++) {
if (bx >= 0 && bx < TOWN_WIDTH / BLOCK_SIZE) {
let blockData = generatedBlocks.get(`${bx},${by}`);
if (blockData) {
for (let building of blockData.buildings) {
fill(building.color);
rect(building.x, building.y, building.w, building.h);
}
}
}
}
}
}
if (currentLevel === 6 && !diamondFound && chasingUFO) {
let targetX = -camX + width / 2;
let targetY = -camY + height / 2;
let moveVec = createVector(targetX - chasingUFO.x, targetY - chasingUFO.y);
moveVec.normalize().mult(chasingUFO.speed);
chasingUFO.x += moveVec.x;
chasingUFO.y += moveVec.y;
chasingUFO.x += sin(frameCount * 0.05) * 5;
chasingUFO.y += cos(frameCount * 0.04) * 5;
drawUFO(chasingUFO.x, chasingUFO.y, chasingUFO.size, color(255, 0, 0, 180), color(255, 255, 0));
}
if (currentLevel === 6 && petUFO) {
let targetX = -camX + width / 2;
let targetY = -camY + height / 2;
petUFO.x = lerp(petUFO.x, targetX, 0.05);
petUFO.y = lerp(petUFO.y, targetY, 0.05);
drawUFO(petUFO.x, petUFO.y, petUFO.size, petUFO.bodyColor, petUFO.lightColor);
}
if (!diamondFound) {
if (currentLevel === 8) {
fill(50, 150, 255);
noStroke();
rect(-camX, height / 2, width, height / 2);
stroke(100);
strokeWeight(4);
line(width / 2 - 50, 0, width / 2 + 50, height / 2 - 100);
fill(150);
strokeWeight(2);
rect(width / 2 - 60, -10, 20, 20);
stroke(0);
strokeWeight(1);
line(width / 2 + 50, height / 2 - 100, diamondX, fishingBobberY + fishingBobberJiggleOffset);
fill(255, 0, 0);
noStroke();
ellipse(diamondX, fishingBobberY + fishingBobberJiggleOffset, 10, 15);
if (fishingRodActive) {
let elapsed = millis() - fishingRodCastTime;
if (elapsed > fishingCooldown && !fishingCatch) {
fishingBobberJiggleOffset = sin(frameCount * 0.3) * 5;
} else {
fishingBobberJiggleOffset = 0;
}
}
if (fishingCatch) {
if (fishingCatch.y < height / 2 - 80) {
fishingCatch.y = height / 2 - 80;
} else {
fishingCatch.y = lerp(fishingCatch.y, height / 2 - 80, 0.1);
}
}
if (fishingCatch) {
if (fishingCatch.type === 'fish') drawFish(fishingCatch.x, fishingCatch.y, fishingCatch.size);
else if (fishingCatch.type === 'sushi') drawSushi(fishingCatch.x, fishingCatch.y, fishingCatch.size);
else if (fishingCatch.type === 'diamond') {
push();
translate(fishingCatch.x, fishingCatch.y);
rotate(frameCount * 0.1);
fill(0, 255, 255, 200);
noStroke();
ellipse(0, 0, fishingCatch.size, fishingCatch.size);
pop();
}
}
} else if (currentLevel === 7) {
if (diggingAnimationActive) {
let elapsed = millis() - diggingStartTime;
let alpha = map(elapsed, 0, diggingDuration, 200, 0);
let digSize = map(elapsed, 0, diggingDuration, 10, diamondSize * 1.5);
fill(139, 69, 19, alpha);
noStroke();
ellipse(diamondX, diamondY + diamondSize / 4, digSize, digSize / 2);
if (elapsed > diggingDuration) {
diggingAnimationActive = false;
diamondFound = true;
diamondOsc.start(0, 880, 0.5);
diamondOsc.amp(0, 0.5, 0.2);
diamondOsc.stop(0.7);
setTimeout(() => {
triggerLevel7Win();
}, 2000);
}
} else {
drawFootballDiamond(diamondX, diamondY, diamondSize);
}
} else if (currentLevel === 6) {
drawUFO(diamondX, diamondY, diamondSize, color(0, 255, 255), color(255, 255, 0));
} else if (currentLevel === 9) {
fill(0, 255, 255);
noStroke();
ellipse(diamondX, diamondY, diamondSize, diamondSize);
} else {
fill(0, 255, 255);
noStroke();
ellipse(diamondX, diamondY, diamondSize, diamondSize);
}
} else {
textAlign(CENTER, CENTER);
textSize(64);
fill(0);
if (gameCompleted) {
text("Game Over, You Won!", -camX + width / 2, -camY + height / 2);
if (diamondRock) {
if (currentLevel === 6) {
drawUFO(diamondRock.x, diamondRock.y, diamondRock.size, color(0, 255, 255), color(255, 255, 0));
} else if (currentLevel === 7) {
drawFootballDiamond(diamondRock.x, diamondRock.y, diamondRock.size);
} else if (currentLevel === 8) {
drawSushi(diamondRock.x, diamondRock.y, diamondRock.size);
} else if (currentLevel === 9) {
push();
translate(diamondRock.x, diamondRock.y);
rotate(frameCount * 0.1);
fill(0, 255, 255, 200);
noStroke();
ellipse(0, 0, diamondRock.size, diamondRock.size);
pop();
}
}
} else {
text("You Found the Diamond!", -camX + width / 2, -camY + height / 2);
}
}
if (gameCompleted) {
for (let i = confetti.length - 1; i >= 0; i--) {
confetti[i].update();
confetti[i].display();
if (confetti[i].isOffScreen()) {
confetti.splice(i, 1);
}
}
}
if (postWinAnimationActive) {
for (let i = grabbingPeople.length - 1; i >= 0; i--) {
let person = grabbingPeople[i];
if (person.state === 'movingToRock') {
let moveVec = createVector(person.targetX - person.x, person.targetY - person.y);
moveVec.normalize().mult(person.speed);
person.x += moveVec.x;
person.y += moveVec.y;
let d = dist(person.x, person.y, person.targetX, person.targetY);
if (d < person.speed * 2) {
person.state = 'grabbing';
if (diamondRock) {
diamondRock.size *= 0.9;
if (diamondRock.size < 5) diamondRock = undefined;
}
person.targetX = random(0, TOWN_WIDTH);
person.targetY = -camY - height;
person.speed = random(5, 10);
}
} else if (person.state === 'grabbing') {
person.state = 'leaving';
} else if (person.state === 'leaving') {
let moveVec = createVector(person.targetX - person.x, person.targetY - person.y);
moveVec.normalize().mult(person.speed);
person.x += moveVec.x;
person.y += moveVec.y;
if (person.y < -camY - BLOCK_SIZE || person.y > -camY + height + BLOCK_SIZE ||
person.x < -camX - BLOCK_SIZE || person.x > -camX + width + BLOCK_SIZE) {
grabbingPeople.splice(i, 1);
}
}
if (person) {
fill(person.color);
noStroke();
rect(person.x, person.y, person.bodyW, person.bodyH);
ellipse(person.x + person.bodyW / 2, person.y - person.headSize / 2, person.headSize, person.headSize);
}
}
if (grabbingPeople.length === 0) {
postWinAnimationActive = false;
}
}
if (currentLevel === 7 && hintCircleActive) {
let elapsed = millis() - hintCircleStartTime;
let alpha = map(elapsed, 0, hintCircleDuration, 255, 0);
let circleSize = map(elapsed, 0, hintCircleDuration, diamondSize + tapTolerance * 2, diamondSize + tapTolerance * 3);
push();
noFill();
stroke(255, 0, 0, alpha);
strokeWeight(3);
ellipse(diamondX, diamondY, circleSize, circleSize);
pop();
if (elapsed > hintCircleDuration) {
hintCircleActive = false;
resetGame(currentLevel + 1);
}
}
}