// TWANG
// by Eric Vander Horst
//Instructions:
//Click the mouse to pull back the ball from it's origin point.
//The further its being pulled, the faster it will be released,
//the skinnier the hoop will be, and the faster the hoop will move.
//Release click to let it go.
//variable introductions
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//BALL
float ballX=200;
float ballY=240;//ball position
float xSpeed=0;
float ySpeed=0;//ball speed
float ballYMemory=240;//ball tracking. Stores the y position of the ball from the previous frame.
//RING
float ringX=200;//ring position
float ringXChange=0;//ring speed
//STRING
float pullDist=0;//elastic string length, pulled from (200,240)
//draw room
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void setup() {
size(400, 400);
}
void draw() {
drawBackground();
//if the mouse is pressed, mouse pulls tethered ball
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (mousePressed) {
updateBallDrag();
updateString();
//draw string from ball to origin.
line(ballX, ballY, 200, 240);
}
//but if the mouse isn't pressed, ball is released. Ring moves whether the mouse is pressed or not.
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
else {
updateBallRelease();
}
updateRing();
//draw ball and ring
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
noStroke();
//if ball is beneath the ring, draw ball earlier a layer underneath the ring.
if (ballY>=110) {
drawBall();
}
drawRing();
//if ball is above the ring, draw ball later on top of the ring.
if (ballY<110) {
drawBall();
}
}
//define functions
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void drawBackground() {
//Orange Walls
background(255, 139, 28);
//FLOOR, CEILING
for (int i=0; i<8; i++) {
//orange turning yellow as i increases
fill(255, 159+(i+3)*5, 28+(i+3)*2);
//floor pads printing up as i increases
quad(0+(i*10), 400-(i*10), 20+(i*10), 380-(i*10), 380-(i*10), 380-(i*10), 400-(i*10), 400-(i*10));
//ceiling pads printing down as i increases
quad(0+(i*10), -50+(i*10), 20+(i*10), -30+(i*10), 380-(i*10), -30+(i*10), 400-(i*10), -50+(i*10));
}
}
void updateBallDrag() {
//BALL
//set ball location to at mouse
ballX=mouseX;
ballY=mouseY;
//return the ball to inside the window if the mouse is outside it.
if (ballX>400) {
ballX=400;
}
if (ballX<0) {
ballX=0;
}
if (ballY>400) {
ballY=400;
}
if (ballY<0) {
ballY=0;
}
//depending on how far the ball is pulled, set x and y speed for when it is released.
xSpeed=(200-ballX)/10;
ySpeed=(240-ballY)/10;
}
void updateString() {
//STRING
//record distance from ball to ball origin
pullDist=dist(ballX, ballY, 200, 240);
//flicker and thin string more as it is pulled further
stroke(265-random(pullDist/3));
strokeWeight(abs(350-pullDist)/80);
}
void updateBallRelease() {
//remember last frame's ball y position.
//** ballYMemory is used in hitBoxBounceY() to detect if the ball was previously above or below the hit box. **
ballYMemory=ballY;
//move ball by its current speed
ballX+=xSpeed;
ballY+=ySpeed;
//bounce on the ring
//** "(abs(350-pullDist))" is the width of the outer circle, which makes the arguments look long and complicated. See "//draw ball and ring" to see how that value is used to draw the ring. **
hitBoxBounceY(ringX+(abs(350-pullDist))/2, ringX+(abs(300-pullDist)/1.3)/2, 14);//Right
hitBoxBounceY(ringX-(abs(300-pullDist)/1.3)/2, ringX-(abs(350-pullDist))/2, 14);//Left
//bounce on walls
//400 & 0 are the max and min of both x and y.
wallBounceBoth(400, 0);
//gravity, horizontal air resistance.
ySpeed+=0.2;
xSpeed*=0.997;
}
void wallBounceBoth(float a, float i) {
//when the ball goes beyond a wall, keep it inside and bounce it.
if (ballX>a) {
//keep it inside
ballX=a-1;
//bounce:reverse and diminish x speed
xSpeed*=-0.8;
}
if (ballX<i) {
//keep it inside
ballX=i+1;
//bounce:reverse and diminish x speed
xSpeed*=-0.8;
}
if (ballY>a) {
//keep it inside
ballY=a-1;
//bounce:reverse and diminish y speed
ySpeed*=-0.8;
}
if (ballY<i) {
//keep it inside
ballY=i+1;
//bounce:reverse and diminish y speed
ySpeed*=-0.8;
}
}
void hitBoxBounceY(float a, float b, float c) {
//keep ball outside of hit box. a and b are x limits of the hit box, c is adjustable extra width to add to both a & b.
//if ball x is between a & b
if (ballX<a+c && ballX>b-c) {
//if ball y is between top and bottom of hit box
if (120>ballY && ballY>100 && (abs(ySpeed)>1.5 || abs(xSpeed)>20)) {
//bounce:reverse and diminish y speed
ySpeed*=-0.8;
//if ball was previously below ring,
if (ballYMemory>120) {
//keep it below the ring and outside of the hit box.
ballY=121;
//if ball was previously above ring,
} else {
//keep it above the ring and outside the hit box.
ballY=99;
}
}
}
}
void drawBall() {
fill(255, 78, 0);
ellipse(ballX, ballY, 30, 30);
}
void updateRing() {
//Ring speed changes depending on how far back string is pulled.
ringXChange+=pullDist/5000;
ringX=150*(sin(ringXChange))+200;
}
void drawRing() {
//ring width is smaller when ball string length is longer
//ring outside
fill(223, 235, 235);
ellipse(ringX, 110, abs(350-pullDist), 60);
//ring inside
fill(255, 139, 28);
ellipse(ringX, 110, abs(300-pullDist)/1.3, 30);
}