4. Project 10: Sonic Story

sketch – CopyDownload
// This program displays a game of cup pong.
// The 'characters' are the ball, cups, table, and water in the cups.
// When the ball bounces on different surfaces (on the floor, into a cup, etc.),
// it produces different sounds.
// One side wins when all of the cups are empty
//(or just a few if you change the 'win' variable in the draw function).

// sounds:
var watercup;
var emptycup;
var bouncefloor;
var throwing;
var gameover;


// objects:
var cup; // will have fields for cx, cy, and boolean isFull
var ball; // will have fields for x, y, dx, dy, and functions

// arrays:
var leftCups = [];
var rightCups = [];

function preload() {
    watercup = loadSound("https://courses.ideate.cmu.edu/15-104/f2021/wp-content/uploads/2021/11/pong-sounds-with-liquid.wav");
    bouncefloor = loadSound("https://courses.ideate.cmu.edu/15-104/f2021/wp-content/uploads/2021/11/bouncing-ping-pong-ball.wav");
    throwing = loadSound("https://courses.ideate.cmu.edu/15-104/f2021/wp-content/uploads/2021/11/throwing-paper-in-trash.wav");
    gameover = loadSound("https://courses.ideate.cmu.edu/15-104/f2021/wp-content/uploads/2021/11/ending.wav");
}

// makes a cup object, always full to begin
function makeCup(cx, cy) {
    cup = {x:cx, y:cy, isFull: true, drawc: drawCup};
    return(cup);
}

// makes a ball object
function makeBall(cx, cy, dirx, diry) {
    ball = {x:cx, y:cy,
            dx:dirx, dy:diry,
            drawb: drawBall,
            throwb: throwBall,
            resetb: resetBall,
            leftright: true};
    return(ball);
}

function setup() {
    createCanvas(480, 300);
    frameRate(35);	// high framerate is better for this program
    useSound();
    rectMode(CENTER);

    // fill cup arrays:
    // set x and y positions to create pyramid shape.
    // the if statements create the rows for the pyramid
    for (var i=0; i<10; i++) {
        if (i<4) {
	    lcup = makeCup(width/10+10,	(i*20)+120);
            rcup = makeCup(9*width/10-10, (i*20)+120);
        }
        else if (i<7) {
	    lcup = makeCup(width/10+30,	(i*20)+50);
            rcup = makeCup(9*width/10-30, (i*20)+50);
        }
        else if (i<9) {
	    lcup = makeCup(width/10+50,	i*20);
            rcup = makeCup(9*width/10-50, i*20);
        }
        else {
	    lcup = makeCup(width/10+70,	height/2);
            rcup = makeCup(9*width/10-70, height/2);
        }
        leftCups.push(lcup);
        rightCups.push(rcup);
    }

    // create ping pong ball
    let dy = random(-4, 4);
    ball = makeBall(5, height/2, 5, dy);
}

function soundSetup() { // setup for audio generation
    watercup.setVolume(0.5);
    bouncefloor.setVolume(0.5);
    throwing.setVolume(0.5);
    gameover.setVolume(0.5);
}


function draw() {
    background(133, 94, 66);

    // draw the table
    drawTable();

    // draw the cups
    for (var c=0; c<leftCups.length; c++) {
        leftCups[c].drawc();
        rightCups[c].drawc();
    }

    // draw the ball
    ball.drawb();

    // throw the ball
    ball.throwb();

    // check for winner
    let checkl = 0;
    let checkr = 0;
    for (l=0; l<leftCups.length; l++) {
        if (leftCups[l].isFull == false) { checkl+=1 }
    }
    for (r=0; r<rightCups.length; r++) {
        if (rightCups[r].isFull == false) { checkr+=1 }
    }
    // when one side wins, display text and play sound
    // change 'win' value to see game over sooner:
    let win = 10;
    if (checkl == win|| checkr == win) {
        gameover.play();
        textAlign(CENTER, CENTER);
        textSize(25);
        fill(0);
        rect(width/2, height/2, width/2, 50, 10);
        fill(255);
        text('Game Finished!', width/2, height/2);
        noLoop();
    }


}

// draws a green table with offwhite diagonal lines:
function drawTable() {
    let linescol = color(250, 250, 225);
    let tcol = color(0, 100, 100);
    strokeWeight(7);
    stroke(linescol);
    fill(tcol);
    rect(width/2, height/2, 4*width/5, 4*height/5);
    line(width/10, height/10, 9*width/10, 9*height/10);
    line(width/10, 9*height/10, 9*width/10, height/10);
}

// draws individual cups based on x and y fields:
function drawCup() {
    let diam = 20;
    fill(200, 0, 0);	// red cup
    stroke(255);
    strokeWeight(2);
    circle(this.x, this.y, diam);
    // if the cup hasnt been hit, it has water in it:
    if (this.isFull == true) {
        noStroke();
        fill(0, 0, 200);	// blue water
        circle(this.x, this.y, diam/2);
    }
}

// draws the ball
function drawBall() {
    stroke(0);
    strokeWeight(.5);
    fill(250);
    circle(this.x, this.y, 10);
}

//throws the ball
function throwBall() {
    if (this.leftright==true) {		// going left to right
        if (this.x < width/2) {
            this.x += this.dx;
            this.y -= this.dy;
        } else {
            this.x += this.dx;
            this.y += (1.5*this.dy);
        }
        // remove the water if the ball goes into a full cup and reset ball placement
	// play water cup noise if cup is hit
        for (var j=0; j<rightCups.length; j++) {
            if (dist(rightCups[j].x, rightCups[j].y, this.x, this.y)<=7 &
		rightCups[j].isFull==true) {
	   	watercup.play();
                rightCups[j].isFull = false;
                this.resetb();
            }
        }
    } else {				// going right to left
        if (this.x > width/2) {
            this.x -= this.dx;
            this.y -= this.dy;
        }
        else {
            this.x -= this.dx;
            this.y += (1.5*this.dy);
        }
	// same code to remove water from hit cup
        for (var j=0; j<leftCups.length; j++) {
            if (dist(leftCups[j].x, leftCups[j].y, this.x, this.y)<=7 &
		leftCups[j].isFull==true) {
	   	watercup.play();
                leftCups[j].isFull = false;
                this.resetb();
            }
        }
    }
    // no cups are hit, reset the ball position & play floor bounce track
    if (this.x > width || this.x < 0 ) {
       	this.resetb();
        bouncefloor.play();
    }
}

//resets the ball to the next players starting position
function resetBall() {
    this.leftright = -this.leftright;
    if (this.leftright == true) {this.x=10}
    else {this.x =width-10}
    this.y = height/2;
    this.dy = random(-4, 4);
    // plays a 'whoosh' track for each throw
    throwing.play();
}

I chose to make a program that displays a game of water pong. The sounds I use are a ‘whoosh’ noise when a ball is thrown, a ‘clink’ sound if the ball goes into a full cup, a bouncing pingpong ball noise if the ball does not go into any full cups, and a bell noise if there is a winner. My code is randomized in a way that every game will be slightly different.

Leave a Reply