xxxxxxxxxx
706
let gif_loadImg;
let backgroundImageStart;
let backgroundImageInstructions;
let backgroundImageWaiting;
let backgroundImagePlaying;
let backgroundImageResult;
let startButton;
let playerImages = []; // Declare an array to store the player images
let starImages = [];
let me;
let guests;
let bgm;
let sharedBombId;
let pointSound;
let clickSound;
let bombSound;
let moveSpeed = 5; // Speed at which players move
let waitingArea, playingArea; //restricting play area
//bomb explosion variables
let particles = [];
let isBursting = false;
let colors = ['#9C4242 ', '#787979', '4F4F4F'];
let burstTimer; // Variable to store the burst timer
const names = [
"MICKEY",
"MINNIE",
"JERRY",
"REMY",
"PINKY",
"ALVIN",
"SIMON",
"THEODORE",
];
let stars = []; // Array to hold star objects
let score = 0; // Player's score
const numStars = 5; // Number of stars to generate
const WAITING_DURATION = 10 * 1000;
const PLAYING_DURATION = 32 * 1000;
const requiredNumberOfPlayers = 3;
const playerImageSize = { width: 80, height: 80 };
let sharedTimer;
let gameAlreadyReset = false;
function preload() {
partyConnect("wss://demoserver.p5party.org", "stefernnieweek4!");
let startX = random(0, 400);
let startY = random(0, 400);
let nameIndex = floor(random(names.length)); // Random index for name
let assignedName = names.splice(nameIndex, 1); // Assign and remove the name from the array
me = partyLoadMyShared({
x: startX,
y: startY,
id: random(1000000),
score: 0,
name: assignedName[0],
isReady: false,
});
guests = partyLoadGuestShareds();
sharedBombId = partyLoadShared("bombId", null);
sharedTimer = partyLoadShared("globals", {
gameState: "start",
startTime: Date.now(),
displayTime: null,
});
backgroundImageStart = loadImage("backgrounds/start.png");
backgroundImageInstructions = loadImage("backgrounds/instructions.png");
backgroundImageWaiting = loadImage("backgrounds/waiting.png");
backgroundImagePlaying = loadImage("backgrounds/playing.png");
backgroundImageResult = loadImage("backgrounds/result.png");
playerImages[0] = loadImage("players/player1.png");
playerImages[1] = loadImage("players/player2.png");
playerImages[2] = loadImage("players/player3.png");
gif_loadImg = loadImage("explosion.gif");
for (let i = 0; i < numStars; i++) {
starImages.push(loadImage("stars/star" + (i + 1) + ".png"));
}
sharedBombVisibility = partyLoadShared("bombVisible", true);
bgm = loadSound("sound/bgm.mp3", () => {
bgm.setVolume(0.3);
});
pointSound = loadSound('sound/points.wav', () => {
pointSound.setVolume(0.3); // Set volume to 0%
});
clickSound = loadSound('sound/click.wav', () => {
pointSound.setVolume(0.3); // Set volume to 0%
});
bombSound = loadSound('sound/bomb.wav');
}
function setup() {
createCanvas(563, 750);
// Initialize waiting and playing areas after createCanvas
waitingArea = {
minX: 60,
maxX: width - 60,
minY: 210,
maxY: height - 45
};
playingArea = {
minX: 45,
maxX: width - 50,
minY: 65,
maxY: height - 60
};
bgm.loop();
noStroke();
if (partyIsHost()) {
sharedBombId.value = me.id; // Host has the // Generate stars
}
for (let i = 0; i < numStars; i++) {
let starX = random(playingArea.minX, playingArea.maxX);
let starY = random(playingArea.minY, playingArea.maxY);
stars.push(createVector(starX, starY));
}
}
function resetGame() {
me.score = 0; // Reset the score
guests.forEach(guest => {
guest.score = 0;
});
stars = []; // Clear and repopulate the stars array
for (let i = 0; i < numStars; i++) {
let starX = random(playingArea.minX, playingArea.maxX);
let starY = random(playingArea.minY, playingArea.maxY);
stars.push(createVector(starX, starY));
}
sharedTimer.gameState = "waiting"; // Set game state to waiting
gameAlreadyReset = true; // Mark game as reset
sharedBombVisibility.value = true;
// Reset exploded status
me.exploded = false;
guests.forEach(guest => guest.exploded = false);
}
function draw() {
background("#F5F1EA");
manageTimer(); // Ensure the timer is managed correctly based on game state
// Check if the game has just transitioned to the waiting state
if (sharedTimer.gameState === "waiting" && !gameAlreadyReset) {
resetGame(); // Reset the game
gameAlreadyReset = true; // Mark the game as reset
} else if (sharedTimer.gameState !== "waiting") {
gameAlreadyReset = false; // Reset the flag when not in waiting state
}
switch (sharedTimer.gameState) {
case "start":
background(backgroundImageStart);
drawStartPage();
break;
case "instructions":
background(backgroundImageInstructions);
drawInstructionsPage();
break;
case "waiting":
background(backgroundImageWaiting);
drawWaitingPage();
break;
case "playing":
background(backgroundImagePlaying);
drawPlayingPage(); // Now handles both playing and waiting logic
break;
case "result":
background(backgroundImageResult);
drawResultPage(); // Handle the result display
break;
// Optionally, you could handle other states here if needed
}
}
function drawStartPage() {
background(backgroundImageStart);
}
function startGame() {
// Handle any setup or initialization logic before transitioning to the next game state
sharedTimer.gameState = "instructions"; // or any other initial state you want
startButton.hide(); // Remove the button once clicked
}
function drawInstructionsPage() {
fill(0);
}
function drawWaitingPage() {
// Handle player movement and interaction
handleMovementAndInteraction();
// Check if the game is in the playing state and waiting for more players
if (sharedTimer.gameState === "waiting") {
let requiredPlayers = 3;
let currentPlayers = guests.length; // Including 'me' in the count
if (currentPlayers < requiredPlayers) {
// Display waiting message
fill("#552B1C"); // Set the text color to #552B1C
textSize(22);
textAlign(CENTER, CENTER);
textFont("Avenir"); // Set the font to Avenir
textStyle(BOLD);
text(
"WAITING FOR " +
(requiredPlayers - currentPlayers) +
" MORE PLAYERS...",
width / 2,
height / 3 + 120
);
let gifWidth = 200; // Adjust the width as needed
let gifHeight = 200; // Adjust the height as needed
image(gif_loadImg, 190, 400, gifWidth, gifHeight);
} else if (currentPlayers >= requiredPlayers) {
// Corrected the comparison operator here
// Display ready message
fill("#552B1C"); // Set the ƒtext color to #552B1C
textSize(21);
textAlign(CENTER, CENTER);
textFont("Avenir"); // Set the font to Avenir
textStyle(BOLD);
text("YOUR PARTY IS READY CLICK TO START", width / 2, height / 3 + 120);
}
}
// Draw players and the bomb
drawPlayersAndBomb();
}
function drawPlayingPage() {
handleMovementAndInteraction(); // Handle player movement
// Draw and manage stars
const starSize = 60;
for (let i = stars.length - 1; i >= 0; i--) {
image(
starImages[i % starImages.length], // Ensure we loop through star images without going out of bounds
stars[i].x - starSize / 2,
stars[i].y - starSize / 2,
starSize,
starSize
);
if (dist(me.x, me.y, stars[i].x, stars[i].y) < starSize / 2) {
if (me.id !== sharedBombId.value) { // Can score points if not holding the bomb
me.score++;
pointSound.play();
stars.splice(i, 1); // Remove the collected star
// Immediately add a new star at a random position within playingArea
let newStarX = random(playingArea.minX, playingArea.maxX);
let newStarY = random(playingArea.minY, playingArea.maxY);
stars.push(createVector(newStarX, newStarY));
}
}
if (isBursting) {
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.update();
p.show();
if (p.isFinished()) {
particles.splice(i, 1);
}
}
}
}
// Check if the game is in the playing state and waiting for more players
if (sharedTimer.gameState === "playing") {
let requiredPlayers = 3;
let currentPlayers = guests.length; // Including 'me' in the count
if (currentPlayers < requiredPlayers) {
// Transition back to waiting state
sharedTimer.gameState = "waiting";
sharedTimer.startTime = Date.now();
}
}
// Now, call the newly defined function to draw players and the bomb
drawPlayersAndBomb();
// Draw the countdown timer during gameplay
if (sharedTimer.displayTime !== null) {
noStroke();
fill("#FED087");
textSize(20);
textFont("Avenir"); // Set the font to Avenir
textStyle(BOLD);
textAlign(CENTER, CENTER);
text("TIME: " + sharedTimer.displayTime, width / 2, height - 20);
}
}
function handleMovementAndInteraction() {
// Arrow key controls for movement
if (keyIsDown(LEFT_ARROW)) {
me.x -= moveSpeed;
}
if (keyIsDown(RIGHT_ARROW)) {
me.x += moveSpeed;
}
if (keyIsDown(UP_ARROW)) {
me.y -= moveSpeed;
}
if (keyIsDown(DOWN_ARROW)) {
me.y += moveSpeed;
}
// Choose the current area based on game state
let currentArea = sharedTimer.gameState === "waiting" ? waitingArea : playingArea;
// Constrain the player's position to the current area
me.x = constrain(me.x, currentArea.minX, currentArea.maxX);
me.y = constrain(me.y, currentArea.minY, currentArea.maxY);
}
const BOMB_PASS_DISTANCE = 30; // The distance used for passing the bomb
function drawPlayersAndBomb() {
guests = partyLoadGuestShareds(); // Refresh the guest list
const textOffsetY = -55; // Distance above the player image for text
const bombOffsetY = -30; // Distance above the player image for the bomb
// Function to draw the bomb, can be reused for 'me' and guests
function drawBomb(x, y) {
if (sharedBombVisibility.value) {
fill("#000000");
ellipse(x, y + bombOffsetY, 25, 25); // Bomb representation
stroke("#000000");
strokeWeight(3);
let fuseStartX = x;
let fuseStartY = y;
let fuseEndX = x + 18; // Move to the right
let fuseEndY = y - 50;
line(x, y + bombOffsetY, fuseEndX, fuseEndY); // Fuse
// Spark flicker at the tip of the fuse
noStroke(); // No outline for the spark
fill("#F283E1");
let sparkSize = random(5, 7); // Random size for flicker effect
let sparkX = fuseEndX + random(-2, 2); // Slightly randomize the spark position for flicker effect
let sparkY = fuseEndY + random(-2, 2);
ellipse(sparkX, sparkY, sparkSize, sparkSize); // Draw the spark
}
}
// Draw 'me' unless 'me' has exploded
if (!me.exploded) {
let myImg = playerImages[0]; // Assuming the first image is 'me's
image(myImg, me.x - playerImageSize.width / 2, me.y - playerImageSize.height / 2, playerImageSize.width, playerImageSize.height);
fill("#000000");
textSize(11);
textAlign(CENTER, CENTER);
text(me.name + " " + me.score, me.x, me.y + textOffsetY);
if (me.id === sharedBombId.value) {
drawBomb(me.x, me.y);
}
}
// Draw each guest unless they have exploded
guests.forEach(guest => {
if (!guest.exploded) {
let guestImgIndex = (guests.indexOf(guest) + 1) % playerImages.length;
let guestImg = playerImages[guestImgIndex];
image(guestImg, guest.x - playerImageSize.width / 2, guest.y - playerImageSize.height / 2, playerImageSize.width, playerImageSize.height);
fill("#000000");
textSize(11);
textAlign(CENTER, CENTER);
text(guest.name + " " + guest.score, guest.x, guest.y + textOffsetY);
if (guest.id === sharedBombId.value) {
drawBomb(guest.x, guest.y);
}
}
});
// Check bomb passing if the player is 'me' and the current guest is not 'me'
if (me.id === sharedBombId.value && !me.exploded) {
for (const guest of guests) {
if (
guest.id !== me.id &&
dist(me.x, me.y, guest.x, guest.y) < BOMB_PASS_DISTANCE &&
!guest.exploded
) {
console.log(`Passing bomb from ${me.id} to ${guest.id}`);
guest.score -= 1; // Deduct score for receiving the bomb
pointSound.play();
sharedBombId.value = guest.id; // Pass the bomb to another player
break; // Exit the loop after passing the bomb
}
}
}
}
function checkAndStartGame() {
if (partyIsHost() && guests.length >= requiredNumberOfPlayers - 1) {
let playerIds = [me.id].concat(guests.map((guest) => guest.id));
let randomIndex = floor(random(playerIds.length));
sharedBombId.value = playerIds[randomIndex]; // Assign bomb to a random player
// Reduce the score of the initial bomb receiver
guests.forEach((guest) => {
if (guest.id === sharedBombId.value) guest.score -= 1;
});
if (me.id === sharedBombId.value) me.score -= 1; // Check if 'me' is the initial bomb receiver
guests.forEach((guest) => (guest.score = 0)); // Initialize scores to 0 for all guests
me.score = 0; // Initialize 'me' score to 0
sharedTimer.gameState = "playing";
sharedTimer.startTime = Date.now();
}
}
function drawWaiting() {
fill(0);
textSize(20);
textAlign(CENTER, CENTER);
text("Waiting for players...", width / 2, height / 2);
image(gif_loadImg, 50, 50);
gif_createImg.position(50, 350);
resetGame();
}
function manageTimer() {
const currentTime = Date.now();
const elapsed = currentTime - sharedTimer.startTime;
if (sharedTimer.gameState === "playing") {
// Only show up to 30 seconds to the players
sharedTimer.displayTime = floor(Math.max(0, 30 * 1000 - elapsed) / 1000);
if (!isBursting && elapsed >= 30 * 1000) {
// Trigger explosion animation at the 30-second mark
isBursting = true;
initiateExplosion(); // We'll define this function next
}
if (elapsed >= PLAYING_DURATION) {
// Transition to the result state after 32 seconds
sharedTimer.gameState = "result";
sharedTimer.displayTime = null; // Reset display time for the result state
isBursting = false; // Make sure to reset this for the next round
}
}
}
function drawResultPage() {
noStroke();
fill("#ffffff"); // Set the text color to #552B1C
textSize(60);
textAlign(CENTER, CENTER);
textFont("Avenir"); // Set the font to Avenir
textStyle(BOLD);
text("GAME OVER!", width / 2, 100); // Adjusted for better layout
// Calculate start Y position for listing scores
let startY = 150;
let spacingY = 20;
// Display score and name for 'me'
textSize(22);
let myFinalScore = me.id === sharedBombId.value ? 0 : me.score;
fill(me.id === sharedBombId.value ? "#F9C7B6" : "white");
text(`My Score: ${myFinalScore}`, width / 2, startY);
// Display scores and names for guests
guests.forEach((guest, index) => {
let guestFinalScore = guest.id === sharedBombId.value ? 0 : guest.score;
fill(guest.id === sharedBombId.value ? "#F9C7B6" : "#white");
text(
`${guest.name}: ${guestFinalScore}`,
width / 2,
startY + 15 + (index + 1) * spacingY
);
});
// Prompt to restart game
fill(0);
}
function mousePressed() {
clickSound.play();
switch (sharedTimer.gameState) {
case "start":
// Transition from the start state to the instructions state
sharedTimer.gameState = "instructions";
break;
case "instructions":
// Transition from the instructions state to the waiting state
sharedTimer.gameState = "waiting";
break;
case "waiting":
// Check if conditions are met to start the game (e.g., enough players)
// Directly transition to the playing state
sharedTimer.gameState = "playing";
sharedTimer.startTime = Date.now(); // Reset timer for game duration tracking
sharedTimer.displayTime = floor(PLAYING_DURATION / 1000) + 1; // Initialize display time if needed
break;
case "exploding":
background(backgroundImagePlaying); // Or any background you prefer
handleExplosionAnimation();
break;
case "result":
// Transition from the result state back to the start or waiting state
sharedTimer.gameState = "start"; // Or "waiting" if you have a waiting state before the game officially starts
sharedTimer.startTime = Date.now();
sharedTimer.displayTime = null;
// Reset player positions and potentially reshuffle/reassign images here if needed
resetGame(); // Ensure this function resets positions, scores, etc., as needed
if (partyIsHost()) {
assignBombRandomly(); // Ensure bomb is reassigned for the new game
}
break;
// No default case needed
}}
function mousePressed() {
clickSound.play();
switch (sharedTimer.gameState) {
case "start":
// Transition from the start state to the instructions state
sharedTimer.gameState = "instructions";
break;
case "instructions":
// Transition from the instructions state to the waiting state
sharedTimer.gameState = "waiting";
break;
case "waiting":
// Check if conditions are met to start the game (e.g., enough players)
// Directly transition to the playing state
sharedTimer.gameState = "playing";
sharedTimer.startTime = Date.now(); // Reset timer for game duration tracking
sharedTimer.displayTime = floor(PLAYING_DURATION / 1000) + 1; // Initialize display time if needed
break;
case "exploding":
background(backgroundImagePlaying); // Or any background you prefer
handleExplosionAnimation();
break;
case "result":
// Transition from the result state back to the start or waiting state
sharedTimer.gameState = "start"; // Or "waiting" if you have a waiting state before the game officially starts
sharedTimer.startTime = Date.now();
sharedTimer.displayTime = null;
// Reset player positions and potentially reshuffle/reassign images here if needed
resetGame(); // Ensure this function resets positions, scores, etc., as needed
if (partyIsHost()) {
assignBombRandomly(); // Ensure bomb is reassigned for the new game
}
break;
// No default case needed
}
function resetPlayerPositionsAndImages() {
// Reset 'me'
let startX = random(0, 400);
let startY = random(0, 400);
me.x = startX;
me.y = startY;
me.score = 0;
// Optionally reshuffle or reassign 'me's image if that's part of your game logic
// Reset guests
guests.forEach((guest) => {
guest.x = random(0, 400);
guest.y = random(0, 400);
guest.score = 0;
});
}
function assignBombRandomly() {
let playerIds = [me.id].concat(guests.map((guest) => guest.id));
let randomIndex = floor(random(playerIds.length));
sharedBombId.value = playerIds[randomIndex];
}
}
function initiateExplosion() {
// Find the player who has the bomb
let bombPosition = findBombPosition();
particles = []; // Clear existing particles
for (let i = 0; i < 100; i++) {
particles.push(new Particle(bombPosition.x, bombPosition.y));
}
bombSound.play(); // Play explosion sound effect
sharedBombVisibility.value = false; // Hide the bomb
// Mark the player holding the bomb as exploded
if (me.id === sharedBombId.value) {
me.exploded = true;
} else {
guests.forEach(guest => {
if (guest.id === sharedBombId.value) {
guest.exploded = true;
}
});
}
}
function findBombPosition() {
if (me.id === sharedBombId.value) {
return { x: me.x, y: me.y };
}
for (let guest of guests) {
if (guest.id === sharedBombId.value) {
return { x: guest.x, y: guest.y };
}
}
// Default to a position if not found
return { x: width / 2, y: height / 2 };
}
function handleExplosionAnimation() {
if (isBursting) {
// Create particles if not already created
if (particles.length === 0) {
for (let i = 0; i < 100; i++) {
particles.push(new Particle(me.x, me.y));
}
bombSound.play();
}
// Update and show particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.update();
p.show();
if (p.isFinished()) {
particles.splice(i, 1);
}
}
// Transition to the result state once the explosion is done
if (particles.length === 0) {
sharedTimer.gameState = "result";
isBursting = false; // Reset for the next game
}
}
}
class Particle {
constructor(x, y) {
this.pos = createVector(x, y);
this.vel = p5.Vector.random2D();
this.vel.mult(random(1, 7));
this.alpha = 255;
this.size = random(20, 65); // Adjusted size range
let colorIndex = floor(random(colors.length));
this.color = colors[colorIndex]; // Assign the color from the array
this.rgba = color(this.color)._array.concat([this.alpha / 255]);
this.history = [];
}
update() {
this.vel.mult(0.9); // Slow down
this.pos.add(this.vel);
this.alpha -= 5; // Adjust the fading speed
if (this.alpha < 0) this.alpha = 0;
this.rgba[3] = this.alpha / 255;
this.history.push(this.pos.copy()); // Add the current position to the history
if (this.history.length > 15) { // Limit the length of the trail
this.history.splice(0, 1);
}
}
isFinished() {
return this.alpha <= 0;
}
show() {
stroke(this.color);
strokeWeight(2);
noFill();
// Draw the trail
beginShape();
for (let i = 0; i < this.history.length; i++) {
let pos = this.history[i];
vertex(pos.x, pos.y); // Draw a vertex at each historical position
}
endShape();
}
}