Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next

//   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);
}